mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Merge branch 'for-6.0-fixes' into for-6.1
for-6.0 has the following fix for cgroup_get_from_id().
836ac87d ("cgroup: fix cgroup_get_from_id")
which conflicts with the following two commits in for-6.1.
4534dee9 ("cgroup: cgroup: Honor caller's cgroup NS when resolving cgroup id")
fa7e439c ("cgroup: Homogenize cgroup_get_from_id() return value")
While the resolution is straightforward, the code ends up pretty ugly
afterwards. Let's pull for-6.0-fixes into for-6.1 so that the code can be
fixed up there.
Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
@@ -144,7 +144,6 @@ config NF_CONNTRACK_ZONES
|
||||
|
||||
config NF_CONNTRACK_PROCFS
|
||||
bool "Supply CT list in procfs (OBSOLETE)"
|
||||
default y
|
||||
depends on PROC_FS
|
||||
help
|
||||
This option enables for the list of known conntrack entries
|
||||
|
||||
@@ -1280,12 +1280,12 @@ static void set_sock_size(struct sock *sk, int mode, int val)
|
||||
lock_sock(sk);
|
||||
if (mode) {
|
||||
val = clamp_t(int, val, (SOCK_MIN_SNDBUF + 1) / 2,
|
||||
sysctl_wmem_max);
|
||||
READ_ONCE(sysctl_wmem_max));
|
||||
sk->sk_sndbuf = val * 2;
|
||||
sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
|
||||
} else {
|
||||
val = clamp_t(int, val, (SOCK_MIN_RCVBUF + 1) / 2,
|
||||
sysctl_rmem_max);
|
||||
READ_ONCE(sysctl_rmem_max));
|
||||
sk->sk_rcvbuf = val * 2;
|
||||
sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
|
||||
}
|
||||
|
||||
@@ -34,11 +34,6 @@ MODULE_DESCRIPTION("ftp connection tracking helper");
|
||||
MODULE_ALIAS("ip_conntrack_ftp");
|
||||
MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
|
||||
|
||||
/* This is slow, but it's simple. --RR */
|
||||
static char *ftp_buffer;
|
||||
|
||||
static DEFINE_SPINLOCK(nf_ftp_lock);
|
||||
|
||||
#define MAX_PORTS 8
|
||||
static u_int16_t ports[MAX_PORTS];
|
||||
static unsigned int ports_c;
|
||||
@@ -398,6 +393,9 @@ static int help(struct sk_buff *skb,
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
if (unlikely(skb_linearize(skb)))
|
||||
return NF_DROP;
|
||||
|
||||
th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
|
||||
if (th == NULL)
|
||||
return NF_ACCEPT;
|
||||
@@ -411,12 +409,8 @@ static int help(struct sk_buff *skb,
|
||||
}
|
||||
datalen = skb->len - dataoff;
|
||||
|
||||
spin_lock_bh(&nf_ftp_lock);
|
||||
fb_ptr = skb_header_pointer(skb, dataoff, datalen, ftp_buffer);
|
||||
if (!fb_ptr) {
|
||||
spin_unlock_bh(&nf_ftp_lock);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
spin_lock_bh(&ct->lock);
|
||||
fb_ptr = skb->data + dataoff;
|
||||
|
||||
ends_in_nl = (fb_ptr[datalen - 1] == '\n');
|
||||
seq = ntohl(th->seq) + datalen;
|
||||
@@ -544,7 +538,7 @@ out_update_nl:
|
||||
if (ends_in_nl)
|
||||
update_nl_seq(ct, seq, ct_ftp_info, dir, skb);
|
||||
out:
|
||||
spin_unlock_bh(&nf_ftp_lock);
|
||||
spin_unlock_bh(&ct->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -571,7 +565,6 @@ static const struct nf_conntrack_expect_policy ftp_exp_policy = {
|
||||
static void __exit nf_conntrack_ftp_fini(void)
|
||||
{
|
||||
nf_conntrack_helpers_unregister(ftp, ports_c * 2);
|
||||
kfree(ftp_buffer);
|
||||
}
|
||||
|
||||
static int __init nf_conntrack_ftp_init(void)
|
||||
@@ -580,10 +573,6 @@ static int __init nf_conntrack_ftp_init(void)
|
||||
|
||||
NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_ftp_master));
|
||||
|
||||
ftp_buffer = kmalloc(65536, GFP_KERNEL);
|
||||
if (!ftp_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ports_c == 0)
|
||||
ports[ports_c++] = FTP_PORT;
|
||||
|
||||
@@ -603,7 +592,6 @@ static int __init nf_conntrack_ftp_init(void)
|
||||
ret = nf_conntrack_helpers_register(ftp, ports_c * 2);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to register helpers\n");
|
||||
kfree(ftp_buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include <net/netfilter/nf_conntrack_zones.h>
|
||||
#include <linux/netfilter/nf_conntrack_h323.h>
|
||||
|
||||
#define H323_MAX_SIZE 65535
|
||||
|
||||
/* Parameters */
|
||||
static unsigned int default_rrq_ttl __read_mostly = 300;
|
||||
module_param(default_rrq_ttl, uint, 0600);
|
||||
@@ -86,6 +88,9 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
|
||||
if (tcpdatalen <= 0) /* No TCP data */
|
||||
goto clear_out;
|
||||
|
||||
if (tcpdatalen > H323_MAX_SIZE)
|
||||
tcpdatalen = H323_MAX_SIZE;
|
||||
|
||||
if (*data == NULL) { /* first TPKT */
|
||||
/* Get first TPKT pointer */
|
||||
tpkt = skb_header_pointer(skb, tcpdataoff, tcpdatalen,
|
||||
@@ -1169,6 +1174,9 @@ static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
|
||||
if (dataoff >= skb->len)
|
||||
return NULL;
|
||||
*datalen = skb->len - dataoff;
|
||||
if (*datalen > H323_MAX_SIZE)
|
||||
*datalen = H323_MAX_SIZE;
|
||||
|
||||
return skb_header_pointer(skb, dataoff, *datalen, h323_buffer);
|
||||
}
|
||||
|
||||
@@ -1770,7 +1778,7 @@ static int __init nf_conntrack_h323_init(void)
|
||||
|
||||
NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_h323_master));
|
||||
|
||||
h323_buffer = kmalloc(65536, GFP_KERNEL);
|
||||
h323_buffer = kmalloc(H323_MAX_SIZE + 1, GFP_KERNEL);
|
||||
if (!h323_buffer)
|
||||
return -ENOMEM;
|
||||
ret = h323_helper_init();
|
||||
|
||||
@@ -39,6 +39,7 @@ unsigned int (*nf_nat_irc_hook)(struct sk_buff *skb,
|
||||
EXPORT_SYMBOL_GPL(nf_nat_irc_hook);
|
||||
|
||||
#define HELPER_NAME "irc"
|
||||
#define MAX_SEARCH_SIZE 4095
|
||||
|
||||
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
||||
MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
|
||||
@@ -121,6 +122,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
|
||||
int i, ret = NF_ACCEPT;
|
||||
char *addr_beg_p, *addr_end_p;
|
||||
typeof(nf_nat_irc_hook) nf_nat_irc;
|
||||
unsigned int datalen;
|
||||
|
||||
/* If packet is coming from IRC server */
|
||||
if (dir == IP_CT_DIR_REPLY)
|
||||
@@ -140,8 +142,12 @@ static int help(struct sk_buff *skb, unsigned int protoff,
|
||||
if (dataoff >= skb->len)
|
||||
return NF_ACCEPT;
|
||||
|
||||
datalen = skb->len - dataoff;
|
||||
if (datalen > MAX_SEARCH_SIZE)
|
||||
datalen = MAX_SEARCH_SIZE;
|
||||
|
||||
spin_lock_bh(&irc_buffer_lock);
|
||||
ib_ptr = skb_header_pointer(skb, dataoff, skb->len - dataoff,
|
||||
ib_ptr = skb_header_pointer(skb, dataoff, datalen,
|
||||
irc_buffer);
|
||||
if (!ib_ptr) {
|
||||
spin_unlock_bh(&irc_buffer_lock);
|
||||
@@ -149,7 +155,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
|
||||
}
|
||||
|
||||
data = ib_ptr;
|
||||
data_limit = ib_ptr + skb->len - dataoff;
|
||||
data_limit = ib_ptr + datalen;
|
||||
|
||||
/* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
|
||||
* 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
|
||||
@@ -251,7 +257,7 @@ static int __init nf_conntrack_irc_init(void)
|
||||
irc_exp_policy.max_expected = max_dcc_channels;
|
||||
irc_exp_policy.timeout = dcc_timeout;
|
||||
|
||||
irc_buffer = kmalloc(65536, GFP_KERNEL);
|
||||
irc_buffer = kmalloc(MAX_SEARCH_SIZE + 1, GFP_KERNEL);
|
||||
if (!irc_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@@ -655,6 +655,37 @@ static bool tcp_in_window(struct nf_conn *ct,
|
||||
tn->tcp_be_liberal)
|
||||
res = true;
|
||||
if (!res) {
|
||||
bool seq_ok = before(seq, sender->td_maxend + 1);
|
||||
|
||||
if (!seq_ok) {
|
||||
u32 overshot = end - sender->td_maxend + 1;
|
||||
bool ack_ok;
|
||||
|
||||
ack_ok = after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1);
|
||||
|
||||
if (in_recv_win &&
|
||||
ack_ok &&
|
||||
overshot <= receiver->td_maxwin &&
|
||||
before(sack, receiver->td_end + 1)) {
|
||||
/* Work around TCPs that send more bytes than allowed by
|
||||
* the receive window.
|
||||
*
|
||||
* If the (marked as invalid) packet is allowed to pass by
|
||||
* the ruleset and the peer acks this data, then its possible
|
||||
* all future packets will trigger 'ACK is over upper bound' check.
|
||||
*
|
||||
* Thus if only the sequence check fails then do update td_end so
|
||||
* possible ACK for this data can update internal state.
|
||||
*/
|
||||
sender->td_end = end;
|
||||
sender->flags |= IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED;
|
||||
|
||||
nf_ct_l4proto_log_invalid(skb, ct, hook_state,
|
||||
"%u bytes more than expected", overshot);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
nf_ct_l4proto_log_invalid(skb, ct, hook_state,
|
||||
"%s",
|
||||
before(seq, sender->td_maxend + 1) ?
|
||||
|
||||
@@ -34,10 +34,6 @@ MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
|
||||
MODULE_DESCRIPTION("SANE connection tracking helper");
|
||||
MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
|
||||
|
||||
static char *sane_buffer;
|
||||
|
||||
static DEFINE_SPINLOCK(nf_sane_lock);
|
||||
|
||||
#define MAX_PORTS 8
|
||||
static u_int16_t ports[MAX_PORTS];
|
||||
static unsigned int ports_c;
|
||||
@@ -67,14 +63,16 @@ static int help(struct sk_buff *skb,
|
||||
unsigned int dataoff, datalen;
|
||||
const struct tcphdr *th;
|
||||
struct tcphdr _tcph;
|
||||
void *sb_ptr;
|
||||
int ret = NF_ACCEPT;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
struct nf_ct_sane_master *ct_sane_info = nfct_help_data(ct);
|
||||
struct nf_conntrack_expect *exp;
|
||||
struct nf_conntrack_tuple *tuple;
|
||||
struct sane_request *req;
|
||||
struct sane_reply_net_start *reply;
|
||||
union {
|
||||
struct sane_request req;
|
||||
struct sane_reply_net_start repl;
|
||||
} buf;
|
||||
|
||||
/* Until there's been traffic both ways, don't look in packets. */
|
||||
if (ctinfo != IP_CT_ESTABLISHED &&
|
||||
@@ -92,59 +90,62 @@ static int help(struct sk_buff *skb,
|
||||
return NF_ACCEPT;
|
||||
|
||||
datalen = skb->len - dataoff;
|
||||
|
||||
spin_lock_bh(&nf_sane_lock);
|
||||
sb_ptr = skb_header_pointer(skb, dataoff, datalen, sane_buffer);
|
||||
if (!sb_ptr) {
|
||||
spin_unlock_bh(&nf_sane_lock);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
if (dir == IP_CT_DIR_ORIGINAL) {
|
||||
if (datalen != sizeof(struct sane_request))
|
||||
goto out;
|
||||
const struct sane_request *req;
|
||||
|
||||
if (datalen != sizeof(struct sane_request))
|
||||
return NF_ACCEPT;
|
||||
|
||||
req = skb_header_pointer(skb, dataoff, datalen, &buf.req);
|
||||
if (!req)
|
||||
return NF_ACCEPT;
|
||||
|
||||
req = sb_ptr;
|
||||
if (req->RPC_code != htonl(SANE_NET_START)) {
|
||||
/* Not an interesting command */
|
||||
ct_sane_info->state = SANE_STATE_NORMAL;
|
||||
goto out;
|
||||
WRITE_ONCE(ct_sane_info->state, SANE_STATE_NORMAL);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* We're interested in the next reply */
|
||||
ct_sane_info->state = SANE_STATE_START_REQUESTED;
|
||||
goto out;
|
||||
WRITE_ONCE(ct_sane_info->state, SANE_STATE_START_REQUESTED);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* IP_CT_DIR_REPLY */
|
||||
|
||||
/* Is it a reply to an uninteresting command? */
|
||||
if (ct_sane_info->state != SANE_STATE_START_REQUESTED)
|
||||
goto out;
|
||||
if (READ_ONCE(ct_sane_info->state) != SANE_STATE_START_REQUESTED)
|
||||
return NF_ACCEPT;
|
||||
|
||||
/* It's a reply to SANE_NET_START. */
|
||||
ct_sane_info->state = SANE_STATE_NORMAL;
|
||||
WRITE_ONCE(ct_sane_info->state, SANE_STATE_NORMAL);
|
||||
|
||||
if (datalen < sizeof(struct sane_reply_net_start)) {
|
||||
pr_debug("NET_START reply too short\n");
|
||||
goto out;
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
reply = sb_ptr;
|
||||
datalen = sizeof(struct sane_reply_net_start);
|
||||
|
||||
reply = skb_header_pointer(skb, dataoff, datalen, &buf.repl);
|
||||
if (!reply)
|
||||
return NF_ACCEPT;
|
||||
|
||||
if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
|
||||
/* saned refused the command */
|
||||
pr_debug("unsuccessful SANE_STATUS = %u\n",
|
||||
ntohl(reply->status));
|
||||
goto out;
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Invalid saned reply? Ignore it. */
|
||||
if (reply->zero != 0)
|
||||
goto out;
|
||||
return NF_ACCEPT;
|
||||
|
||||
exp = nf_ct_expect_alloc(ct);
|
||||
if (exp == NULL) {
|
||||
nf_ct_helper_log(skb, ct, "cannot alloc expectation");
|
||||
ret = NF_DROP;
|
||||
goto out;
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
|
||||
@@ -162,9 +163,6 @@ static int help(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
nf_ct_expect_put(exp);
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&nf_sane_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -178,7 +176,6 @@ static const struct nf_conntrack_expect_policy sane_exp_policy = {
|
||||
static void __exit nf_conntrack_sane_fini(void)
|
||||
{
|
||||
nf_conntrack_helpers_unregister(sane, ports_c * 2);
|
||||
kfree(sane_buffer);
|
||||
}
|
||||
|
||||
static int __init nf_conntrack_sane_init(void)
|
||||
@@ -187,10 +184,6 @@ static int __init nf_conntrack_sane_init(void)
|
||||
|
||||
NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_sane_master));
|
||||
|
||||
sane_buffer = kmalloc(65536, GFP_KERNEL);
|
||||
if (!sane_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ports_c == 0)
|
||||
ports[ports_c++] = SANE_PORT;
|
||||
|
||||
@@ -210,7 +203,6 @@ static int __init nf_conntrack_sane_init(void)
|
||||
ret = nf_conntrack_helpers_register(sane, ports_c * 2);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to register helpers\n");
|
||||
kfree(sane_buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -437,12 +437,17 @@ static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
|
||||
}
|
||||
}
|
||||
|
||||
void nf_flow_table_gc_run(struct nf_flowtable *flow_table)
|
||||
{
|
||||
nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL);
|
||||
}
|
||||
|
||||
static void nf_flow_offload_work_gc(struct work_struct *work)
|
||||
{
|
||||
struct nf_flowtable *flow_table;
|
||||
|
||||
flow_table = container_of(work, struct nf_flowtable, gc_work.work);
|
||||
nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL);
|
||||
nf_flow_table_gc_run(flow_table);
|
||||
queue_delayed_work(system_power_efficient_wq, &flow_table->gc_work, HZ);
|
||||
}
|
||||
|
||||
@@ -600,11 +605,11 @@ void nf_flow_table_free(struct nf_flowtable *flow_table)
|
||||
mutex_unlock(&flowtable_lock);
|
||||
|
||||
cancel_delayed_work_sync(&flow_table->gc_work);
|
||||
nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL);
|
||||
nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL);
|
||||
nf_flow_table_offload_flush(flow_table);
|
||||
if (nf_flowtable_hw_offload(flow_table))
|
||||
nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL);
|
||||
/* ... no more pending work after this stage ... */
|
||||
nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL);
|
||||
nf_flow_table_gc_run(flow_table);
|
||||
nf_flow_table_offload_flush_cleanup(flow_table);
|
||||
rhashtable_destroy(&flow_table->rhashtable);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_flow_table_free);
|
||||
|
||||
@@ -1074,6 +1074,14 @@ void nf_flow_offload_stats(struct nf_flowtable *flowtable,
|
||||
flow_offload_queue_work(offload);
|
||||
}
|
||||
|
||||
void nf_flow_table_offload_flush_cleanup(struct nf_flowtable *flowtable)
|
||||
{
|
||||
if (nf_flowtable_hw_offload(flowtable)) {
|
||||
flush_workqueue(nf_flow_offload_del_wq);
|
||||
nf_flow_table_gc_run(flowtable);
|
||||
}
|
||||
}
|
||||
|
||||
void nf_flow_table_offload_flush(struct nf_flowtable *flowtable)
|
||||
{
|
||||
if (nf_flowtable_hw_offload(flowtable)) {
|
||||
|
||||
@@ -32,7 +32,6 @@ static LIST_HEAD(nf_tables_objects);
|
||||
static LIST_HEAD(nf_tables_flowtables);
|
||||
static LIST_HEAD(nf_tables_destroy_list);
|
||||
static DEFINE_SPINLOCK(nf_tables_destroy_list_lock);
|
||||
static u64 table_handle;
|
||||
|
||||
enum {
|
||||
NFT_VALIDATE_SKIP = 0,
|
||||
@@ -889,7 +888,7 @@ static int nf_tables_dump_tables(struct sk_buff *skb,
|
||||
|
||||
rcu_read_lock();
|
||||
nft_net = nft_pernet(net);
|
||||
cb->seq = nft_net->base_seq;
|
||||
cb->seq = READ_ONCE(nft_net->base_seq);
|
||||
|
||||
list_for_each_entry_rcu(table, &nft_net->tables, list) {
|
||||
if (family != NFPROTO_UNSPEC && family != table->family)
|
||||
@@ -1235,7 +1234,7 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
INIT_LIST_HEAD(&table->flowtables);
|
||||
table->family = family;
|
||||
table->flags = flags;
|
||||
table->handle = ++table_handle;
|
||||
table->handle = ++nft_net->table_handle;
|
||||
if (table->flags & NFT_TABLE_F_OWNER)
|
||||
table->nlpid = NETLINK_CB(skb).portid;
|
||||
|
||||
@@ -1705,7 +1704,7 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
|
||||
|
||||
rcu_read_lock();
|
||||
nft_net = nft_pernet(net);
|
||||
cb->seq = nft_net->base_seq;
|
||||
cb->seq = READ_ONCE(nft_net->base_seq);
|
||||
|
||||
list_for_each_entry_rcu(table, &nft_net->tables, list) {
|
||||
if (family != NFPROTO_UNSPEC && family != table->family)
|
||||
@@ -2196,9 +2195,9 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct nlattr * const *nla = ctx->nla;
|
||||
struct nft_stats __percpu *stats = NULL;
|
||||
struct nft_table *table = ctx->table;
|
||||
struct nft_base_chain *basechain;
|
||||
struct nft_stats __percpu *stats;
|
||||
struct net *net = ctx->net;
|
||||
char name[NFT_NAME_MAXLEN];
|
||||
struct nft_rule_blob *blob;
|
||||
@@ -2236,7 +2235,6 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
|
||||
return PTR_ERR(stats);
|
||||
}
|
||||
rcu_assign_pointer(basechain->stats, stats);
|
||||
static_branch_inc(&nft_counters_enabled);
|
||||
}
|
||||
|
||||
err = nft_basechain_init(basechain, family, &hook, flags);
|
||||
@@ -2319,6 +2317,9 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
|
||||
goto err_unregister_hook;
|
||||
}
|
||||
|
||||
if (stats)
|
||||
static_branch_inc(&nft_counters_enabled);
|
||||
|
||||
table->use++;
|
||||
|
||||
return 0;
|
||||
@@ -2574,6 +2575,9 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
|
||||
|
||||
if (chain != NULL) {
|
||||
if (chain->flags & NFT_CHAIN_BINDING)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->nlh->nlmsg_flags & NLM_F_EXCL) {
|
||||
NL_SET_BAD_ATTR(extack, attr);
|
||||
return -EEXIST;
|
||||
@@ -3149,7 +3153,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
|
||||
|
||||
rcu_read_lock();
|
||||
nft_net = nft_pernet(net);
|
||||
cb->seq = nft_net->base_seq;
|
||||
cb->seq = READ_ONCE(nft_net->base_seq);
|
||||
|
||||
list_for_each_entry_rcu(table, &nft_net->tables, list) {
|
||||
if (family != NFPROTO_UNSPEC && family != table->family)
|
||||
@@ -3907,7 +3911,7 @@ cont:
|
||||
list_for_each_entry(i, &ctx->table->sets, list) {
|
||||
int tmp;
|
||||
|
||||
if (!nft_is_active_next(ctx->net, set))
|
||||
if (!nft_is_active_next(ctx->net, i))
|
||||
continue;
|
||||
if (!sscanf(i->name, name, &tmp))
|
||||
continue;
|
||||
@@ -4133,7 +4137,7 @@ static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
||||
rcu_read_lock();
|
||||
nft_net = nft_pernet(net);
|
||||
cb->seq = nft_net->base_seq;
|
||||
cb->seq = READ_ONCE(nft_net->base_seq);
|
||||
|
||||
list_for_each_entry_rcu(table, &nft_net->tables, list) {
|
||||
if (ctx->family != NFPROTO_UNSPEC &&
|
||||
@@ -4451,6 +4455,11 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
err = nf_tables_set_desc_parse(&desc, nla[NFTA_SET_DESC]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (desc.field_count > 1 && !(flags & NFT_SET_CONCAT))
|
||||
return -EINVAL;
|
||||
} else if (flags & NFT_SET_CONCAT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (nla[NFTA_SET_EXPR] || nla[NFTA_SET_EXPRESSIONS])
|
||||
@@ -5061,6 +5070,8 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
||||
rcu_read_lock();
|
||||
nft_net = nft_pernet(net);
|
||||
cb->seq = READ_ONCE(nft_net->base_seq);
|
||||
|
||||
list_for_each_entry_rcu(table, &nft_net->tables, list) {
|
||||
if (dump_ctx->ctx.family != NFPROTO_UNSPEC &&
|
||||
dump_ctx->ctx.family != table->family)
|
||||
@@ -5196,6 +5207,9 @@ static int nft_setelem_parse_flags(const struct nft_set *set,
|
||||
if (!(set->flags & NFT_SET_INTERVAL) &&
|
||||
*flags & NFT_SET_ELEM_INTERVAL_END)
|
||||
return -EINVAL;
|
||||
if ((*flags & (NFT_SET_ELEM_INTERVAL_END | NFT_SET_ELEM_CATCHALL)) ==
|
||||
(NFT_SET_ELEM_INTERVAL_END | NFT_SET_ELEM_CATCHALL))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -5599,7 +5613,7 @@ int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
|
||||
|
||||
err = nft_expr_clone(expr, set->exprs[i]);
|
||||
if (err < 0) {
|
||||
nft_expr_destroy(ctx, expr);
|
||||
kfree(expr);
|
||||
goto err_expr;
|
||||
}
|
||||
expr_array[i] = expr;
|
||||
@@ -5842,6 +5856,24 @@ static void nft_setelem_remove(const struct net *net,
|
||||
set->ops->remove(net, set, elem);
|
||||
}
|
||||
|
||||
static bool nft_setelem_valid_key_end(const struct nft_set *set,
|
||||
struct nlattr **nla, u32 flags)
|
||||
{
|
||||
if ((set->flags & (NFT_SET_CONCAT | NFT_SET_INTERVAL)) ==
|
||||
(NFT_SET_CONCAT | NFT_SET_INTERVAL)) {
|
||||
if (flags & NFT_SET_ELEM_INTERVAL_END)
|
||||
return false;
|
||||
if (!nla[NFTA_SET_ELEM_KEY_END] &&
|
||||
!(flags & NFT_SET_ELEM_CATCHALL))
|
||||
return false;
|
||||
} else {
|
||||
if (nla[NFTA_SET_ELEM_KEY_END])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
|
||||
const struct nlattr *attr, u32 nlmsg_flags)
|
||||
{
|
||||
@@ -5892,6 +5924,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (set->flags & NFT_SET_OBJECT) {
|
||||
if (!nla[NFTA_SET_ELEM_OBJREF] &&
|
||||
!(flags & NFT_SET_ELEM_INTERVAL_END))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (nla[NFTA_SET_ELEM_OBJREF])
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!nft_setelem_valid_key_end(set, nla, flags))
|
||||
return -EINVAL;
|
||||
|
||||
if ((flags & NFT_SET_ELEM_INTERVAL_END) &&
|
||||
(nla[NFTA_SET_ELEM_DATA] ||
|
||||
nla[NFTA_SET_ELEM_OBJREF] ||
|
||||
@@ -5899,6 +5943,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
|
||||
nla[NFTA_SET_ELEM_EXPIRATION] ||
|
||||
nla[NFTA_SET_ELEM_USERDATA] ||
|
||||
nla[NFTA_SET_ELEM_EXPR] ||
|
||||
nla[NFTA_SET_ELEM_KEY_END] ||
|
||||
nla[NFTA_SET_ELEM_EXPRESSIONS]))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -6029,10 +6074,6 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
|
||||
}
|
||||
|
||||
if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
|
||||
if (!(set->flags & NFT_SET_OBJECT)) {
|
||||
err = -EINVAL;
|
||||
goto err_parse_key_end;
|
||||
}
|
||||
obj = nft_obj_lookup(ctx->net, ctx->table,
|
||||
nla[NFTA_SET_ELEM_OBJREF],
|
||||
set->objtype, genmask);
|
||||
@@ -6325,6 +6366,9 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
|
||||
if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
|
||||
return -EINVAL;
|
||||
|
||||
if (!nft_setelem_valid_key_end(set, nla, flags))
|
||||
return -EINVAL;
|
||||
|
||||
nft_set_ext_prepare(&tmpl);
|
||||
|
||||
if (flags != 0) {
|
||||
@@ -6941,7 +6985,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
||||
rcu_read_lock();
|
||||
nft_net = nft_pernet(net);
|
||||
cb->seq = nft_net->base_seq;
|
||||
cb->seq = READ_ONCE(nft_net->base_seq);
|
||||
|
||||
list_for_each_entry_rcu(table, &nft_net->tables, list) {
|
||||
if (family != NFPROTO_UNSPEC && family != table->family)
|
||||
@@ -7873,7 +7917,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb,
|
||||
|
||||
rcu_read_lock();
|
||||
nft_net = nft_pernet(net);
|
||||
cb->seq = nft_net->base_seq;
|
||||
cb->seq = READ_ONCE(nft_net->base_seq);
|
||||
|
||||
list_for_each_entry_rcu(table, &nft_net->tables, list) {
|
||||
if (family != NFPROTO_UNSPEC && family != table->family)
|
||||
@@ -8806,6 +8850,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
|
||||
struct nft_trans_elem *te;
|
||||
struct nft_chain *chain;
|
||||
struct nft_table *table;
|
||||
unsigned int base_seq;
|
||||
LIST_HEAD(adl);
|
||||
int err;
|
||||
|
||||
@@ -8855,9 +8900,12 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
|
||||
* Bump generation counter, invalidate any dump in progress.
|
||||
* Cannot fail after this point.
|
||||
*/
|
||||
while (++nft_net->base_seq == 0)
|
||||
base_seq = READ_ONCE(nft_net->base_seq);
|
||||
while (++base_seq == 0)
|
||||
;
|
||||
|
||||
WRITE_ONCE(nft_net->base_seq, base_seq);
|
||||
|
||||
/* step 3. Start new generation, rules_gen_X now in use. */
|
||||
net->nft.gencursor = nft_gencursor_next(net);
|
||||
|
||||
@@ -9419,13 +9467,9 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
list_for_each_entry(set, &ctx->table->sets, list) {
|
||||
cond_resched();
|
||||
|
||||
if (!nft_is_active_next(ctx->net, set))
|
||||
continue;
|
||||
if (!(set->flags & NFT_SET_MAP) ||
|
||||
@@ -9667,6 +9711,8 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
|
||||
return PTR_ERR(chain);
|
||||
if (nft_is_base_chain(chain))
|
||||
return -EOPNOTSUPP;
|
||||
if (nft_chain_is_bound(chain))
|
||||
return -EINVAL;
|
||||
if (desc->flags & NFT_DATA_DESC_SETELEM &&
|
||||
chain->flags & NFT_CHAIN_BINDING)
|
||||
return -EINVAL;
|
||||
|
||||
+71
-12
@@ -44,6 +44,10 @@ MODULE_DESCRIPTION("Netfilter messages via netlink socket");
|
||||
|
||||
static unsigned int nfnetlink_pernet_id __read_mostly;
|
||||
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
static DEFINE_SPINLOCK(nfnl_grp_active_lock);
|
||||
#endif
|
||||
|
||||
struct nfnl_net {
|
||||
struct sock *nfnl;
|
||||
};
|
||||
@@ -654,6 +658,44 @@ static void nfnetlink_rcv(struct sk_buff *skb)
|
||||
netlink_rcv_skb(skb, nfnetlink_rcv_msg);
|
||||
}
|
||||
|
||||
static void nfnetlink_bind_event(struct net *net, unsigned int group)
|
||||
{
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
int type, group_bit;
|
||||
u8 v;
|
||||
|
||||
/* All NFNLGRP_CONNTRACK_* group bits fit into u8.
|
||||
* The other groups are not relevant and can be ignored.
|
||||
*/
|
||||
if (group >= 8)
|
||||
return;
|
||||
|
||||
type = nfnl_group2type[group];
|
||||
|
||||
switch (type) {
|
||||
case NFNL_SUBSYS_CTNETLINK:
|
||||
break;
|
||||
case NFNL_SUBSYS_CTNETLINK_EXP:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
group_bit = (1 << group);
|
||||
|
||||
spin_lock(&nfnl_grp_active_lock);
|
||||
v = READ_ONCE(net->ct.ctnetlink_has_listener);
|
||||
if ((v & group_bit) == 0) {
|
||||
v |= group_bit;
|
||||
|
||||
/* read concurrently without nfnl_grp_active_lock held. */
|
||||
WRITE_ONCE(net->ct.ctnetlink_has_listener, v);
|
||||
}
|
||||
|
||||
spin_unlock(&nfnl_grp_active_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int nfnetlink_bind(struct net *net, int group)
|
||||
{
|
||||
const struct nfnetlink_subsystem *ss;
|
||||
@@ -670,28 +712,45 @@ static int nfnetlink_bind(struct net *net, int group)
|
||||
if (!ss)
|
||||
request_module_nowait("nfnetlink-subsys-%d", type);
|
||||
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
if (type == NFNL_SUBSYS_CTNETLINK) {
|
||||
nfnl_lock(NFNL_SUBSYS_CTNETLINK);
|
||||
WRITE_ONCE(net->ct.ctnetlink_has_listener, true);
|
||||
nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
|
||||
}
|
||||
#endif
|
||||
nfnetlink_bind_event(net, group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nfnetlink_unbind(struct net *net, int group)
|
||||
{
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
int type, group_bit;
|
||||
|
||||
if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX)
|
||||
return;
|
||||
|
||||
if (nfnl_group2type[group] == NFNL_SUBSYS_CTNETLINK) {
|
||||
nfnl_lock(NFNL_SUBSYS_CTNETLINK);
|
||||
if (!nfnetlink_has_listeners(net, group))
|
||||
WRITE_ONCE(net->ct.ctnetlink_has_listener, false);
|
||||
nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
|
||||
type = nfnl_group2type[group];
|
||||
|
||||
switch (type) {
|
||||
case NFNL_SUBSYS_CTNETLINK:
|
||||
break;
|
||||
case NFNL_SUBSYS_CTNETLINK_EXP:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* ctnetlink_has_listener is u8 */
|
||||
if (group >= 8)
|
||||
return;
|
||||
|
||||
group_bit = (1 << group);
|
||||
|
||||
spin_lock(&nfnl_grp_active_lock);
|
||||
if (!nfnetlink_has_listeners(net, group)) {
|
||||
u8 v = READ_ONCE(net->ct.ctnetlink_has_listener);
|
||||
|
||||
v &= ~group_bit;
|
||||
|
||||
/* read concurrently without nfnl_grp_active_lock held. */
|
||||
WRITE_ONCE(net->ct.ctnetlink_has_listener, v);
|
||||
}
|
||||
spin_unlock(&nfnl_grp_active_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+15
-3
@@ -115,9 +115,21 @@ static int nft_osf_validate(const struct nft_ctx *ctx,
|
||||
const struct nft_expr *expr,
|
||||
const struct nft_data **data)
|
||||
{
|
||||
return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) |
|
||||
(1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_FORWARD));
|
||||
unsigned int hooks;
|
||||
|
||||
switch (ctx->family) {
|
||||
case NFPROTO_IPV4:
|
||||
case NFPROTO_IPV6:
|
||||
case NFPROTO_INET:
|
||||
hooks = (1 << NF_INET_LOCAL_IN) |
|
||||
(1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_FORWARD);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return nft_chain_validate_hooks(ctx->chain, hooks);
|
||||
}
|
||||
|
||||
static bool nft_osf_reduce(struct nft_regs_track *track,
|
||||
|
||||
@@ -740,17 +740,23 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
|
||||
const struct nlattr * const tb[])
|
||||
{
|
||||
struct nft_payload_set *priv = nft_expr_priv(expr);
|
||||
u32 csum_offset, csum_type = NFT_PAYLOAD_CSUM_NONE;
|
||||
int err;
|
||||
|
||||
priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
|
||||
priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
|
||||
priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
|
||||
|
||||
if (tb[NFTA_PAYLOAD_CSUM_TYPE])
|
||||
priv->csum_type =
|
||||
ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_TYPE]));
|
||||
if (tb[NFTA_PAYLOAD_CSUM_OFFSET])
|
||||
priv->csum_offset =
|
||||
ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_OFFSET]));
|
||||
csum_type = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_TYPE]));
|
||||
if (tb[NFTA_PAYLOAD_CSUM_OFFSET]) {
|
||||
err = nft_parse_u32_check(tb[NFTA_PAYLOAD_CSUM_OFFSET], U8_MAX,
|
||||
&csum_offset);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
priv->csum_offset = csum_offset;
|
||||
}
|
||||
if (tb[NFTA_PAYLOAD_CSUM_FLAGS]) {
|
||||
u32 flags;
|
||||
|
||||
@@ -761,7 +767,7 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
|
||||
priv->csum_flags = flags;
|
||||
}
|
||||
|
||||
switch (priv->csum_type) {
|
||||
switch (csum_type) {
|
||||
case NFT_PAYLOAD_CSUM_NONE:
|
||||
case NFT_PAYLOAD_CSUM_INET:
|
||||
break;
|
||||
@@ -775,6 +781,7 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
priv->csum_type = csum_type;
|
||||
|
||||
return nft_parse_register_load(tb[NFTA_PAYLOAD_SREG], &priv->sreg,
|
||||
priv->len);
|
||||
@@ -833,6 +840,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
|
||||
{
|
||||
enum nft_payload_bases base;
|
||||
unsigned int offset, len;
|
||||
int err;
|
||||
|
||||
if (tb[NFTA_PAYLOAD_BASE] == NULL ||
|
||||
tb[NFTA_PAYLOAD_OFFSET] == NULL ||
|
||||
@@ -859,8 +867,13 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
|
||||
if (tb[NFTA_PAYLOAD_DREG] == NULL)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
|
||||
len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
|
||||
err = nft_parse_u32_check(tb[NFTA_PAYLOAD_OFFSET], U8_MAX, &offset);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = nft_parse_u32_check(tb[NFTA_PAYLOAD_LEN], U8_MAX, &len);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
|
||||
base != NFT_PAYLOAD_LL_HEADER && base != NFT_PAYLOAD_INNER_HEADER)
|
||||
|
||||
@@ -312,6 +312,13 @@ static int nft_tproxy_dump(struct sk_buff *skb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_tproxy_validate(const struct nft_ctx *ctx,
|
||||
const struct nft_expr *expr,
|
||||
const struct nft_data **data)
|
||||
{
|
||||
return nft_chain_validate_hooks(ctx->chain, 1 << NF_INET_PRE_ROUTING);
|
||||
}
|
||||
|
||||
static struct nft_expr_type nft_tproxy_type;
|
||||
static const struct nft_expr_ops nft_tproxy_ops = {
|
||||
.type = &nft_tproxy_type,
|
||||
@@ -321,6 +328,7 @@ static const struct nft_expr_ops nft_tproxy_ops = {
|
||||
.destroy = nft_tproxy_destroy,
|
||||
.dump = nft_tproxy_dump,
|
||||
.reduce = NFT_REDUCE_READONLY,
|
||||
.validate = nft_tproxy_validate,
|
||||
};
|
||||
|
||||
static struct nft_expr_type nft_tproxy_type __read_mostly = {
|
||||
|
||||
@@ -161,6 +161,7 @@ static const struct nft_expr_ops nft_tunnel_get_ops = {
|
||||
|
||||
static struct nft_expr_type nft_tunnel_type __read_mostly = {
|
||||
.name = "tunnel",
|
||||
.family = NFPROTO_NETDEV,
|
||||
.ops = &nft_tunnel_get_ops,
|
||||
.policy = nft_tunnel_policy,
|
||||
.maxattr = NFTA_TUNNEL_MAX,
|
||||
|
||||
Reference in New Issue
Block a user