Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'nf-26-03-13' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf

Florian Westphal says:

====================
netfilter: updates for net

This is a much earlier pull request than usual, due to the large
backlog. We are aware of several unfixed issues, in particular
in ctnetlink, patches are being worked on.

The following patchset contains Netfilter fixes for *net*:

1) fix a use-after-free in ctnetlink, from Hyunwoo Kim, broken
since v3.10.
2) add missing netlink range checks in ctnetlink, broken since v2.6
days.
3) fix content length truncation in sip conntrack helper,
from Lukas Johannes Möller. Broken since 2.6.34.
4) Revert a recent patch to add stronger checks for overlapping ranges
in nf_tables rbtree set type.
Patch is correct, but several nftables version have a bug (now fixed)
that trigger the checks incorrectly.
5) Reset mac header before the vlan push to avoid warning splat (and
make things functional). From Eric Woudstra.
6) Add missing bounds check in H323 conntrack helper, broken since this
helper was added 20 years ago, from Jenny Guanni Qu.
7) Fix a memory leak in the dynamic set infrastructure, from Pablo Neira
Ayuso. Broken since v5.11.
8+9) a few spots failed to purge skbs queued to userspace via nfqueue,
this causes RCU escape / use-after-free. Also from Pablo. broken
since v3.4 added the CT target to xtables.
10) Fix undefined behaviour in xt_time, use u32 for a shift-by-31
operation, not s32, from Jenny Guanni Qu.
11) H323 conntrack helper lacks a check for length variable becoming
negative after decrement, causes major out-of-bounds read due to
cast to unsigned size later, also from Jenny.
Both issues exist since 2.6 days.

* tag 'nf-26-03-13' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
netfilter: nf_conntrack_h323: check for zero length in DecodeQ931()
netfilter: xt_time: use unsigned int for monthday bit shift
netfilter: xt_CT: drop pending enqueued packets on template removal
netfilter: nft_ct: drop pending enqueued packets on removal
nf_tables: nft_dynset: fix possible stateful expression memleak in error path
netfilter: nf_conntrack_h323: fix OOB read in decode_int() CONS case
netfilter: nf_flow_table_ip: reset mac header before vlan push
netfilter: revert nft_set_rbtree: validate open interval overlap
netfilter: nf_conntrack_sip: fix Content-Length u32 truncation in sip_help_tcp()
netfilter: conntrack: add missing netlink policy validations
netfilter: ctnetlink: fix use-after-free in ctnetlink_dump_exp_ct()
====================

Link: https://patch.msgid.link/20260313150614.21177-1-fw@strlen.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+75 -91
+2 -4
include/net/netfilter/nf_tables.h
··· 277 277 unsigned char data[]; 278 278 }; 279 279 280 - #define NFT_SET_ELEM_INTERNAL_LAST 0x1 281 - 282 280 /* placeholder structure for opaque set element backend representation. */ 283 281 struct nft_elem_priv { }; 284 282 ··· 286 288 * @key: element key 287 289 * @key_end: closing element key 288 290 * @data: element data 289 - * @flags: flags 290 291 * @priv: element private data and extensions 291 292 */ 292 293 struct nft_set_elem { ··· 301 304 u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)]; 302 305 struct nft_data val; 303 306 } data; 304 - u32 flags; 305 307 struct nft_elem_priv *priv; 306 308 }; 307 309 ··· 874 878 u64 timeout, u64 expiration, gfp_t gfp); 875 879 int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set, 876 880 struct nft_expr *expr_array[]); 881 + void nft_set_elem_expr_destroy(const struct nft_ctx *ctx, 882 + struct nft_set_elem_expr *elem_expr); 877 883 void nft_set_elem_destroy(const struct nft_set *set, 878 884 const struct nft_elem_priv *elem_priv, 879 885 bool destroy_expr);
+4
net/netfilter/nf_conntrack_h323_asn1.c
··· 331 331 if (nf_h323_error_boundary(bs, 0, 2)) 332 332 return H323_ERROR_BOUND; 333 333 len = get_bits(bs, 2) + 1; 334 + if (nf_h323_error_boundary(bs, len, 0)) 335 + return H323_ERROR_BOUND; 334 336 BYTE_ALIGN(bs); 335 337 if (base && (f->attr & DECODE)) { /* timeToLive */ 336 338 unsigned int v = get_uint(bs, len) + f->lb; ··· 924 922 break; 925 923 p++; 926 924 len--; 925 + if (len <= 0) 926 + break; 927 927 return DecodeH323_UserInformation(buf, p, len, 928 928 &q931->UUIE); 929 929 }
+26 -2
net/netfilter/nf_conntrack_netlink.c
··· 3212 3212 { 3213 3213 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); 3214 3214 struct nf_conn *ct = cb->data; 3215 - struct nf_conn_help *help = nfct_help(ct); 3215 + struct nf_conn_help *help; 3216 3216 u_int8_t l3proto = nfmsg->nfgen_family; 3217 3217 unsigned long last_id = cb->args[1]; 3218 3218 struct nf_conntrack_expect *exp; 3219 3219 3220 3220 if (cb->args[0]) 3221 + return 0; 3222 + 3223 + help = nfct_help(ct); 3224 + if (!help) 3221 3225 return 0; 3222 3226 3223 3227 rcu_read_lock(); ··· 3253 3249 return skb->len; 3254 3250 } 3255 3251 3252 + static int ctnetlink_dump_exp_ct_start(struct netlink_callback *cb) 3253 + { 3254 + struct nf_conn *ct = cb->data; 3255 + 3256 + if (!refcount_inc_not_zero(&ct->ct_general.use)) 3257 + return -ENOENT; 3258 + return 0; 3259 + } 3260 + 3261 + static int ctnetlink_dump_exp_ct_done(struct netlink_callback *cb) 3262 + { 3263 + struct nf_conn *ct = cb->data; 3264 + 3265 + if (ct) 3266 + nf_ct_put(ct); 3267 + return 0; 3268 + } 3269 + 3256 3270 static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl, 3257 3271 struct sk_buff *skb, 3258 3272 const struct nlmsghdr *nlh, ··· 3286 3264 struct nf_conntrack_zone zone; 3287 3265 struct netlink_dump_control c = { 3288 3266 .dump = ctnetlink_exp_ct_dump_table, 3267 + .start = ctnetlink_dump_exp_ct_start, 3268 + .done = ctnetlink_dump_exp_ct_done, 3289 3269 }; 3290 3270 3291 3271 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, ··· 3489 3465 3490 3466 #if IS_ENABLED(CONFIG_NF_NAT) 3491 3467 static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = { 3492 - [CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 }, 3468 + [CTA_EXPECT_NAT_DIR] = NLA_POLICY_MAX(NLA_BE32, IP_CT_DIR_REPLY), 3493 3469 [CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED }, 3494 3470 }; 3495 3471 #endif
+2 -1
net/netfilter/nf_conntrack_proto_sctp.c
··· 582 582 } 583 583 584 584 static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = { 585 - [CTA_PROTOINFO_SCTP_STATE] = { .type = NLA_U8 }, 585 + [CTA_PROTOINFO_SCTP_STATE] = NLA_POLICY_MAX(NLA_U8, 586 + SCTP_CONNTRACK_HEARTBEAT_SENT), 586 587 [CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NLA_U32 }, 587 588 [CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 }, 588 589 };
+5 -1
net/netfilter/nf_conntrack_sip.c
··· 1534 1534 { 1535 1535 struct tcphdr *th, _tcph; 1536 1536 unsigned int dataoff, datalen; 1537 - unsigned int matchoff, matchlen, clen; 1537 + unsigned int matchoff, matchlen; 1538 1538 unsigned int msglen, origlen; 1539 1539 const char *dptr, *end; 1540 1540 s16 diff, tdiff = 0; 1541 1541 int ret = NF_ACCEPT; 1542 + unsigned long clen; 1542 1543 bool term; 1543 1544 1544 1545 if (ctinfo != IP_CT_ESTABLISHED && ··· 1572 1571 1573 1572 clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); 1574 1573 if (dptr + matchoff == end) 1574 + break; 1575 + 1576 + if (clen > datalen) 1575 1577 break; 1576 1578 1577 1579 term = false;
+1
net/netfilter/nf_flow_table_ip.c
··· 738 738 switch (tuple->encap[i].proto) { 739 739 case htons(ETH_P_8021Q): 740 740 case htons(ETH_P_8021AD): 741 + skb_reset_mac_header(skb); 741 742 if (skb_vlan_push(skb, tuple->encap[i].proto, 742 743 tuple->encap[i].id) < 0) 743 744 return -1;
+6 -19
net/netfilter/nf_tables_api.c
··· 6744 6744 } 6745 6745 } 6746 6746 6747 - static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx, 6748 - struct nft_set_elem_expr *elem_expr) 6747 + void nft_set_elem_expr_destroy(const struct nft_ctx *ctx, 6748 + struct nft_set_elem_expr *elem_expr) 6749 6749 { 6750 6750 struct nft_expr *expr; 6751 6751 u32 size; ··· 7156 7156 } 7157 7157 7158 7158 static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, 7159 - const struct nlattr *attr, u32 nlmsg_flags, 7160 - bool last) 7159 + const struct nlattr *attr, u32 nlmsg_flags) 7161 7160 { 7162 7161 struct nft_expr *expr_array[NFT_SET_EXPR_MAX] = {}; 7163 7162 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; ··· 7443 7444 if (flags) 7444 7445 *nft_set_ext_flags(ext) = flags; 7445 7446 7446 - if (last) 7447 - elem.flags = NFT_SET_ELEM_INTERNAL_LAST; 7448 - else 7449 - elem.flags = 0; 7450 - 7451 7447 if (obj) 7452 7448 *nft_set_ext_obj(ext) = obj; 7453 7449 ··· 7607 7613 nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); 7608 7614 7609 7615 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { 7610 - err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags, 7611 - nla_is_last(attr, rem)); 7616 + err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags); 7612 7617 if (err < 0) { 7613 7618 NL_SET_BAD_ATTR(extack, attr); 7614 7619 return err; ··· 7731 7738 } 7732 7739 7733 7740 static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, 7734 - const struct nlattr *attr, bool last) 7741 + const struct nlattr *attr) 7735 7742 { 7736 7743 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; 7737 7744 struct nft_set_ext_tmpl tmpl; ··· 7798 7805 ext = nft_set_elem_ext(set, elem.priv); 7799 7806 if (flags) 7800 7807 *nft_set_ext_flags(ext) = flags; 7801 - 7802 - if (last) 7803 - elem.flags = NFT_SET_ELEM_INTERNAL_LAST; 7804 - else 7805 - elem.flags = 0; 7806 7808 7807 7809 trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set); 7808 7810 if (trans == NULL) ··· 7949 7961 return nft_set_flush(&ctx, set, genmask); 7950 7962 7951 7963 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { 7952 - err = nft_del_setelem(&ctx, set, attr, 7953 - nla_is_last(attr, rem)); 7964 + err = nft_del_setelem(&ctx, set, attr); 7954 7965 if (err == -ENOENT && 7955 7966 NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM) 7956 7967 continue;
+4
net/netfilter/nft_ct.c
··· 23 23 #include <net/netfilter/nf_conntrack_l4proto.h> 24 24 #include <net/netfilter/nf_conntrack_expect.h> 25 25 #include <net/netfilter/nf_conntrack_seqadj.h> 26 + #include "nf_internals.h" 26 27 27 28 struct nft_ct_helper_obj { 28 29 struct nf_conntrack_helper *helper4; ··· 544 543 #endif 545 544 #ifdef CONFIG_NF_CONNTRACK_ZONES 546 545 case NFT_CT_ZONE: 546 + nf_queue_nf_hook_drop(ctx->net); 547 547 mutex_lock(&nft_ct_pcpu_mutex); 548 548 if (--nft_ct_pcpu_template_refcnt == 0) 549 549 nft_ct_tmpl_put_pcpu(); ··· 1017 1015 struct nft_ct_timeout_obj *priv = nft_obj_data(obj); 1018 1016 struct nf_ct_timeout *timeout = priv->timeout; 1019 1017 1018 + nf_queue_nf_hook_drop(ctx->net); 1020 1019 nf_ct_untimeout(ctx->net, timeout); 1021 1020 nf_ct_netns_put(ctx->net, ctx->family); 1022 1021 kfree(priv->timeout); ··· 1150 1147 { 1151 1148 struct nft_ct_helper_obj *priv = nft_obj_data(obj); 1152 1149 1150 + nf_queue_nf_hook_drop(ctx->net); 1153 1151 if (priv->helper4) 1154 1152 nf_conntrack_helper_put(priv->helper4); 1155 1153 if (priv->helper6)
+9 -1
net/netfilter/nft_dynset.c
··· 30 30 const struct nft_set_ext *ext) 31 31 { 32 32 struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext); 33 + struct nft_ctx ctx = { 34 + .net = read_pnet(&priv->set->net), 35 + .family = priv->set->table->family, 36 + }; 33 37 struct nft_expr *expr; 34 38 int i; 35 39 36 40 for (i = 0; i < priv->num_exprs; i++) { 37 41 expr = nft_setelem_expr_at(elem_expr, elem_expr->size); 38 42 if (nft_expr_clone(expr, priv->expr_array[i], GFP_ATOMIC) < 0) 39 - return -1; 43 + goto err_out; 40 44 41 45 elem_expr->size += priv->expr_array[i]->ops->size; 42 46 } 43 47 44 48 return 0; 49 + err_out: 50 + nft_set_elem_expr_destroy(&ctx, elem_expr); 51 + 52 + return -1; 45 53 } 46 54 47 55 struct nft_elem_priv *nft_dynset_new(struct nft_set *set,
+10 -61
net/netfilter/nft_set_rbtree.c
··· 304 304 priv->start_rbe_cookie = (unsigned long)rbe; 305 305 } 306 306 307 - static void nft_rbtree_set_start_cookie_open(struct nft_rbtree *priv, 308 - const struct nft_rbtree_elem *rbe, 309 - unsigned long open_interval) 310 - { 311 - priv->start_rbe_cookie = (unsigned long)rbe | open_interval; 312 - } 313 - 314 - #define NFT_RBTREE_OPEN_INTERVAL 1UL 315 - 316 307 static bool nft_rbtree_cmp_start_cookie(struct nft_rbtree *priv, 317 308 const struct nft_rbtree_elem *rbe) 318 309 { 319 - return (priv->start_rbe_cookie & ~NFT_RBTREE_OPEN_INTERVAL) == (unsigned long)rbe; 310 + return priv->start_rbe_cookie == (unsigned long)rbe; 320 311 } 321 312 322 313 static bool nft_rbtree_insert_same_interval(const struct net *net, ··· 337 346 338 347 static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, 339 348 struct nft_rbtree_elem *new, 340 - struct nft_elem_priv **elem_priv, u64 tstamp, bool last) 349 + struct nft_elem_priv **elem_priv, u64 tstamp) 341 350 { 342 351 struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; 343 352 struct rb_node *node, *next, *parent, **p, *first = NULL; 344 353 struct nft_rbtree *priv = nft_set_priv(set); 345 354 u8 cur_genmask = nft_genmask_cur(net); 346 355 u8 genmask = nft_genmask_next(net); 347 - unsigned long open_interval = 0; 348 356 int d; 349 357 350 358 /* Descend the tree to search for an existing element greater than the ··· 449 459 } 450 460 } 451 461 452 - if (nft_rbtree_interval_null(set, new)) { 462 + if (nft_rbtree_interval_null(set, new)) 453 463 priv->start_rbe_cookie = 0; 454 - } else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) { 455 - if (nft_set_is_anonymous(set)) { 456 - priv->start_rbe_cookie = 0; 457 - } else if (priv->start_rbe_cookie & NFT_RBTREE_OPEN_INTERVAL) { 458 - /* Previous element is an open interval that partially 459 - * overlaps with an existing non-open interval. 460 - */ 461 - return -ENOTEMPTY; 462 - } 463 - } 464 + else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) 465 + priv->start_rbe_cookie = 0; 464 466 465 467 /* - new start element matching existing start element: full overlap 466 468 * reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given. ··· 460 478 if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) && 461 479 nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) { 462 480 *elem_priv = &rbe_ge->priv; 463 - 464 - /* - Corner case: new start element of open interval (which 465 - * comes as last element in the batch) overlaps the start of 466 - * an existing interval with an end element: partial overlap. 467 - */ 468 - node = rb_first(&priv->root); 469 - rbe = __nft_rbtree_next_active(node, genmask); 470 - if (rbe && nft_rbtree_interval_end(rbe)) { 471 - rbe = nft_rbtree_next_active(rbe, genmask); 472 - if (rbe && 473 - nft_rbtree_interval_start(rbe) && 474 - !nft_rbtree_cmp(set, new, rbe)) { 475 - if (last) 476 - return -ENOTEMPTY; 477 - 478 - /* Maybe open interval? */ 479 - open_interval = NFT_RBTREE_OPEN_INTERVAL; 480 - } 481 - } 482 - nft_rbtree_set_start_cookie_open(priv, rbe_ge, open_interval); 483 - 481 + nft_rbtree_set_start_cookie(priv, rbe_ge); 484 482 return -EEXIST; 485 483 } 486 484 ··· 513 551 */ 514 552 if (rbe_ge && 515 553 nft_rbtree_interval_end(rbe_ge) && nft_rbtree_interval_end(new)) 516 - return -ENOTEMPTY; 517 - 518 - /* - start element overlaps an open interval but end element is new: 519 - * partial overlap, reported as -ENOEMPTY. 520 - */ 521 - if (!rbe_ge && priv->start_rbe_cookie && nft_rbtree_interval_end(new)) 522 554 return -ENOTEMPTY; 523 555 524 556 /* Accepted element: pick insertion point depending on key value */ ··· 624 668 struct nft_elem_priv **elem_priv) 625 669 { 626 670 struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem->priv); 627 - bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST); 628 671 struct nft_rbtree *priv = nft_set_priv(set); 629 672 u64 tstamp = nft_net_tstamp(net); 630 673 int err; ··· 640 685 cond_resched(); 641 686 642 687 write_lock_bh(&priv->lock); 643 - err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp, last); 688 + err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp); 644 689 write_unlock_bh(&priv->lock); 645 - 646 - if (nft_rbtree_interval_end(rbe)) 647 - priv->start_rbe_cookie = 0; 648 - 649 690 } while (err == -EAGAIN); 650 691 651 692 return err; ··· 729 778 const struct nft_set_elem *elem) 730 779 { 731 780 struct nft_rbtree_elem *rbe, *this = nft_elem_priv_cast(elem->priv); 732 - bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST); 733 781 struct nft_rbtree *priv = nft_set_priv(set); 734 782 const struct rb_node *parent = priv->root.rb_node; 735 783 u8 genmask = nft_genmask_next(net); ··· 769 819 continue; 770 820 } 771 821 772 - if (nft_rbtree_interval_start(rbe)) { 773 - if (!last) 774 - nft_rbtree_set_start_cookie(priv, rbe); 775 - } else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe)) 822 + if (nft_rbtree_interval_start(rbe)) 823 + nft_rbtree_set_start_cookie(priv, rbe); 824 + else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe)) 776 825 return NULL; 777 826 778 827 nft_rbtree_flush(net, set, &rbe->priv);
+4
net/netfilter/xt_CT.c
··· 16 16 #include <net/netfilter/nf_conntrack_ecache.h> 17 17 #include <net/netfilter/nf_conntrack_timeout.h> 18 18 #include <net/netfilter/nf_conntrack_zones.h> 19 + #include "nf_internals.h" 19 20 20 21 static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct) 21 22 { ··· 284 283 struct nf_conn_help *help; 285 284 286 285 if (ct) { 286 + if (info->helper[0] || info->timeout[0]) 287 + nf_queue_nf_hook_drop(par->net); 288 + 287 289 help = nfct_help(ct); 288 290 xt_ct_put_helper(help); 289 291
+2 -2
net/netfilter/xt_time.c
··· 223 223 224 224 localtime_2(&current_time, stamp); 225 225 226 - if (!(info->weekdays_match & (1 << current_time.weekday))) 226 + if (!(info->weekdays_match & (1U << current_time.weekday))) 227 227 return false; 228 228 229 229 /* Do not spend time computing monthday if all days match anyway */ 230 230 if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) { 231 231 localtime_3(&current_time, stamp); 232 - if (!(info->monthdays_match & (1 << current_time.monthday))) 232 + if (!(info->monthdays_match & (1U << current_time.monthday))) 233 233 return false; 234 234 } 235 235