Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Browse files Browse the repository at this point in the history
Pablo Neira Ayuso says:

====================
Netfilter/IPVS fixes for net

The following patchset contains Netfilter/IPVS fixes for your net tree:

1) Reject non-null terminated helper names from xt_CT, from Gao Feng.

2) Fix KASAN splat due to out-of-bound access from commit phase, from
   Alexey Kodanev.

3) Missing conntrack hook registration on IPVS FTP helper, from Julian
   Anastasov.

4) Incorrect skbuff allocation size in bridge nft_reject, from Taehee Yoo.

5) Fix inverted check on packet xmit to non-local addresses, also from
   Julian.

6) Fix ebtables alignment compat problems, from Alin Nastac.

7) Hook mask checks are not correct in xt_set, from Serhey Popovych.

8) Fix timeout listing of element in ipsets, from Jozsef.

9) Cap maximum timeout value in ipset, also from Jozsef.

10) Don't allow family option for hash:mac sets, from Florent Fourcot.

11) Restrict ebtables to work with NFPROTO_BRIDGE targets only, this
    Florian.

12) Another bug reported by KASAN in the rbtree set backend, from
    Taehee Yoo.

13) Missing __IPS_MAX_BIT update doesn't include IPS_OFFLOAD_BIT.
    From Gao Feng.

14) Missing initialization of match/target in ebtables, from Florian
    Westphal.

15) Remove useless nft_dup.h file in include path, from C. Labbe.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Jun 11, 2018
2 parents 349b71d + d8e87fc commit a08ce73
Show file tree
Hide file tree
Showing 15 changed files with 99 additions and 36 deletions.
20 changes: 14 additions & 6 deletions include/linux/netfilter/ipset/ip_set_timeout.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
/* Set is defined with timeout support: timeout value may be 0 */
#define IPSET_NO_TIMEOUT UINT_MAX

/* Max timeout value, see msecs_to_jiffies() in jiffies.h */
#define IPSET_MAX_TIMEOUT (UINT_MAX >> 1)/MSEC_PER_SEC

#define ip_set_adt_opt_timeout(opt, set) \
((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (set)->timeout)

Expand All @@ -32,11 +35,10 @@ ip_set_timeout_uget(struct nlattr *tb)
unsigned int timeout = ip_set_get_h32(tb);

/* Normalize to fit into jiffies */
if (timeout > UINT_MAX/MSEC_PER_SEC)
timeout = UINT_MAX/MSEC_PER_SEC;
if (timeout > IPSET_MAX_TIMEOUT)
timeout = IPSET_MAX_TIMEOUT;

/* Userspace supplied TIMEOUT parameter: adjust crazy size */
return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout;
return timeout;
}

static inline bool
Expand Down Expand Up @@ -65,8 +67,14 @@ ip_set_timeout_set(unsigned long *timeout, u32 value)
static inline u32
ip_set_timeout_get(const unsigned long *timeout)
{
return *timeout == IPSET_ELEM_PERMANENT ? 0 :
jiffies_to_msecs(*timeout - jiffies)/MSEC_PER_SEC;
u32 t;

if (*timeout == IPSET_ELEM_PERMANENT)
return 0;

t = jiffies_to_msecs(*timeout - jiffies)/MSEC_PER_SEC;
/* Zero value in userspace means no timeout */
return t == 0 ? 1 : t;
}

#endif /* __KERNEL__ */
Expand Down
30 changes: 30 additions & 0 deletions include/net/ip_vs.h
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ struct ip_vs_service {

/* alternate persistence engine */
struct ip_vs_pe __rcu *pe;
int conntrack_afmask;

struct rcu_head rcu_head;
};
Expand Down Expand Up @@ -1611,6 +1612,35 @@ static inline bool ip_vs_conn_uses_conntrack(struct ip_vs_conn *cp,
return false;
}

static inline int ip_vs_register_conntrack(struct ip_vs_service *svc)
{
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
int afmask = (svc->af == AF_INET6) ? 2 : 1;
int ret = 0;

if (!(svc->conntrack_afmask & afmask)) {
ret = nf_ct_netns_get(svc->ipvs->net, svc->af);
if (ret >= 0)
svc->conntrack_afmask |= afmask;
}
return ret;
#else
return 0;
#endif
}

static inline void ip_vs_unregister_conntrack(struct ip_vs_service *svc)
{
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
int afmask = (svc->af == AF_INET6) ? 2 : 1;

if (svc->conntrack_afmask & afmask) {
nf_ct_netns_put(svc->ipvs->net, svc->af);
svc->conntrack_afmask &= ~afmask;
}
#endif
}

static inline int
ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
{
Expand Down
10 changes: 0 additions & 10 deletions include/net/netfilter/nft_dup.h

This file was deleted.

2 changes: 1 addition & 1 deletion include/uapi/linux/netfilter/nf_conntrack_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ enum ip_conntrack_status {
IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING |
IPS_SEQ_ADJUST | IPS_TEMPLATE | IPS_OFFLOAD),

__IPS_MAX_BIT = 14,
__IPS_MAX_BIT = 15,
};

/* Connection tracking event types */
Expand Down
25 changes: 20 additions & 5 deletions net/bridge/netfilter/ebtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,12 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
watcher = xt_request_find_target(NFPROTO_BRIDGE, w->u.name, 0);
if (IS_ERR(watcher))
return PTR_ERR(watcher);

if (watcher->family != NFPROTO_BRIDGE) {
module_put(watcher->me);
return -ENOENT;
}

w->u.watcher = watcher;

par->target = watcher;
Expand Down Expand Up @@ -709,6 +715,8 @@ ebt_check_entry(struct ebt_entry *e, struct net *net,
}
i = 0;

memset(&mtpar, 0, sizeof(mtpar));
memset(&tgpar, 0, sizeof(tgpar));
mtpar.net = tgpar.net = net;
mtpar.table = tgpar.table = name;
mtpar.entryinfo = tgpar.entryinfo = e;
Expand All @@ -730,6 +738,13 @@ ebt_check_entry(struct ebt_entry *e, struct net *net,
goto cleanup_watchers;
}

/* Reject UNSPEC, xtables verdicts/return values are incompatible */
if (target->family != NFPROTO_BRIDGE) {
module_put(target->me);
ret = -ENOENT;
goto cleanup_watchers;
}

t->u.target = target;
if (t->u.target == &ebt_standard_target) {
if (gap < sizeof(struct ebt_standard_target)) {
Expand Down Expand Up @@ -1605,16 +1620,16 @@ struct compat_ebt_entry_mwt {
compat_uptr_t ptr;
} u;
compat_uint_t match_size;
compat_uint_t data[0];
compat_uint_t data[0] __attribute__ ((aligned (__alignof__(struct compat_ebt_replace))));
};

/* account for possible padding between match_size and ->data */
static int ebt_compat_entry_padsize(void)
{
BUILD_BUG_ON(XT_ALIGN(sizeof(struct ebt_entry_match)) <
COMPAT_XT_ALIGN(sizeof(struct compat_ebt_entry_mwt)));
return (int) XT_ALIGN(sizeof(struct ebt_entry_match)) -
COMPAT_XT_ALIGN(sizeof(struct compat_ebt_entry_mwt));
BUILD_BUG_ON(sizeof(struct ebt_entry_match) <
sizeof(struct compat_ebt_entry_mwt));
return (int) sizeof(struct ebt_entry_match) -
sizeof(struct compat_ebt_entry_mwt);
}

static int ebt_compat_match_offset(const struct xt_match *match,
Expand Down
2 changes: 1 addition & 1 deletion net/bridge/netfilter/nft_reject_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ static void nft_reject_br_send_v6_unreach(struct net *net,
if (!reject6_br_csum_ok(oldskb, hook))
return;

nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmp6hdr) +
nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr) +
LL_MAX_HEADER + len, GFP_ATOMIC);
if (!nskb)
return;
Expand Down
1 change: 1 addition & 0 deletions net/ipv4/netfilter/ip_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
return -ENOMEM;

j = 0;
memset(&mtpar, 0, sizeof(mtpar));
mtpar.net = net;
mtpar.table = name;
mtpar.entryinfo = &e->ip;
Expand Down
1 change: 1 addition & 0 deletions net/ipv6/netfilter/ip6_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
return -ENOMEM;

j = 0;
memset(&mtpar, 0, sizeof(mtpar));
mtpar.net = net;
mtpar.table = name;
mtpar.entryinfo = &e->ipv6;
Expand Down
5 changes: 4 additions & 1 deletion net/netfilter/ipset/ip_set_hash_gen.h
Original file line number Diff line number Diff line change
Expand Up @@ -1234,7 +1234,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
pr_debug("Create set %s with family %s\n",
set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");

#ifndef IP_SET_PROTO_UNDEF
#ifdef IP_SET_PROTO_UNDEF
if (set->family != NFPROTO_UNSPEC)
return -IPSET_ERR_INVALID_FAMILY;
#else
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY;
#endif
Expand Down
4 changes: 4 additions & 0 deletions net/netfilter/ipvs/ip_vs_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,9 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
* For now only for NAT!
*/
ip_vs_rs_hash(ipvs, dest);
/* FTP-NAT requires conntrack for mangling */
if (svc->port == FTPPORT)
ip_vs_register_conntrack(svc);
}
atomic_set(&dest->conn_flags, conn_flags);

Expand Down Expand Up @@ -1462,6 +1465,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup)
*/
static void ip_vs_unlink_service(struct ip_vs_service *svc, bool cleanup)
{
ip_vs_unregister_conntrack(svc);
/* Hold svc to avoid double release from dest_trash */
atomic_inc(&svc->refcnt);
/*
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/ipvs/ip_vs_xmit.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ static inline bool crosses_local_route_boundary(int skb_af, struct sk_buff *skb,
bool new_rt_is_local)
{
bool rt_mode_allow_local = !!(rt_mode & IP_VS_RT_MODE_LOCAL);
bool rt_mode_allow_non_local = !!(rt_mode & IP_VS_RT_MODE_LOCAL);
bool rt_mode_allow_non_local = !!(rt_mode & IP_VS_RT_MODE_NON_LOCAL);
bool rt_mode_allow_redirect = !!(rt_mode & IP_VS_RT_MODE_RDR);
bool source_is_loopback;
bool old_rt_is_local;
Expand Down
11 changes: 6 additions & 5 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -2890,12 +2890,13 @@ static struct nft_set *nft_set_lookup_byid(const struct net *net,
u32 id = ntohl(nla_get_be32(nla));

list_for_each_entry(trans, &net->nft.commit_list, list) {
struct nft_set *set = nft_trans_set(trans);
if (trans->msg_type == NFT_MSG_NEWSET) {
struct nft_set *set = nft_trans_set(trans);

if (trans->msg_type == NFT_MSG_NEWSET &&
id == nft_trans_set_id(trans) &&
nft_active_genmask(set, genmask))
return set;
if (id == nft_trans_set_id(trans) &&
nft_active_genmask(set, genmask))
return set;
}
}
return ERR_PTR(-ENOENT);
}
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/nft_set_rbtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
parent = rcu_dereference_raw(parent->rb_left);
if (interval &&
nft_rbtree_equal(set, this, interval) &&
nft_rbtree_interval_end(this) &&
nft_rbtree_interval_end(rbe) &&
!nft_rbtree_interval_end(interval))
continue;
interval = rbe;
Expand Down
10 changes: 10 additions & 0 deletions net/netfilter/xt_CT.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,22 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
}

if (info->helper[0]) {
if (strnlen(info->helper, sizeof(info->helper)) == sizeof(info->helper)) {
ret = -ENAMETOOLONG;
goto err3;
}

ret = xt_ct_set_helper(ct, info->helper, par);
if (ret < 0)
goto err3;
}

if (info->timeout[0]) {
if (strnlen(info->timeout, sizeof(info->timeout)) == sizeof(info->timeout)) {
ret = -ENAMETOOLONG;
goto err4;
}

ret = xt_ct_set_timeout(ct, par, info->timeout);
if (ret < 0)
goto err4;
Expand Down
10 changes: 5 additions & 5 deletions net/netfilter/xt_set.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,8 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)

/* Normalize to fit into jiffies */
if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC)
add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC;
add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
if (info->add_set.index != IPSET_INVALID_ID)
ip_set_add(info->add_set.index, skb, par, &add_opt);
if (info->del_set.index != IPSET_INVALID_ID)
Expand Down Expand Up @@ -407,8 +407,8 @@ set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)

/* Normalize to fit into jiffies */
if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC)
add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC;
add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
if (info->add_set.index != IPSET_INVALID_ID)
ip_set_add(info->add_set.index, skb, par, &add_opt);
if (info->del_set.index != IPSET_INVALID_ID)
Expand Down Expand Up @@ -470,7 +470,7 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
}
if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
(info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
!(par->hook_mask & (1 << NF_INET_FORWARD |
(par->hook_mask & ~(1 << NF_INET_FORWARD |
1 << NF_INET_LOCAL_OUT |
1 << NF_INET_POST_ROUTING))) {
pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
Expand Down

0 comments on commit a08ce73

Please sign in to comment.