Commit 513acc5b 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/IPVS fixes for net

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

1) Null pointer dereference when dumping conntrack helper configuration,
   from Taehee Yoo.

2) Missing sanitization in ebtables extension name through compat,
   from Paolo Abeni.

3) Broken fetch of tracing value, from Taehee Yoo.

4) Incorrect arithmetics in packet ratelimiting.

5) Buffer overflow in IPVS sync daemon, from Julian Anastasov.

6) Wrong argument to nla_strlcpy() in nfnetlink_{acct,cthelper},
   from Eric Dumazet.

7) Fix splat in nft_update_chain_stats().

8) Null pointer dereference from object netlink dump path, from
   Taehee Yoo.

9) Missing static_branch_inc() when enabling counters in existing
   chain, from Taehee Yoo.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bc2dbc54 bbb8c61f
...@@ -1954,7 +1954,8 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, ...@@ -1954,7 +1954,8 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
int off, pad = 0; int off, pad = 0;
unsigned int size_kern, match_size = mwt->match_size; unsigned int size_kern, match_size = mwt->match_size;
strlcpy(name, mwt->u.name, sizeof(name)); if (strscpy(name, mwt->u.name, sizeof(name)) < 0)
return -EINVAL;
if (state->buf_kern_start) if (state->buf_kern_start)
dst = state->buf_kern_start + state->buf_kern_offset; dst = state->buf_kern_start + state->buf_kern_offset;
......
...@@ -2381,8 +2381,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ...@@ -2381,8 +2381,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
struct ipvs_sync_daemon_cfg cfg; struct ipvs_sync_daemon_cfg cfg;
memset(&cfg, 0, sizeof(cfg)); memset(&cfg, 0, sizeof(cfg));
strlcpy(cfg.mcast_ifn, dm->mcast_ifn, ret = -EINVAL;
sizeof(cfg.mcast_ifn)); if (strscpy(cfg.mcast_ifn, dm->mcast_ifn,
sizeof(cfg.mcast_ifn)) <= 0)
goto out_dec;
cfg.syncid = dm->syncid; cfg.syncid = dm->syncid;
ret = start_sync_thread(ipvs, &cfg, dm->state); ret = start_sync_thread(ipvs, &cfg, dm->state);
} else { } else {
...@@ -2420,12 +2422,19 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ...@@ -2420,12 +2422,19 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
} }
} }
if ((cmd == IP_VS_SO_SET_ADD || cmd == IP_VS_SO_SET_EDIT) &&
strnlen(usvc.sched_name, IP_VS_SCHEDNAME_MAXLEN) ==
IP_VS_SCHEDNAME_MAXLEN) {
ret = -EINVAL;
goto out_unlock;
}
/* Check for valid protocol: TCP or UDP or SCTP, even for fwmark!=0 */ /* Check for valid protocol: TCP or UDP or SCTP, even for fwmark!=0 */
if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP && if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP &&
usvc.protocol != IPPROTO_SCTP) { usvc.protocol != IPPROTO_SCTP) {
pr_err("set_ctl: invalid protocol: %d %pI4:%d %s\n", pr_err("set_ctl: invalid protocol: %d %pI4:%d\n",
usvc.protocol, &usvc.addr.ip, usvc.protocol, &usvc.addr.ip,
ntohs(usvc.port), usvc.sched_name); ntohs(usvc.port));
ret = -EFAULT; ret = -EFAULT;
goto out_unlock; goto out_unlock;
} }
...@@ -2847,7 +2856,7 @@ static const struct nla_policy ip_vs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] = { ...@@ -2847,7 +2856,7 @@ static const struct nla_policy ip_vs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] = {
static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = { static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = {
[IPVS_DAEMON_ATTR_STATE] = { .type = NLA_U32 }, [IPVS_DAEMON_ATTR_STATE] = { .type = NLA_U32 },
[IPVS_DAEMON_ATTR_MCAST_IFN] = { .type = NLA_NUL_STRING, [IPVS_DAEMON_ATTR_MCAST_IFN] = { .type = NLA_NUL_STRING,
.len = IP_VS_IFNAME_MAXLEN }, .len = IP_VS_IFNAME_MAXLEN - 1 },
[IPVS_DAEMON_ATTR_SYNC_ID] = { .type = NLA_U32 }, [IPVS_DAEMON_ATTR_SYNC_ID] = { .type = NLA_U32 },
[IPVS_DAEMON_ATTR_SYNC_MAXLEN] = { .type = NLA_U16 }, [IPVS_DAEMON_ATTR_SYNC_MAXLEN] = { .type = NLA_U16 },
[IPVS_DAEMON_ATTR_MCAST_GROUP] = { .type = NLA_U32 }, [IPVS_DAEMON_ATTR_MCAST_GROUP] = { .type = NLA_U32 },
...@@ -2865,7 +2874,7 @@ static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = { ...@@ -2865,7 +2874,7 @@ static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = {
[IPVS_SVC_ATTR_PORT] = { .type = NLA_U16 }, [IPVS_SVC_ATTR_PORT] = { .type = NLA_U16 },
[IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 }, [IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 },
[IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_NUL_STRING, [IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_NUL_STRING,
.len = IP_VS_SCHEDNAME_MAXLEN }, .len = IP_VS_SCHEDNAME_MAXLEN - 1 },
[IPVS_SVC_ATTR_PE_NAME] = { .type = NLA_NUL_STRING, [IPVS_SVC_ATTR_PE_NAME] = { .type = NLA_NUL_STRING,
.len = IP_VS_PENAME_MAXLEN }, .len = IP_VS_PENAME_MAXLEN },
[IPVS_SVC_ATTR_FLAGS] = { .type = NLA_BINARY, [IPVS_SVC_ATTR_FLAGS] = { .type = NLA_BINARY,
......
...@@ -1298,8 +1298,10 @@ static void nft_chain_stats_replace(struct nft_base_chain *chain, ...@@ -1298,8 +1298,10 @@ static void nft_chain_stats_replace(struct nft_base_chain *chain,
rcu_assign_pointer(chain->stats, newstats); rcu_assign_pointer(chain->stats, newstats);
synchronize_rcu(); synchronize_rcu();
free_percpu(oldstats); free_percpu(oldstats);
} else } else {
rcu_assign_pointer(chain->stats, newstats); rcu_assign_pointer(chain->stats, newstats);
static_branch_inc(&nft_counters_enabled);
}
} }
static void nf_tables_chain_destroy(struct nft_ctx *ctx) static void nf_tables_chain_destroy(struct nft_ctx *ctx)
...@@ -4706,7 +4708,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -4706,7 +4708,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
if (idx > s_idx) if (idx > s_idx)
memset(&cb->args[1], 0, memset(&cb->args[1], 0,
sizeof(cb->args) - sizeof(cb->args[0])); sizeof(cb->args) - sizeof(cb->args[0]));
if (filter && filter->table[0] && if (filter && filter->table &&
strcmp(filter->table, table->name)) strcmp(filter->table, table->name))
goto cont; goto cont;
if (filter && if (filter &&
...@@ -5380,7 +5382,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb, ...@@ -5380,7 +5382,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb,
if (idx > s_idx) if (idx > s_idx)
memset(&cb->args[1], 0, memset(&cb->args[1], 0,
sizeof(cb->args) - sizeof(cb->args[0])); sizeof(cb->args) - sizeof(cb->args[0]));
if (filter && filter->table[0] && if (filter && filter->table &&
strcmp(filter->table, table->name)) strcmp(filter->table, table->name))
goto cont; goto cont;
......
...@@ -126,15 +126,15 @@ static noinline void nft_update_chain_stats(const struct nft_chain *chain, ...@@ -126,15 +126,15 @@ static noinline void nft_update_chain_stats(const struct nft_chain *chain,
if (!base_chain->stats) if (!base_chain->stats)
return; return;
local_bh_disable();
stats = this_cpu_ptr(rcu_dereference(base_chain->stats)); stats = this_cpu_ptr(rcu_dereference(base_chain->stats));
if (stats) { if (stats) {
local_bh_disable();
u64_stats_update_begin(&stats->syncp); u64_stats_update_begin(&stats->syncp);
stats->pkts++; stats->pkts++;
stats->bytes += pkt->skb->len; stats->bytes += pkt->skb->len;
u64_stats_update_end(&stats->syncp); u64_stats_update_end(&stats->syncp);
local_bh_enable();
} }
local_bh_enable();
} }
struct nft_jumpstack { struct nft_jumpstack {
......
...@@ -115,7 +115,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl, ...@@ -115,7 +115,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl,
nfacct->flags = flags; nfacct->flags = flags;
} }
nla_strlcpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX); nla_strlcpy(nfacct->name, tb[NFACCT_NAME], NFACCT_NAME_MAX);
if (tb[NFACCT_BYTES]) { if (tb[NFACCT_BYTES]) {
atomic64_set(&nfacct->bytes, atomic64_set(&nfacct->bytes,
......
...@@ -150,7 +150,7 @@ nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy, ...@@ -150,7 +150,7 @@ nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
return -EINVAL; return -EINVAL;
nla_strlcpy(expect_policy->name, nla_strlcpy(expect_policy->name,
nla_data(tb[NFCTH_POLICY_NAME]), NF_CT_HELPER_NAME_LEN); tb[NFCTH_POLICY_NAME], NF_CT_HELPER_NAME_LEN);
expect_policy->max_expected = expect_policy->max_expected =
ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX])); ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT) if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
...@@ -235,7 +235,7 @@ nfnl_cthelper_create(const struct nlattr * const tb[], ...@@ -235,7 +235,7 @@ nfnl_cthelper_create(const struct nlattr * const tb[],
goto err1; goto err1;
nla_strlcpy(helper->name, nla_strlcpy(helper->name,
nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN); tb[NFCTH_NAME], NF_CT_HELPER_NAME_LEN);
size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN])); size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
if (size > FIELD_SIZEOF(struct nf_conn_help, data)) { if (size > FIELD_SIZEOF(struct nf_conn_help, data)) {
ret = -ENOMEM; ret = -ENOMEM;
......
...@@ -880,22 +880,26 @@ static int nft_ct_helper_obj_dump(struct sk_buff *skb, ...@@ -880,22 +880,26 @@ static int nft_ct_helper_obj_dump(struct sk_buff *skb,
struct nft_object *obj, bool reset) struct nft_object *obj, bool reset)
{ {
const struct nft_ct_helper_obj *priv = nft_obj_data(obj); const struct nft_ct_helper_obj *priv = nft_obj_data(obj);
const struct nf_conntrack_helper *helper = priv->helper4; const struct nf_conntrack_helper *helper;
u16 family; u16 family;
if (priv->helper4 && priv->helper6) {
family = NFPROTO_INET;
helper = priv->helper4;
} else if (priv->helper6) {
family = NFPROTO_IPV6;
helper = priv->helper6;
} else {
family = NFPROTO_IPV4;
helper = priv->helper4;
}
if (nla_put_string(skb, NFTA_CT_HELPER_NAME, helper->name)) if (nla_put_string(skb, NFTA_CT_HELPER_NAME, helper->name))
return -1; return -1;
if (nla_put_u8(skb, NFTA_CT_HELPER_L4PROTO, priv->l4proto)) if (nla_put_u8(skb, NFTA_CT_HELPER_L4PROTO, priv->l4proto))
return -1; return -1;
if (priv->helper4 && priv->helper6)
family = NFPROTO_INET;
else if (priv->helper6)
family = NFPROTO_IPV6;
else
family = NFPROTO_IPV4;
if (nla_put_be16(skb, NFTA_CT_HELPER_L3PROTO, htons(family))) if (nla_put_be16(skb, NFTA_CT_HELPER_L3PROTO, htons(family)))
return -1; return -1;
......
...@@ -51,10 +51,13 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost) ...@@ -51,10 +51,13 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
return !limit->invert; return !limit->invert;
} }
/* Use same default as in iptables. */
#define NFT_LIMIT_PKT_BURST_DEFAULT 5
static int nft_limit_init(struct nft_limit *limit, static int nft_limit_init(struct nft_limit *limit,
const struct nlattr * const tb[]) const struct nlattr * const tb[], bool pkts)
{ {
u64 unit; u64 unit, tokens;
if (tb[NFTA_LIMIT_RATE] == NULL || if (tb[NFTA_LIMIT_RATE] == NULL ||
tb[NFTA_LIMIT_UNIT] == NULL) tb[NFTA_LIMIT_UNIT] == NULL)
...@@ -68,18 +71,25 @@ static int nft_limit_init(struct nft_limit *limit, ...@@ -68,18 +71,25 @@ static int nft_limit_init(struct nft_limit *limit,
if (tb[NFTA_LIMIT_BURST]) if (tb[NFTA_LIMIT_BURST])
limit->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST])); limit->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST]));
else
limit->burst = 0; if (pkts && limit->burst == 0)
limit->burst = NFT_LIMIT_PKT_BURST_DEFAULT;
if (limit->rate + limit->burst < limit->rate) if (limit->rate + limit->burst < limit->rate)
return -EOVERFLOW; return -EOVERFLOW;
/* The token bucket size limits the number of tokens can be if (pkts) {
* accumulated. tokens_max specifies the bucket size. tokens = div_u64(limit->nsecs, limit->rate) * limit->burst;
* tokens_max = unit * (rate + burst) / rate. } else {
*/ /* The token bucket size limits the number of tokens can be
limit->tokens = div_u64(limit->nsecs * (limit->rate + limit->burst), * accumulated. tokens_max specifies the bucket size.
limit->rate); * tokens_max = unit * (rate + burst) / rate.
*/
tokens = div_u64(limit->nsecs * (limit->rate + limit->burst),
limit->rate);
}
limit->tokens = tokens;
limit->tokens_max = limit->tokens; limit->tokens_max = limit->tokens;
if (tb[NFTA_LIMIT_FLAGS]) { if (tb[NFTA_LIMIT_FLAGS]) {
...@@ -144,7 +154,7 @@ static int nft_limit_pkts_init(const struct nft_ctx *ctx, ...@@ -144,7 +154,7 @@ static int nft_limit_pkts_init(const struct nft_ctx *ctx,
struct nft_limit_pkts *priv = nft_expr_priv(expr); struct nft_limit_pkts *priv = nft_expr_priv(expr);
int err; int err;
err = nft_limit_init(&priv->limit, tb); err = nft_limit_init(&priv->limit, tb, true);
if (err < 0) if (err < 0)
return err; return err;
...@@ -185,7 +195,7 @@ static int nft_limit_bytes_init(const struct nft_ctx *ctx, ...@@ -185,7 +195,7 @@ static int nft_limit_bytes_init(const struct nft_ctx *ctx,
{ {
struct nft_limit *priv = nft_expr_priv(expr); struct nft_limit *priv = nft_expr_priv(expr);
return nft_limit_init(priv, tb); return nft_limit_init(priv, tb, false);
} }
static int nft_limit_bytes_dump(struct sk_buff *skb, static int nft_limit_bytes_dump(struct sk_buff *skb,
...@@ -246,7 +256,7 @@ static int nft_limit_obj_pkts_init(const struct nft_ctx *ctx, ...@@ -246,7 +256,7 @@ static int nft_limit_obj_pkts_init(const struct nft_ctx *ctx,
struct nft_limit_pkts *priv = nft_obj_data(obj); struct nft_limit_pkts *priv = nft_obj_data(obj);
int err; int err;
err = nft_limit_init(&priv->limit, tb); err = nft_limit_init(&priv->limit, tb, true);
if (err < 0) if (err < 0)
return err; return err;
...@@ -289,7 +299,7 @@ static int nft_limit_obj_bytes_init(const struct nft_ctx *ctx, ...@@ -289,7 +299,7 @@ static int nft_limit_obj_bytes_init(const struct nft_ctx *ctx,
{ {
struct nft_limit *priv = nft_obj_data(obj); struct nft_limit *priv = nft_obj_data(obj);
return nft_limit_init(priv, tb); return nft_limit_init(priv, tb, false);
} }
static int nft_limit_obj_bytes_dump(struct sk_buff *skb, static int nft_limit_obj_bytes_dump(struct sk_buff *skb,
......
...@@ -234,7 +234,7 @@ void nft_meta_set_eval(const struct nft_expr *expr, ...@@ -234,7 +234,7 @@ void nft_meta_set_eval(const struct nft_expr *expr,
struct sk_buff *skb = pkt->skb; struct sk_buff *skb = pkt->skb;
u32 *sreg = &regs->data[meta->sreg]; u32 *sreg = &regs->data[meta->sreg];
u32 value = *sreg; u32 value = *sreg;
u8 pkt_type; u8 value8;
switch (meta->key) { switch (meta->key) {
case NFT_META_MARK: case NFT_META_MARK:
...@@ -244,15 +244,17 @@ void nft_meta_set_eval(const struct nft_expr *expr, ...@@ -244,15 +244,17 @@ void nft_meta_set_eval(const struct nft_expr *expr,
skb->priority = value; skb->priority = value;
break; break;
case NFT_META_PKTTYPE: case NFT_META_PKTTYPE:
pkt_type = nft_reg_load8(sreg); value8 = nft_reg_load8(sreg);
if (skb->pkt_type != pkt_type && if (skb->pkt_type != value8 &&
skb_pkt_type_ok(pkt_type) && skb_pkt_type_ok(value8) &&
skb_pkt_type_ok(skb->pkt_type)) skb_pkt_type_ok(skb->pkt_type))
skb->pkt_type = pkt_type; skb->pkt_type = value8;
break; break;
case NFT_META_NFTRACE: case NFT_META_NFTRACE:
skb->nf_trace = !!value; value8 = nft_reg_load8(sreg);
skb->nf_trace = !!value8;
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
......
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