diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/filter.c | 4 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 6 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 6 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 16 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 3 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 16 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.c | 4 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_gen.h | 2 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_list_set.c | 9 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_helper.c | 39 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 43 | ||||
-rw-r--r-- | net/netfilter/nfnetlink.c | 2 | ||||
-rw-r--r-- | net/netfilter/xt_hashlimit.c | 25 |
13 files changed, 120 insertions, 55 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index e466e0040137..ebaeaf2e46e8 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2584,8 +2584,8 @@ BPF_CALL_5(bpf_xdp_event_output, struct xdp_buff *, xdp, struct bpf_map *, map, if (unlikely(xdp_size > (unsigned long)(xdp->data_end - xdp->data))) return -EFAULT; - return bpf_event_output(map, flags, meta, meta_size, xdp, xdp_size, - bpf_xdp_copy); + return bpf_event_output(map, flags, meta, meta_size, xdp->data, + xdp_size, bpf_xdp_copy); } static const struct bpf_func_proto bpf_xdp_event_output_proto = { diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index b043ec833785..409d0cfd3447 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -1017,9 +1017,15 @@ static void __net_exit dccp_v4_exit_net(struct net *net) inet_ctl_sock_destroy(net->dccp.v4_ctl_sk); } +static void __net_exit dccp_v4_exit_batch(struct list_head *net_exit_list) +{ + inet_twsk_purge(&dccp_hashinfo, AF_INET); +} + static struct pernet_operations dccp_v4_ops = { .init = dccp_v4_init_net, .exit = dccp_v4_exit_net, + .exit_batch = dccp_v4_exit_batch, }; static int __init dccp_v4_init(void) diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index cef60a4a2803..233b57367758 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1075,9 +1075,15 @@ static void __net_exit dccp_v6_exit_net(struct net *net) inet_ctl_sock_destroy(net->dccp.v6_ctl_sk); } +static void __net_exit dccp_v6_exit_batch(struct list_head *net_exit_list) +{ + inet_twsk_purge(&dccp_hashinfo, AF_INET6); +} + static struct pernet_operations dccp_v6_ops = { .init = dccp_v6_init_net, .exit = dccp_v6_exit_net, + .exit_batch = dccp_v6_exit_batch, }; static int __init dccp_v6_init(void) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 8c124d4ef4b7..9a89b8deafae 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -145,6 +145,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) struct flowi4 *fl4; struct rtable *rt; int err; + u32 seq; struct ip_options_rcu *inet_opt; struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row; @@ -234,12 +235,15 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) sk_setup_caps(sk, &rt->dst); rt = NULL; - if (!tp->write_seq && likely(!tp->repair)) - tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr, - inet->inet_daddr, - inet->inet_sport, - usin->sin_port, - &tp->tsoffset); + if (likely(!tp->repair)) { + seq = secure_tcp_sequence_number(inet->inet_saddr, + inet->inet_daddr, + inet->inet_sport, + usin->sin_port, + &tp->tsoffset); + if (!tp->write_seq) + tp->write_seq = seq; + } inet->inet_id = tp->write_seq ^ jiffies; diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index dff7d2aaf861..7e16243cdb58 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -101,7 +101,8 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, tcp_parse_options(skb, &tmp_opt, 0, NULL); if (tmp_opt.saw_tstamp) { - tmp_opt.rcv_tsecr -= tcptw->tw_ts_offset; + if (tmp_opt.rcv_tsecr) + tmp_opt.rcv_tsecr -= tcptw->tw_ts_offset; tmp_opt.ts_recent = tcptw->tw_ts_recent; tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; paws_reject = tcp_paws_reject(&tmp_opt, th->rst); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 21c719965b6b..60a5295a7de6 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -122,6 +122,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, struct flowi6 fl6; struct dst_entry *dst; int addr_type; + u32 seq; int err; struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row; @@ -285,12 +286,15 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, sk_set_txhash(sk); - if (!tp->write_seq && likely(!tp->repair)) - tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, - sk->sk_v6_daddr.s6_addr32, - inet->inet_sport, - inet->inet_dport, - &tp->tsoffset); + if (likely(!tp->repair)) { + seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, + sk->sk_v6_daddr.s6_addr32, + inet->inet_sport, + inet->inet_dport, + &tp->tsoffset); + if (!tp->write_seq) + tp->write_seq = seq; + } if (tcp_fastopen_defer_connect(sk, &err)) return err; diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 85948c69b236..b58000efee73 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1317,6 +1317,9 @@ static void l2tp_tunnel_del_work(struct work_struct *work) struct sock *sk = NULL; tunnel = container_of(work, struct l2tp_tunnel, del_work); + + l2tp_tunnel_closeall(tunnel); + sk = l2tp_tunnel_sock_lookup(tunnel); if (!sk) goto out; @@ -1639,7 +1642,6 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create); int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) { l2tp_tunnel_inc_refcount(tunnel); - l2tp_tunnel_closeall(tunnel); if (false == queue_work(l2tp_wq, &tunnel->del_work)) { l2tp_tunnel_dec_refcount(tunnel); return 1; diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index 1b05d4a7d5a1..f236c0bc7b3f 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h @@ -897,7 +897,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, continue; data = ahash_data(n, j, dsize); memcpy(tmp->value + k * dsize, data, dsize); - set_bit(j, tmp->used); + set_bit(k, tmp->used); k++; } tmp->pos = k; diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index 51077c53d76b..178d4eba013b 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c @@ -260,11 +260,14 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext, else prev = e; } + + /* If before/after is used on an empty set */ + if ((d->before > 0 && !next) || + (d->before < 0 && !prev)) + return -IPSET_ERR_REF_EXIST; + /* Re-add already existing element */ if (n) { - if ((d->before > 0 && !next) || - (d->before < 0 && !prev)) - return -IPSET_ERR_REF_EXIST; if (!flag_exist) return -IPSET_ERR_EXIST; /* Update extensions */ diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 7341adf7059d..6dc44d9b4190 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -188,6 +188,26 @@ nf_ct_helper_ext_add(struct nf_conn *ct, } EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); +static struct nf_conntrack_helper * +nf_ct_lookup_helper(struct nf_conn *ct, struct net *net) +{ + if (!net->ct.sysctl_auto_assign_helper) { + if (net->ct.auto_assign_helper_warned) + return NULL; + if (!__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)) + return NULL; + pr_info("nf_conntrack: default automatic helper assignment " + "has been turned off for security reasons and CT-based " + " firewall rule not found. Use the iptables CT target " + "to attach helpers instead.\n"); + net->ct.auto_assign_helper_warned = 1; + return NULL; + } + + return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); +} + + int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, gfp_t flags) { @@ -213,21 +233,14 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, } help = nfct_help(ct); - if (net->ct.sysctl_auto_assign_helper && helper == NULL) { - helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); - if (unlikely(!net->ct.auto_assign_helper_warned && helper)) { - pr_info("nf_conntrack: automatic helper " - "assignment is deprecated and it will " - "be removed soon. Use the iptables CT target " - "to attach helpers instead.\n"); - net->ct.auto_assign_helper_warned = true; - } - } if (helper == NULL) { - if (help) - RCU_INIT_POINTER(help->helper, NULL); - return 0; + helper = nf_ct_lookup_helper(ct, net); + if (helper == NULL) { + if (help) + RCU_INIT_POINTER(help->helper, NULL); + return 0; + } } if (help == NULL) { diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 27540455dc62..6806b5e73567 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1478,14 +1478,23 @@ static int ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *helpinfo = NULL; int err; - /* don't change helper of sibling connections */ - if (ct->master) - return -EBUSY; - err = ctnetlink_parse_help(cda[CTA_HELP], &helpname, &helpinfo); if (err < 0) return err; + /* don't change helper of sibling connections */ + if (ct->master) { + /* If we try to change the helper to the same thing twice, + * treat the second attempt as a no-op instead of returning + * an error. + */ + if (help && help->helper && + !strcmp(help->helper->name, helpname)) + return 0; + else + return -EBUSY; + } + if (!strcmp(helpname, "")) { if (help && help->helper) { /* we had a helper before ... */ @@ -2270,6 +2279,30 @@ nla_put_failure: } static int +ctnetlink_update_status(struct nf_conn *ct, const struct nlattr * const cda[]) +{ + unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS])); + unsigned long d = ct->status ^ status; + + if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) + /* SEEN_REPLY bit can only be set */ + return -EBUSY; + + if (d & IPS_ASSURED && !(status & IPS_ASSURED)) + /* ASSURED bit can only be set */ + return -EBUSY; + + /* This check is less strict than ctnetlink_change_status() + * because callers often flip IPS_EXPECTED bits when sending + * an NFQA_CT attribute to the kernel. So ignore the + * unchangeable bits but do not error out. + */ + ct->status = (status & ~IPS_UNCHANGEABLE_MASK) | + (ct->status & IPS_UNCHANGEABLE_MASK); + return 0; +} + +static int ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) { int err; @@ -2280,7 +2313,7 @@ ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) return err; } if (cda[CTA_STATUS]) { - err = ctnetlink_change_status(ct, cda); + err = ctnetlink_update_status(ct, cda); if (err < 0) return err; } diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index a2148d0bc50e..68eda920160e 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -279,7 +279,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, struct net *net = sock_net(skb->sk); const struct nfnetlink_subsystem *ss; const struct nfnl_callback *nc; - static LIST_HEAD(err_list); + LIST_HEAD(err_list); u32 status; int err; diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 26ef70c50e3b..2a6dfe8b74d3 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -463,23 +463,16 @@ static u32 xt_hashlimit_len_to_chunks(u32 len) /* Precision saver. */ static u64 user2credits(u64 user, int revision) { - if (revision == 1) { - /* If multiplying would overflow... */ - if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY_v1)) - /* Divide first. */ - return div64_u64(user, XT_HASHLIMIT_SCALE) - * HZ * CREDITS_PER_JIFFY_v1; - - return div64_u64(user * HZ * CREDITS_PER_JIFFY_v1, - XT_HASHLIMIT_SCALE); - } else { - if (user > 0xFFFFFFFFFFFFFFFFULL / (HZ*CREDITS_PER_JIFFY)) - return div64_u64(user, XT_HASHLIMIT_SCALE_v2) - * HZ * CREDITS_PER_JIFFY; + u64 scale = (revision == 1) ? + XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2; + u64 cpj = (revision == 1) ? + CREDITS_PER_JIFFY_v1 : CREDITS_PER_JIFFY; - return div64_u64(user * HZ * CREDITS_PER_JIFFY, - XT_HASHLIMIT_SCALE_v2); - } + /* Avoid overflow: divide the constant operands first */ + if (scale >= HZ * cpj) + return div64_u64(user, div64_u64(scale, HZ * cpj)); + + return user * div64_u64(HZ * cpj, scale); } static u32 user2credits_byte(u32 user) |