Skip to content

Commit

Permalink
netfilter: ebtables: fix race condition in frame_filter_net_init()
Browse files Browse the repository at this point in the history
It is possible for ebt_in_hook to be triggered before ebt_table is assigned
resulting in a NULL-pointer dereference. Make sure hooks are
registered as the last step.

Fixes: aee12a0 ("ebtables: remove nf_hook_register usage")
Signed-off-by: Artem Savkov <[email protected]>
Signed-off-by: Pablo Neira Ayuso <[email protected]>
  • Loading branch information
sm00th authored and ummakynes committed Sep 29, 2017
1 parent 0d18779 commit e6b72ee
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 17 deletions.
7 changes: 4 additions & 3 deletions include/linux/netfilter_bridge/ebtables.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,10 @@ struct ebt_table {

#define EBT_ALIGN(s) (((s) + (__alignof__(struct _xt_align)-1)) & \
~(__alignof__(struct _xt_align)-1))
extern struct ebt_table *ebt_register_table(struct net *net,
const struct ebt_table *table,
const struct nf_hook_ops *);
extern int ebt_register_table(struct net *net,
const struct ebt_table *table,
const struct nf_hook_ops *ops,
struct ebt_table **res);
extern void ebt_unregister_table(struct net *net, struct ebt_table *table,
const struct nf_hook_ops *);
extern unsigned int ebt_do_table(struct sk_buff *skb,
Expand Down
4 changes: 2 additions & 2 deletions net/bridge/netfilter/ebtable_broute.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ static int ebt_broute(struct sk_buff *skb)

static int __net_init broute_net_init(struct net *net)
{
net->xt.broute_table = ebt_register_table(net, &broute_table, NULL);
return PTR_ERR_OR_ZERO(net->xt.broute_table);
return ebt_register_table(net, &broute_table, NULL,
&net->xt.broute_table);
}

static void __net_exit broute_net_exit(struct net *net)
Expand Down
4 changes: 2 additions & 2 deletions net/bridge/netfilter/ebtable_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ static const struct nf_hook_ops ebt_ops_filter[] = {

static int __net_init frame_filter_net_init(struct net *net)
{
net->xt.frame_filter = ebt_register_table(net, &frame_filter, ebt_ops_filter);
return PTR_ERR_OR_ZERO(net->xt.frame_filter);
return ebt_register_table(net, &frame_filter, ebt_ops_filter,
&net->xt.frame_filter);
}

static void __net_exit frame_filter_net_exit(struct net *net)
Expand Down
4 changes: 2 additions & 2 deletions net/bridge/netfilter/ebtable_nat.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ static const struct nf_hook_ops ebt_ops_nat[] = {

static int __net_init frame_nat_net_init(struct net *net)
{
net->xt.frame_nat = ebt_register_table(net, &frame_nat, ebt_ops_nat);
return PTR_ERR_OR_ZERO(net->xt.frame_nat);
return ebt_register_table(net, &frame_nat, ebt_ops_nat,
&net->xt.frame_nat);
}

static void __net_exit frame_nat_net_exit(struct net *net)
Expand Down
17 changes: 9 additions & 8 deletions net/bridge/netfilter/ebtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -1169,9 +1169,8 @@ static void __ebt_unregister_table(struct net *net, struct ebt_table *table)
kfree(table);
}

struct ebt_table *
ebt_register_table(struct net *net, const struct ebt_table *input_table,
const struct nf_hook_ops *ops)
int ebt_register_table(struct net *net, const struct ebt_table *input_table,
const struct nf_hook_ops *ops, struct ebt_table **res)
{
struct ebt_table_info *newinfo;
struct ebt_table *t, *table;
Expand All @@ -1183,7 +1182,7 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table,
repl->entries == NULL || repl->entries_size == 0 ||
repl->counters != NULL || input_table->private != NULL) {
BUGPRINT("Bad table data for ebt_register_table!!!\n");
return ERR_PTR(-EINVAL);
return -EINVAL;
}

/* Don't add one table to multiple lists. */
Expand Down Expand Up @@ -1252,16 +1251,18 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table,
list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
mutex_unlock(&ebt_mutex);

WRITE_ONCE(*res, table);

if (!ops)
return table;
return 0;

ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
if (ret) {
__ebt_unregister_table(net, table);
return ERR_PTR(ret);
*res = NULL;
}

return table;
return ret;
free_unlock:
mutex_unlock(&ebt_mutex);
free_chainstack:
Expand All @@ -1276,7 +1277,7 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table,
free_table:
kfree(table);
out:
return ERR_PTR(ret);
return ret;
}

void ebt_unregister_table(struct net *net, struct ebt_table *table,
Expand Down

0 comments on commit e6b72ee

Please sign in to comment.