Commit 53ba60af authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for net:

1) Missing register size validation in bitwise and cmp offloads.

2) Fix error code in ip_set_sockfn_get() when copy_to_user() fails,
   from Dan Carpenter.

3) Oneliner to copy MAC address in IPv6 hash:ip,mac sets, from
   Stefano Brivio.

4) Missing policy validation in ipset with NL_VALIDATE_STRICT,
   from Jozsef Kadlecsik.

5) Fix unaligned access to private data area of nf_tables instructions,
   from Lukas Wunner.

6) Relax check for object updates, reported as a regression by
   Eric Garver, patch from Fernando Fernandez Mancera.

7) Crash on ebtables dnat extension when used from the output path.
   From Florian Westphal.

8) Fix bogus EOPNOTSUPP when updating basechain flags.

9) Fix bogus EBUSY when updating a basechain that is already offloaded.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 98f33755 774e4d34
...@@ -820,7 +820,8 @@ struct nft_expr_ops { ...@@ -820,7 +820,8 @@ struct nft_expr_ops {
*/ */
struct nft_expr { struct nft_expr {
const struct nft_expr_ops *ops; const struct nft_expr_ops *ops;
unsigned char data[]; unsigned char data[]
__attribute__((aligned(__alignof__(u64))));
}; };
static inline void *nft_expr_priv(const struct nft_expr *expr) static inline void *nft_expr_priv(const struct nft_expr *expr)
......
...@@ -20,7 +20,6 @@ static unsigned int ...@@ -20,7 +20,6 @@ static unsigned int
ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par) ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par)
{ {
const struct ebt_nat_info *info = par->targinfo; const struct ebt_nat_info *info = par->targinfo;
struct net_device *dev;
if (skb_ensure_writable(skb, ETH_ALEN)) if (skb_ensure_writable(skb, ETH_ALEN))
return EBT_DROP; return EBT_DROP;
...@@ -33,10 +32,22 @@ ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par) ...@@ -33,10 +32,22 @@ ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par)
else else
skb->pkt_type = PACKET_MULTICAST; skb->pkt_type = PACKET_MULTICAST;
} else { } else {
if (xt_hooknum(par) != NF_BR_BROUTING) const struct net_device *dev;
dev = br_port_get_rcu(xt_in(par))->br->dev;
else switch (xt_hooknum(par)) {
case NF_BR_BROUTING:
dev = xt_in(par); dev = xt_in(par);
break;
case NF_BR_PRE_ROUTING:
dev = br_port_get_rcu(xt_in(par))->br->dev;
break;
default:
dev = NULL;
break;
}
if (!dev) /* NF_BR_LOCAL_OUT */
return info->target;
if (ether_addr_equal(info->mac, dev->dev_addr)) if (ether_addr_equal(info->mac, dev->dev_addr))
skb->pkt_type = PACKET_HOST; skb->pkt_type = PACKET_HOST;
......
...@@ -296,7 +296,8 @@ ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr) ...@@ -296,7 +296,8 @@ ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr)
if (unlikely(!flag_nested(nla))) if (unlikely(!flag_nested(nla)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (nla_parse_nested_deprecated(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy, NULL)) if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla,
ipaddr_policy, NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV4))) if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV4)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
...@@ -314,7 +315,8 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr) ...@@ -314,7 +315,8 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
if (unlikely(!flag_nested(nla))) if (unlikely(!flag_nested(nla)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (nla_parse_nested_deprecated(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy, NULL)) if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla,
ipaddr_policy, NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV6))) if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV6)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
...@@ -934,7 +936,8 @@ static int ip_set_create(struct net *net, struct sock *ctnl, ...@@ -934,7 +936,8 @@ static int ip_set_create(struct net *net, struct sock *ctnl,
/* Without holding any locks, create private part. */ /* Without holding any locks, create private part. */
if (attr[IPSET_ATTR_DATA] && if (attr[IPSET_ATTR_DATA] &&
nla_parse_nested_deprecated(tb, IPSET_ATTR_CREATE_MAX, attr[IPSET_ATTR_DATA], set->type->create_policy, NULL)) { nla_parse_nested(tb, IPSET_ATTR_CREATE_MAX, attr[IPSET_ATTR_DATA],
set->type->create_policy, NULL)) {
ret = -IPSET_ERR_PROTOCOL; ret = -IPSET_ERR_PROTOCOL;
goto put_out; goto put_out;
} }
...@@ -1281,6 +1284,14 @@ dump_attrs(struct nlmsghdr *nlh) ...@@ -1281,6 +1284,14 @@ dump_attrs(struct nlmsghdr *nlh)
} }
} }
static const struct nla_policy
ip_set_dump_policy[IPSET_ATTR_CMD_MAX + 1] = {
[IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 },
[IPSET_ATTR_SETNAME] = { .type = NLA_NUL_STRING,
.len = IPSET_MAXNAMELEN - 1 },
[IPSET_ATTR_FLAGS] = { .type = NLA_U32 },
};
static int static int
dump_init(struct netlink_callback *cb, struct ip_set_net *inst) dump_init(struct netlink_callback *cb, struct ip_set_net *inst)
{ {
...@@ -1292,9 +1303,9 @@ dump_init(struct netlink_callback *cb, struct ip_set_net *inst) ...@@ -1292,9 +1303,9 @@ dump_init(struct netlink_callback *cb, struct ip_set_net *inst)
ip_set_id_t index; ip_set_id_t index;
int ret; int ret;
ret = nla_parse_deprecated(cda, IPSET_ATTR_CMD_MAX, attr, ret = nla_parse(cda, IPSET_ATTR_CMD_MAX, attr,
nlh->nlmsg_len - min_len, nlh->nlmsg_len - min_len,
ip_set_setname_policy, NULL); ip_set_dump_policy, NULL);
if (ret) if (ret)
return ret; return ret;
...@@ -1543,9 +1554,9 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, ...@@ -1543,9 +1554,9 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
memcpy(&errmsg->msg, nlh, nlh->nlmsg_len); memcpy(&errmsg->msg, nlh, nlh->nlmsg_len);
cmdattr = (void *)&errmsg->msg + min_len; cmdattr = (void *)&errmsg->msg + min_len;
ret = nla_parse_deprecated(cda, IPSET_ATTR_CMD_MAX, cmdattr, ret = nla_parse(cda, IPSET_ATTR_CMD_MAX, cmdattr,
nlh->nlmsg_len - min_len, nlh->nlmsg_len - min_len, ip_set_adt_policy,
ip_set_adt_policy, NULL); NULL);
if (ret) { if (ret) {
nlmsg_free(skb2); nlmsg_free(skb2);
...@@ -1596,7 +1607,9 @@ static int ip_set_ad(struct net *net, struct sock *ctnl, ...@@ -1596,7 +1607,9 @@ static int ip_set_ad(struct net *net, struct sock *ctnl,
use_lineno = !!attr[IPSET_ATTR_LINENO]; use_lineno = !!attr[IPSET_ATTR_LINENO];
if (attr[IPSET_ATTR_DATA]) { if (attr[IPSET_ATTR_DATA]) {
if (nla_parse_nested_deprecated(tb, IPSET_ATTR_ADT_MAX, attr[IPSET_ATTR_DATA], set->type->adt_policy, NULL)) if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX,
attr[IPSET_ATTR_DATA],
set->type->adt_policy, NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
ret = call_ad(ctnl, skb, set, tb, adt, flags, ret = call_ad(ctnl, skb, set, tb, adt, flags,
use_lineno); use_lineno);
...@@ -1606,7 +1619,8 @@ static int ip_set_ad(struct net *net, struct sock *ctnl, ...@@ -1606,7 +1619,8 @@ static int ip_set_ad(struct net *net, struct sock *ctnl,
nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) { nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) {
if (nla_type(nla) != IPSET_ATTR_DATA || if (nla_type(nla) != IPSET_ATTR_DATA ||
!flag_nested(nla) || !flag_nested(nla) ||
nla_parse_nested_deprecated(tb, IPSET_ATTR_ADT_MAX, nla, set->type->adt_policy, NULL)) nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla,
set->type->adt_policy, NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
ret = call_ad(ctnl, skb, set, tb, adt, ret = call_ad(ctnl, skb, set, tb, adt,
flags, use_lineno); flags, use_lineno);
...@@ -1655,7 +1669,8 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1655,7 +1669,8 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb,
if (!set) if (!set)
return -ENOENT; return -ENOENT;
if (nla_parse_nested_deprecated(tb, IPSET_ATTR_ADT_MAX, attr[IPSET_ATTR_DATA], set->type->adt_policy, NULL)) if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, attr[IPSET_ATTR_DATA],
set->type->adt_policy, NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
rcu_read_lock_bh(); rcu_read_lock_bh();
...@@ -1961,7 +1976,7 @@ static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = { ...@@ -1961,7 +1976,7 @@ static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
[IPSET_CMD_LIST] = { [IPSET_CMD_LIST] = {
.call = ip_set_dump, .call = ip_set_dump,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy, .policy = ip_set_dump_policy,
}, },
[IPSET_CMD_SAVE] = { [IPSET_CMD_SAVE] = {
.call = ip_set_dump, .call = ip_set_dump,
...@@ -2069,8 +2084,9 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) ...@@ -2069,8 +2084,9 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
} }
req_version->version = IPSET_PROTOCOL; req_version->version = IPSET_PROTOCOL;
ret = copy_to_user(user, req_version, if (copy_to_user(user, req_version,
sizeof(struct ip_set_req_version)); sizeof(struct ip_set_req_version)))
ret = -EFAULT;
goto done; goto done;
} }
case IP_SET_OP_GET_BYNAME: { case IP_SET_OP_GET_BYNAME: {
...@@ -2129,7 +2145,8 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) ...@@ -2129,7 +2145,8 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
} /* end of switch(op) */ } /* end of switch(op) */
copy: copy:
ret = copy_to_user(user, data, copylen); if (copy_to_user(user, data, copylen))
ret = -EFAULT;
done: done:
vfree(data); vfree(data);
......
...@@ -209,7 +209,7 @@ hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -209,7 +209,7 @@ hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb,
(skb_mac_header(skb) + ETH_HLEN) > skb->data) (skb_mac_header(skb) + ETH_HLEN) > skb->data)
return -EINVAL; return -EINVAL;
if (opt->flags & IPSET_DIM_ONE_SRC) if (opt->flags & IPSET_DIM_TWO_SRC)
ether_addr_copy(e.ether, eth_hdr(skb)->h_source); ether_addr_copy(e.ether, eth_hdr(skb)->h_source);
else else
ether_addr_copy(e.ether, eth_hdr(skb)->h_dest); ether_addr_copy(e.ether, eth_hdr(skb)->h_dest);
......
...@@ -368,6 +368,7 @@ static struct ip_set_type hash_net_type __read_mostly = { ...@@ -368,6 +368,7 @@ static struct ip_set_type hash_net_type __read_mostly = {
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 }, [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
......
...@@ -476,6 +476,7 @@ static struct ip_set_type hash_netnet_type __read_mostly = { ...@@ -476,6 +476,7 @@ static struct ip_set_type hash_netnet_type __read_mostly = {
[IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, [IPSET_ATTR_CIDR2] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 }, [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
......
...@@ -1922,6 +1922,7 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk, ...@@ -1922,6 +1922,7 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
if (nlh->nlmsg_flags & NLM_F_REPLACE) if (nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP; return -EOPNOTSUPP;
flags |= chain->flags & NFT_BASE_CHAIN;
return nf_tables_updchain(&ctx, genmask, policy, flags); return nf_tables_updchain(&ctx, genmask, policy, flags);
} }
...@@ -5143,9 +5144,6 @@ static int nf_tables_updobj(const struct nft_ctx *ctx, ...@@ -5143,9 +5144,6 @@ static int nf_tables_updobj(const struct nft_ctx *ctx,
struct nft_trans *trans; struct nft_trans *trans;
int err; int err;
if (!obj->ops->update)
return -EOPNOTSUPP;
trans = nft_trans_alloc(ctx, NFT_MSG_NEWOBJ, trans = nft_trans_alloc(ctx, NFT_MSG_NEWOBJ,
sizeof(struct nft_trans_obj)); sizeof(struct nft_trans_obj));
if (!trans) if (!trans)
...@@ -6499,7 +6497,8 @@ static void nft_obj_commit_update(struct nft_trans *trans) ...@@ -6499,7 +6497,8 @@ static void nft_obj_commit_update(struct nft_trans *trans)
obj = nft_trans_obj(trans); obj = nft_trans_obj(trans);
newobj = nft_trans_obj_newobj(trans); newobj = nft_trans_obj_newobj(trans);
obj->ops->update(obj, newobj); if (obj->ops->update)
obj->ops->update(obj, newobj);
kfree(newobj); kfree(newobj);
} }
......
...@@ -334,7 +334,8 @@ int nft_flow_rule_offload_commit(struct net *net) ...@@ -334,7 +334,8 @@ int nft_flow_rule_offload_commit(struct net *net)
switch (trans->msg_type) { switch (trans->msg_type) {
case NFT_MSG_NEWCHAIN: case NFT_MSG_NEWCHAIN:
if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)) if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD) ||
nft_trans_chain_update(trans))
continue; continue;
policy = nft_trans_chain_policy(trans); policy = nft_trans_chain_policy(trans);
......
...@@ -134,12 +134,13 @@ static int nft_bitwise_offload(struct nft_offload_ctx *ctx, ...@@ -134,12 +134,13 @@ static int nft_bitwise_offload(struct nft_offload_ctx *ctx,
const struct nft_expr *expr) const struct nft_expr *expr)
{ {
const struct nft_bitwise *priv = nft_expr_priv(expr); const struct nft_bitwise *priv = nft_expr_priv(expr);
struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
if (memcmp(&priv->xor, &zero, sizeof(priv->xor)) || if (memcmp(&priv->xor, &zero, sizeof(priv->xor)) ||
priv->sreg != priv->dreg) priv->sreg != priv->dreg || priv->len != reg->len)
return -EOPNOTSUPP; return -EOPNOTSUPP;
memcpy(&ctx->regs[priv->dreg].mask, &priv->mask, sizeof(priv->mask)); memcpy(&reg->mask, &priv->mask, sizeof(priv->mask));
return 0; return 0;
} }
......
...@@ -116,7 +116,7 @@ static int __nft_cmp_offload(struct nft_offload_ctx *ctx, ...@@ -116,7 +116,7 @@ static int __nft_cmp_offload(struct nft_offload_ctx *ctx,
u8 *mask = (u8 *)&flow->match.mask; u8 *mask = (u8 *)&flow->match.mask;
u8 *key = (u8 *)&flow->match.key; u8 *key = (u8 *)&flow->match.key;
if (priv->op != NFT_CMP_EQ) if (priv->op != NFT_CMP_EQ || reg->len != priv->len)
return -EOPNOTSUPP; return -EOPNOTSUPP;
memcpy(key + reg->offset, &priv->data, priv->len); memcpy(key + reg->offset, &priv->data, priv->len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment