Skip to content

Commit ccb39c6

Browse files
committed
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) Fix NAT IPv6 offload in the flowtable. 2) icmpv6 is printed as unknown in /proc/net/nf_conntrack. 3) Use div64_u64() in nft_limit, from Eric Dumazet. 4) Use pre_exit to unregister ebtables and arptables hooks, from Florian Westphal. 5) Fix out-of-bound memset in x_tables compat match/target, also from Florian. 6) Clone set elements expression to ensure proper initialization. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents f33b0e1 + 4d8f906 commit ccb39c6

File tree

15 files changed

+118
-38
lines changed

15 files changed

+118
-38
lines changed

include/linux/netfilter_arp/arp_tables.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ extern void *arpt_alloc_initial_table(const struct xt_table *);
5252
int arpt_register_table(struct net *net, const struct xt_table *table,
5353
const struct arpt_replace *repl,
5454
const struct nf_hook_ops *ops, struct xt_table **res);
55-
void arpt_unregister_table(struct net *net, struct xt_table *table,
56-
const struct nf_hook_ops *ops);
55+
void arpt_unregister_table(struct net *net, struct xt_table *table);
56+
void arpt_unregister_table_pre_exit(struct net *net, struct xt_table *table,
57+
const struct nf_hook_ops *ops);
5758
extern unsigned int arpt_do_table(struct sk_buff *skb,
5859
const struct nf_hook_state *state,
5960
struct xt_table *table);

include/linux/netfilter_bridge/ebtables.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,9 @@ extern int ebt_register_table(struct net *net,
110110
const struct ebt_table *table,
111111
const struct nf_hook_ops *ops,
112112
struct ebt_table **res);
113-
extern void ebt_unregister_table(struct net *net, struct ebt_table *table,
114-
const struct nf_hook_ops *);
113+
extern void ebt_unregister_table(struct net *net, struct ebt_table *table);
114+
void ebt_unregister_table_pre_exit(struct net *net, const char *tablename,
115+
const struct nf_hook_ops *ops);
115116
extern unsigned int ebt_do_table(struct sk_buff *skb,
116117
const struct nf_hook_state *state,
117118
struct ebt_table *table);

net/bridge/netfilter/ebtable_broute.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,20 @@ static int __net_init broute_net_init(struct net *net)
105105
&net->xt.broute_table);
106106
}
107107

108+
static void __net_exit broute_net_pre_exit(struct net *net)
109+
{
110+
ebt_unregister_table_pre_exit(net, "broute", &ebt_ops_broute);
111+
}
112+
108113
static void __net_exit broute_net_exit(struct net *net)
109114
{
110-
ebt_unregister_table(net, net->xt.broute_table, &ebt_ops_broute);
115+
ebt_unregister_table(net, net->xt.broute_table);
111116
}
112117

113118
static struct pernet_operations broute_net_ops = {
114119
.init = broute_net_init,
115120
.exit = broute_net_exit,
121+
.pre_exit = broute_net_pre_exit,
116122
};
117123

118124
static int __init ebtable_broute_init(void)

net/bridge/netfilter/ebtable_filter.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,20 @@ static int __net_init frame_filter_net_init(struct net *net)
9999
&net->xt.frame_filter);
100100
}
101101

102+
static void __net_exit frame_filter_net_pre_exit(struct net *net)
103+
{
104+
ebt_unregister_table_pre_exit(net, "filter", ebt_ops_filter);
105+
}
106+
102107
static void __net_exit frame_filter_net_exit(struct net *net)
103108
{
104-
ebt_unregister_table(net, net->xt.frame_filter, ebt_ops_filter);
109+
ebt_unregister_table(net, net->xt.frame_filter);
105110
}
106111

107112
static struct pernet_operations frame_filter_net_ops = {
108113
.init = frame_filter_net_init,
109114
.exit = frame_filter_net_exit,
115+
.pre_exit = frame_filter_net_pre_exit,
110116
};
111117

112118
static int __init ebtable_filter_init(void)

net/bridge/netfilter/ebtable_nat.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,20 @@ static int __net_init frame_nat_net_init(struct net *net)
9999
&net->xt.frame_nat);
100100
}
101101

102+
static void __net_exit frame_nat_net_pre_exit(struct net *net)
103+
{
104+
ebt_unregister_table_pre_exit(net, "nat", ebt_ops_nat);
105+
}
106+
102107
static void __net_exit frame_nat_net_exit(struct net *net)
103108
{
104-
ebt_unregister_table(net, net->xt.frame_nat, ebt_ops_nat);
109+
ebt_unregister_table(net, net->xt.frame_nat);
105110
}
106111

107112
static struct pernet_operations frame_nat_net_ops = {
108113
.init = frame_nat_net_init,
109114
.exit = frame_nat_net_exit,
115+
.pre_exit = frame_nat_net_pre_exit,
110116
};
111117

112118
static int __init ebtable_nat_init(void)

net/bridge/netfilter/ebtables.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,10 +1232,34 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
12321232
return ret;
12331233
}
12341234

1235-
void ebt_unregister_table(struct net *net, struct ebt_table *table,
1236-
const struct nf_hook_ops *ops)
1235+
static struct ebt_table *__ebt_find_table(struct net *net, const char *name)
1236+
{
1237+
struct ebt_table *t;
1238+
1239+
mutex_lock(&ebt_mutex);
1240+
1241+
list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
1242+
if (strcmp(t->name, name) == 0) {
1243+
mutex_unlock(&ebt_mutex);
1244+
return t;
1245+
}
1246+
}
1247+
1248+
mutex_unlock(&ebt_mutex);
1249+
return NULL;
1250+
}
1251+
1252+
void ebt_unregister_table_pre_exit(struct net *net, const char *name, const struct nf_hook_ops *ops)
1253+
{
1254+
struct ebt_table *table = __ebt_find_table(net, name);
1255+
1256+
if (table)
1257+
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
1258+
}
1259+
EXPORT_SYMBOL(ebt_unregister_table_pre_exit);
1260+
1261+
void ebt_unregister_table(struct net *net, struct ebt_table *table)
12371262
{
1238-
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
12391263
__ebt_unregister_table(net, table);
12401264
}
12411265

net/ipv4/netfilter/arp_tables.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,8 @@ static int translate_compat_table(struct net *net,
11931193
if (!newinfo)
11941194
goto out_unlock;
11951195

1196+
memset(newinfo->entries, 0, size);
1197+
11961198
newinfo->number = compatr->num_entries;
11971199
for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
11981200
newinfo->hook_entry[i] = compatr->hook_entry[i];
@@ -1539,10 +1541,15 @@ int arpt_register_table(struct net *net,
15391541
return ret;
15401542
}
15411543

1542-
void arpt_unregister_table(struct net *net, struct xt_table *table,
1543-
const struct nf_hook_ops *ops)
1544+
void arpt_unregister_table_pre_exit(struct net *net, struct xt_table *table,
1545+
const struct nf_hook_ops *ops)
15441546
{
15451547
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
1548+
}
1549+
EXPORT_SYMBOL(arpt_unregister_table_pre_exit);
1550+
1551+
void arpt_unregister_table(struct net *net, struct xt_table *table)
1552+
{
15461553
__arpt_unregister_table(net, table);
15471554
}
15481555

net/ipv4/netfilter/arptable_filter.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,24 @@ static int __net_init arptable_filter_table_init(struct net *net)
5656
return err;
5757
}
5858

59+
static void __net_exit arptable_filter_net_pre_exit(struct net *net)
60+
{
61+
if (net->ipv4.arptable_filter)
62+
arpt_unregister_table_pre_exit(net, net->ipv4.arptable_filter,
63+
arpfilter_ops);
64+
}
65+
5966
static void __net_exit arptable_filter_net_exit(struct net *net)
6067
{
6168
if (!net->ipv4.arptable_filter)
6269
return;
63-
arpt_unregister_table(net, net->ipv4.arptable_filter, arpfilter_ops);
70+
arpt_unregister_table(net, net->ipv4.arptable_filter);
6471
net->ipv4.arptable_filter = NULL;
6572
}
6673

6774
static struct pernet_operations arptable_filter_net_ops = {
6875
.exit = arptable_filter_net_exit,
76+
.pre_exit = arptable_filter_net_pre_exit,
6977
};
7078

7179
static int __init arptable_filter_init(void)

net/ipv4/netfilter/ip_tables.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,6 +1428,8 @@ translate_compat_table(struct net *net,
14281428
if (!newinfo)
14291429
goto out_unlock;
14301430

1431+
memset(newinfo->entries, 0, size);
1432+
14311433
newinfo->number = compatr->num_entries;
14321434
for (i = 0; i < NF_INET_NUMHOOKS; i++) {
14331435
newinfo->hook_entry[i] = compatr->hook_entry[i];

net/ipv6/netfilter/ip6_tables.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,8 @@ translate_compat_table(struct net *net,
14431443
if (!newinfo)
14441444
goto out_unlock;
14451445

1446+
memset(newinfo->entries, 0, size);
1447+
14461448
newinfo->number = compatr->num_entries;
14471449
for (i = 0; i < NF_INET_NUMHOOKS; i++) {
14481450
newinfo->hook_entry[i] = compatr->hook_entry[i];

net/netfilter/nf_conntrack_standalone.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ static const char* l4proto_name(u16 proto)
266266
case IPPROTO_GRE: return "gre";
267267
case IPPROTO_SCTP: return "sctp";
268268
case IPPROTO_UDPLITE: return "udplite";
269+
case IPPROTO_ICMPV6: return "icmpv6";
269270
}
270271

271272
return "unknown";

net/netfilter/nf_flow_table_offload.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,12 +305,12 @@ static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
305305
const __be32 *addr, const __be32 *mask)
306306
{
307307
struct flow_action_entry *entry;
308-
int i;
308+
int i, j;
309309

310-
for (i = 0; i < sizeof(struct in6_addr) / sizeof(u32); i += sizeof(u32)) {
310+
for (i = 0, j = 0; i < sizeof(struct in6_addr) / sizeof(u32); i += sizeof(u32), j++) {
311311
entry = flow_action_entry_next(flow_rule);
312312
flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP6,
313-
offset + i, &addr[i], mask);
313+
offset + i, &addr[j], mask);
314314
}
315315
}
316316

net/netfilter/nf_tables_api.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5295,16 +5295,35 @@ int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
52955295
return -ENOMEM;
52965296
}
52975297

5298-
static void nft_set_elem_expr_setup(const struct nft_set_ext *ext, int i,
5299-
struct nft_expr *expr_array[])
5298+
static int nft_set_elem_expr_setup(struct nft_ctx *ctx,
5299+
const struct nft_set_ext *ext,
5300+
struct nft_expr *expr_array[],
5301+
u32 num_exprs)
53005302
{
53015303
struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
5302-
struct nft_expr *expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
5304+
struct nft_expr *expr;
5305+
int i, err;
5306+
5307+
for (i = 0; i < num_exprs; i++) {
5308+
expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
5309+
err = nft_expr_clone(expr, expr_array[i]);
5310+
if (err < 0)
5311+
goto err_elem_expr_setup;
5312+
5313+
elem_expr->size += expr_array[i]->ops->size;
5314+
nft_expr_destroy(ctx, expr_array[i]);
5315+
expr_array[i] = NULL;
5316+
}
5317+
5318+
return 0;
5319+
5320+
err_elem_expr_setup:
5321+
for (; i < num_exprs; i++) {
5322+
nft_expr_destroy(ctx, expr_array[i]);
5323+
expr_array[i] = NULL;
5324+
}
53035325

5304-
memcpy(expr, expr_array[i], expr_array[i]->ops->size);
5305-
elem_expr->size += expr_array[i]->ops->size;
5306-
kfree(expr_array[i]);
5307-
expr_array[i] = NULL;
5326+
return -ENOMEM;
53085327
}
53095328

53105329
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
@@ -5556,12 +5575,15 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
55565575
*nft_set_ext_obj(ext) = obj;
55575576
obj->use++;
55585577
}
5559-
for (i = 0; i < num_exprs; i++)
5560-
nft_set_elem_expr_setup(ext, i, expr_array);
5578+
err = nft_set_elem_expr_setup(ctx, ext, expr_array, num_exprs);
5579+
if (err < 0)
5580+
goto err_elem_expr;
55615581

55625582
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
5563-
if (trans == NULL)
5564-
goto err_trans;
5583+
if (trans == NULL) {
5584+
err = -ENOMEM;
5585+
goto err_elem_expr;
5586+
}
55655587

55665588
ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
55675589
err = set->ops->insert(ctx->net, set, &elem, &ext2);
@@ -5605,7 +5627,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
56055627
set->ops->remove(ctx->net, set, &elem);
56065628
err_element_clash:
56075629
kfree(trans);
5608-
err_trans:
5630+
err_elem_expr:
56095631
if (obj)
56105632
obj->use--;
56115633

net/netfilter/nft_limit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,13 @@ static int nft_limit_init(struct nft_limit *limit,
7676
return -EOVERFLOW;
7777

7878
if (pkts) {
79-
tokens = div_u64(limit->nsecs, limit->rate) * limit->burst;
79+
tokens = div64_u64(limit->nsecs, limit->rate) * limit->burst;
8080
} else {
8181
/* The token bucket size limits the number of tokens can be
8282
* accumulated. tokens_max specifies the bucket size.
8383
* tokens_max = unit * (rate + burst) / rate.
8484
*/
85-
tokens = div_u64(limit->nsecs * (limit->rate + limit->burst),
85+
tokens = div64_u64(limit->nsecs * (limit->rate + limit->burst),
8686
limit->rate);
8787
}
8888

net/netfilter/x_tables.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
733733
{
734734
const struct xt_match *match = m->u.kernel.match;
735735
struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
736-
int pad, off = xt_compat_match_offset(match);
736+
int off = xt_compat_match_offset(match);
737737
u_int16_t msize = cm->u.user.match_size;
738738
char name[sizeof(m->u.user.name)];
739739

@@ -743,9 +743,6 @@ void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
743743
match->compat_from_user(m->data, cm->data);
744744
else
745745
memcpy(m->data, cm->data, msize - sizeof(*cm));
746-
pad = XT_ALIGN(match->matchsize) - match->matchsize;
747-
if (pad > 0)
748-
memset(m->data + match->matchsize, 0, pad);
749746

750747
msize += off;
751748
m->u.user.match_size = msize;
@@ -1116,7 +1113,7 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
11161113
{
11171114
const struct xt_target *target = t->u.kernel.target;
11181115
struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
1119-
int pad, off = xt_compat_target_offset(target);
1116+
int off = xt_compat_target_offset(target);
11201117
u_int16_t tsize = ct->u.user.target_size;
11211118
char name[sizeof(t->u.user.name)];
11221119

@@ -1126,9 +1123,6 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
11261123
target->compat_from_user(t->data, ct->data);
11271124
else
11281125
memcpy(t->data, ct->data, tsize - sizeof(*ct));
1129-
pad = XT_ALIGN(target->targetsize) - target->targetsize;
1130-
if (pad > 0)
1131-
memset(t->data + target->targetsize, 0, pad);
11321126

11331127
tsize += off;
11341128
t->u.user.target_size = tsize;

0 commit comments

Comments
 (0)