diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-11-01 19:14:00 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-11-03 08:28:03 -0400 |
commit | 8866df9264a34e675b4ee8a151db819b87cce2d3 (patch) | |
tree | 9d7f7ce50406f63272a4c6603334578db097b569 | |
parent | a95a7774d51e13f9cf4b7285666829b68852f07a (diff) |
netfilter: nfnetlink_cttimeout: pass default timeout policy to obj_to_nlattr
Otherwise, we hit a NULL pointer deference since handlers always assume
default timeout policy is passed.
netlink: 24 bytes leftover after parsing attributes in process `syz-executor2'.
kasan: CONFIG_KASAN_INLINE enabled
kasan: GPF could be caused by NULL-ptr deref or user memory access
general protection fault: 0000 [#1] PREEMPT SMP KASAN
CPU: 0 PID: 9575 Comm: syz-executor1 Not tainted 4.19.0+ #312
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
RIP: 0010:icmp_timeout_obj_to_nlattr+0x77/0x170 net/netfilter/nf_conntrack_proto_icmp.c:297
Fixes: c779e849608a ("netfilter: conntrack: remove get_timeout() indirection")
Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | net/netfilter/nfnetlink_cttimeout.c | 47 |
1 files changed, 40 insertions, 7 deletions
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index e7a50af1b3d6..a518eb162344 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c | |||
@@ -382,7 +382,8 @@ err: | |||
382 | static int | 382 | static int |
383 | cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid, | 383 | cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid, |
384 | u32 seq, u32 type, int event, u16 l3num, | 384 | u32 seq, u32 type, int event, u16 l3num, |
385 | const struct nf_conntrack_l4proto *l4proto) | 385 | const struct nf_conntrack_l4proto *l4proto, |
386 | const unsigned int *timeouts) | ||
386 | { | 387 | { |
387 | struct nlmsghdr *nlh; | 388 | struct nlmsghdr *nlh; |
388 | struct nfgenmsg *nfmsg; | 389 | struct nfgenmsg *nfmsg; |
@@ -408,7 +409,7 @@ cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid, | |||
408 | if (!nest_parms) | 409 | if (!nest_parms) |
409 | goto nla_put_failure; | 410 | goto nla_put_failure; |
410 | 411 | ||
411 | ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, NULL); | 412 | ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts); |
412 | if (ret < 0) | 413 | if (ret < 0) |
413 | goto nla_put_failure; | 414 | goto nla_put_failure; |
414 | 415 | ||
@@ -430,6 +431,7 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl, | |||
430 | struct netlink_ext_ack *extack) | 431 | struct netlink_ext_ack *extack) |
431 | { | 432 | { |
432 | const struct nf_conntrack_l4proto *l4proto; | 433 | const struct nf_conntrack_l4proto *l4proto; |
434 | unsigned int *timeouts = NULL; | ||
433 | struct sk_buff *skb2; | 435 | struct sk_buff *skb2; |
434 | int ret, err; | 436 | int ret, err; |
435 | __u16 l3num; | 437 | __u16 l3num; |
@@ -442,12 +444,44 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl, | |||
442 | l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); | 444 | l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); |
443 | l4proto = nf_ct_l4proto_find_get(l4num); | 445 | l4proto = nf_ct_l4proto_find_get(l4num); |
444 | 446 | ||
445 | /* This protocol is not supported, skip. */ | 447 | err = -EOPNOTSUPP; |
446 | if (l4proto->l4proto != l4num) { | 448 | if (l4proto->l4proto != l4num) |
447 | err = -EOPNOTSUPP; | ||
448 | goto err; | 449 | goto err; |
450 | |||
451 | switch (l4proto->l4proto) { | ||
452 | case IPPROTO_ICMP: | ||
453 | timeouts = &nf_icmp_pernet(net)->timeout; | ||
454 | break; | ||
455 | case IPPROTO_TCP: | ||
456 | timeouts = nf_tcp_pernet(net)->timeouts; | ||
457 | break; | ||
458 | case IPPROTO_UDP: | ||
459 | timeouts = nf_udp_pernet(net)->timeouts; | ||
460 | break; | ||
461 | case IPPROTO_DCCP: | ||
462 | #ifdef CONFIG_NF_CT_PROTO_DCCP | ||
463 | timeouts = nf_dccp_pernet(net)->dccp_timeout; | ||
464 | #endif | ||
465 | break; | ||
466 | case IPPROTO_ICMPV6: | ||
467 | timeouts = &nf_icmpv6_pernet(net)->timeout; | ||
468 | break; | ||
469 | case IPPROTO_SCTP: | ||
470 | #ifdef CONFIG_NF_CT_PROTO_SCTP | ||
471 | timeouts = nf_sctp_pernet(net)->timeouts; | ||
472 | #endif | ||
473 | break; | ||
474 | case 255: | ||
475 | timeouts = &nf_generic_pernet(net)->timeout; | ||
476 | break; | ||
477 | default: | ||
478 | WARN_ON_ONCE(1); | ||
479 | break; | ||
449 | } | 480 | } |
450 | 481 | ||
482 | if (!timeouts) | ||
483 | goto err; | ||
484 | |||
451 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 485 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
452 | if (skb2 == NULL) { | 486 | if (skb2 == NULL) { |
453 | err = -ENOMEM; | 487 | err = -ENOMEM; |
@@ -458,8 +492,7 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl, | |||
458 | nlh->nlmsg_seq, | 492 | nlh->nlmsg_seq, |
459 | NFNL_MSG_TYPE(nlh->nlmsg_type), | 493 | NFNL_MSG_TYPE(nlh->nlmsg_type), |
460 | IPCTNL_MSG_TIMEOUT_DEFAULT_SET, | 494 | IPCTNL_MSG_TIMEOUT_DEFAULT_SET, |
461 | l3num, | 495 | l3num, l4proto, timeouts); |
462 | l4proto); | ||
463 | if (ret <= 0) { | 496 | if (ret <= 0) { |
464 | kfree_skb(skb2); | 497 | kfree_skb(skb2); |
465 | err = -ENOMEM; | 498 | err = -ENOMEM; |