Merge: netfilter: nf_tables: backports from upstream
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/3593 JIRA: https://issues.redhat.com/browse/RHEL-21443 Upstream Status: mainline Signed-off-by: Florian Westphal <fwestpha@redhat.com> Approved-by: Antoine Tenart <atenart@redhat.com> Approved-by: Guillaume Nault <gnault@redhat.com> Approved-by: Phil Sutter <psutter@redhat.com> Merged-by: Scott Weaver <scweaver@redhat.com>
This commit is contained in:
commit
f8751245d3
|
@ -150,9 +150,9 @@ static inline u16 nft_reg_load16(const u32 *sreg)
|
|||
return *(u16 *)sreg;
|
||||
}
|
||||
|
||||
static inline void nft_reg_store64(u32 *dreg, u64 val)
|
||||
static inline void nft_reg_store64(u64 *dreg, u64 val)
|
||||
{
|
||||
put_unaligned(val, (u64 *)dreg);
|
||||
put_unaligned(val, dreg);
|
||||
}
|
||||
|
||||
static inline u64 nft_reg_load64(const u32 *sreg)
|
||||
|
|
|
@ -30,7 +30,7 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
|
|||
return -1;
|
||||
|
||||
len = iph_totlen(pkt->skb, iph);
|
||||
thoff = iph->ihl * 4;
|
||||
thoff = skb_network_offset(pkt->skb) + (iph->ihl * 4);
|
||||
if (pkt->skb->len < len)
|
||||
return -1;
|
||||
else if (len < thoff)
|
||||
|
|
|
@ -263,6 +263,7 @@ enum nft_chain_attributes {
|
|||
* @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
|
||||
* @NFTA_RULE_ID: uniquely identifies a rule in a transaction (NLA_U32)
|
||||
* @NFTA_RULE_POSITION_ID: transaction unique identifier of the previous rule (NLA_U32)
|
||||
* @NFTA_RULE_CHAIN_ID: add the rule to chain by ID, alternative to @NFTA_RULE_CHAIN (NLA_U32)
|
||||
*/
|
||||
enum nft_rule_attributes {
|
||||
NFTA_RULE_UNSPEC,
|
||||
|
|
|
@ -754,7 +754,7 @@ static struct nft_table *nft_table_lookup(const struct net *net,
|
|||
|
||||
static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
|
||||
const struct nlattr *nla,
|
||||
u8 genmask, u32 nlpid)
|
||||
int family, u8 genmask, u32 nlpid)
|
||||
{
|
||||
struct nftables_pernet *nft_net;
|
||||
struct nft_table *table;
|
||||
|
@ -762,6 +762,7 @@ static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
|
|||
nft_net = nft_pernet(net);
|
||||
list_for_each_entry(table, &nft_net->tables, list) {
|
||||
if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
|
||||
table->family == family &&
|
||||
nft_active_genmask(table, genmask)) {
|
||||
if (nft_table_has_owner(table) &&
|
||||
nlpid && table->nlpid != nlpid)
|
||||
|
@ -1486,7 +1487,7 @@ static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
|
||||
if (nla[NFTA_TABLE_HANDLE]) {
|
||||
attr = nla[NFTA_TABLE_HANDLE];
|
||||
table = nft_table_lookup_byhandle(net, attr, genmask,
|
||||
table = nft_table_lookup_byhandle(net, attr, family, genmask,
|
||||
NETLINK_CB(skb).portid);
|
||||
} else {
|
||||
attr = nla[NFTA_TABLE_NAME];
|
||||
|
@ -5387,7 +5388,6 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
|
|||
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
|
||||
unsigned char *b = skb_tail_pointer(skb);
|
||||
struct nlattr *nest;
|
||||
u64 timeout = 0;
|
||||
|
||||
nest = nla_nest_start_noflag(skb, NFTA_LIST_ELEM);
|
||||
if (nest == NULL)
|
||||
|
@ -5423,15 +5423,11 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
|
|||
htonl(*nft_set_ext_flags(ext))))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) {
|
||||
timeout = *nft_set_ext_timeout(ext);
|
||||
if (nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
|
||||
nf_jiffies64_to_msecs(timeout),
|
||||
NFTA_SET_ELEM_PAD))
|
||||
goto nla_put_failure;
|
||||
} else if (set->flags & NFT_SET_TIMEOUT) {
|
||||
timeout = READ_ONCE(set->timeout);
|
||||
}
|
||||
if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
|
||||
nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
|
||||
nf_jiffies64_to_msecs(*nft_set_ext_timeout(ext)),
|
||||
NFTA_SET_ELEM_PAD))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
|
||||
u64 expires, now = get_jiffies_64();
|
||||
|
@ -5446,9 +5442,6 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
|
|||
nf_jiffies64_to_msecs(expires),
|
||||
NFTA_SET_ELEM_PAD))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (reset)
|
||||
*nft_set_ext_expiration(ext) = now + timeout;
|
||||
}
|
||||
|
||||
if (nft_set_ext_exists(ext, NFT_SET_EXT_USERDATA)) {
|
||||
|
@ -7047,10 +7040,11 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
|
|||
|
||||
if (err < 0) {
|
||||
NL_SET_BAD_ATTR(extack, attr);
|
||||
break;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -9612,7 +9606,7 @@ static void nft_set_commit_update(struct list_head *set_update_list)
|
|||
list_for_each_entry_safe(set, next, set_update_list, pending_update) {
|
||||
list_del_init(&set->pending_update);
|
||||
|
||||
if (!set->ops->commit)
|
||||
if (!set->ops->commit || set->dead)
|
||||
continue;
|
||||
|
||||
set->ops->commit(set);
|
||||
|
@ -10079,6 +10073,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
|
|||
nft_trans_destroy(trans);
|
||||
break;
|
||||
}
|
||||
nft_trans_set(trans)->dead = 1;
|
||||
list_del_rcu(&nft_trans_set(trans)->list);
|
||||
break;
|
||||
case NFT_MSG_DELSET:
|
||||
|
|
|
@ -127,7 +127,7 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
|
|||
else {
|
||||
if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
|
||||
return false;
|
||||
ptr = skb_network_header(skb) + nft_thoff(pkt);
|
||||
ptr = skb->data + nft_thoff(pkt);
|
||||
}
|
||||
|
||||
ptr += priv->offset;
|
||||
|
|
|
@ -38,20 +38,22 @@ void nft_byteorder_eval(const struct nft_expr *expr,
|
|||
|
||||
switch (priv->size) {
|
||||
case 8: {
|
||||
u64 *dst64 = (void *)dst;
|
||||
u64 src64;
|
||||
|
||||
switch (priv->op) {
|
||||
case NFT_BYTEORDER_NTOH:
|
||||
for (i = 0; i < priv->len / 8; i++) {
|
||||
src64 = nft_reg_load64(&src[i]);
|
||||
nft_reg_store64(&dst[i], be64_to_cpu(src64));
|
||||
nft_reg_store64(&dst64[i],
|
||||
be64_to_cpu((__force __be64)src64));
|
||||
}
|
||||
break;
|
||||
case NFT_BYTEORDER_HTON:
|
||||
for (i = 0; i < priv->len / 8; i++) {
|
||||
src64 = (__force __u64)
|
||||
cpu_to_be64(nft_reg_load64(&src[i]));
|
||||
nft_reg_store64(&dst[i], src64);
|
||||
nft_reg_store64(&dst64[i], src64);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,14 @@ static unsigned int optlen(const u8 *opt, unsigned int offset)
|
|||
return opt[offset + 1];
|
||||
}
|
||||
|
||||
static int nft_skb_copy_to_reg(const struct sk_buff *skb, int offset, u32 *dest, unsigned int len)
|
||||
{
|
||||
if (len % NFT_REG32_SIZE)
|
||||
dest[len / NFT_REG32_SIZE] = 0;
|
||||
|
||||
return skb_copy_bits(skb, offset, dest, len);
|
||||
}
|
||||
|
||||
static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
|
||||
struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt)
|
||||
|
@ -55,8 +63,7 @@ static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
|
|||
}
|
||||
offset += priv->offset;
|
||||
|
||||
dest[priv->len / NFT_REG32_SIZE] = 0;
|
||||
if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
|
||||
if (nft_skb_copy_to_reg(pkt->skb, offset, dest, priv->len) < 0)
|
||||
goto err;
|
||||
return;
|
||||
err:
|
||||
|
@ -152,8 +159,7 @@ static void nft_exthdr_ipv4_eval(const struct nft_expr *expr,
|
|||
}
|
||||
offset += priv->offset;
|
||||
|
||||
dest[priv->len / NFT_REG32_SIZE] = 0;
|
||||
if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
|
||||
if (nft_skb_copy_to_reg(pkt->skb, offset, dest, priv->len) < 0)
|
||||
goto err;
|
||||
return;
|
||||
err:
|
||||
|
@ -207,9 +213,10 @@ static void nft_exthdr_tcp_eval(const struct nft_expr *expr,
|
|||
|
||||
offset = i + priv->offset;
|
||||
if (priv->flags & NFT_EXTHDR_F_PRESENT) {
|
||||
*dest = 1;
|
||||
nft_reg_store8(dest, 1);
|
||||
} else {
|
||||
dest[priv->len / NFT_REG32_SIZE] = 0;
|
||||
if (priv->len % NFT_REG32_SIZE)
|
||||
dest[priv->len / NFT_REG32_SIZE] = 0;
|
||||
memcpy(dest, opt + offset, priv->len);
|
||||
}
|
||||
|
||||
|
@ -237,7 +244,12 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
|
|||
if (!tcph)
|
||||
goto err;
|
||||
|
||||
if (skb_ensure_writable(pkt->skb, nft_thoff(pkt) + tcphdr_len))
|
||||
goto err;
|
||||
|
||||
tcph = (struct tcphdr *)(pkt->skb->data + nft_thoff(pkt));
|
||||
opt = (u8 *)tcph;
|
||||
|
||||
for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) {
|
||||
union {
|
||||
__be16 v16;
|
||||
|
@ -252,15 +264,6 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
|
|||
if (i + optl > tcphdr_len || priv->len + priv->offset > optl)
|
||||
goto err;
|
||||
|
||||
if (skb_ensure_writable(pkt->skb,
|
||||
nft_thoff(pkt) + i + priv->len))
|
||||
goto err;
|
||||
|
||||
tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff,
|
||||
&tcphdr_len);
|
||||
if (!tcph)
|
||||
goto err;
|
||||
|
||||
offset = i + priv->offset;
|
||||
|
||||
switch (priv->len) {
|
||||
|
@ -334,9 +337,8 @@ static void nft_exthdr_sctp_eval(const struct nft_expr *expr,
|
|||
offset + ntohs(sch->length) > pkt->skb->len)
|
||||
break;
|
||||
|
||||
dest[priv->len / NFT_REG32_SIZE] = 0;
|
||||
if (skb_copy_bits(pkt->skb, offset + priv->offset,
|
||||
dest, priv->len) < 0)
|
||||
if (nft_skb_copy_to_reg(pkt->skb, offset + priv->offset,
|
||||
dest, priv->len) < 0)
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -140,11 +140,15 @@ void nft_fib_store_result(void *reg, const struct nft_fib *priv,
|
|||
switch (priv->result) {
|
||||
case NFT_FIB_RESULT_OIF:
|
||||
index = dev ? dev->ifindex : 0;
|
||||
*dreg = (priv->flags & NFTA_FIB_F_PRESENT) ? !!index : index;
|
||||
if (priv->flags & NFTA_FIB_F_PRESENT)
|
||||
nft_reg_store8(dreg, !!index);
|
||||
else
|
||||
*dreg = index;
|
||||
|
||||
break;
|
||||
case NFT_FIB_RESULT_OIFNAME:
|
||||
if (priv->flags & NFTA_FIB_F_PRESENT)
|
||||
*dreg = !!dev;
|
||||
nft_reg_store8(dreg, !!dev);
|
||||
else
|
||||
strncpy(reg, dev ? dev->name : "", IFNAMSIZ);
|
||||
break;
|
||||
|
|
|
@ -78,7 +78,7 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
|
|||
case NFT_GOTO:
|
||||
err = nf_tables_bind_chain(ctx, chain);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto err1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -63,7 +63,7 @@ nft_meta_get_eval_time(enum nft_meta_keys key,
|
|||
{
|
||||
switch (key) {
|
||||
case NFT_META_TIME_NS:
|
||||
nft_reg_store64(dest, ktime_get_real_ns());
|
||||
nft_reg_store64((u64 *)dest, ktime_get_real_ns());
|
||||
break;
|
||||
case NFT_META_TIME_DAY:
|
||||
nft_reg_store8(dest, nft_meta_weekday());
|
||||
|
|
|
@ -168,7 +168,7 @@ void nft_payload_eval(const struct nft_expr *expr,
|
|||
|
||||
switch (priv->base) {
|
||||
case NFT_PAYLOAD_LL_HEADER:
|
||||
if (!skb_mac_header_was_set(skb))
|
||||
if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) == 0)
|
||||
goto err;
|
||||
|
||||
if (skb_vlan_tag_present(skb)) {
|
||||
|
|
|
@ -1603,7 +1603,7 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
|
|||
if (nft_set_elem_expired(&e->ext)) {
|
||||
priv->dirty = true;
|
||||
|
||||
gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
|
||||
gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);
|
||||
if (!gc)
|
||||
return;
|
||||
|
||||
|
|
|
@ -570,6 +570,8 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set,
|
|||
nft_rbtree_interval_end(this)) {
|
||||
parent = parent->rb_right;
|
||||
continue;
|
||||
} else if (nft_set_elem_expired(&rbe->ext)) {
|
||||
break;
|
||||
} else if (!nft_set_elem_active(&rbe->ext, genmask)) {
|
||||
parent = parent->rb_left;
|
||||
continue;
|
||||
|
|
Loading…
Reference in New Issue