--- x/net/bridge/netfilter/ebtables.c +++ y/net/bridge/netfilter/ebtables.c @@ -1158,14 +1158,47 @@ free_newinfo: return ret; } +#define __EBT_ENTRY_ITERATE(entries, size, fn, args...) \ +({ \ + unsigned int __i; \ + int __ret = 0; \ + struct ebt_entry *__entry; \ + \ + for (__i = 0; __i + sizeof(struct ebt_entries) < (size);) { \ + __entry = (void *)(entries) + __i; \ + __ret = fn(__entry , ## args); \ + if (__ret != 0) \ + break; \ + if (__entry->bitmask != 0) \ + __i += __entry->next_offset; \ + else \ + __i += sizeof(struct ebt_entries); \ + } \ + if (__ret == 0) { \ + if (__i != (size)) \ + __ret = -EINVAL; \ + } \ + __ret; \ +}) + static void __ebt_unregister_table(struct net *net, struct ebt_table *table) { + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + struct ebt_table *t = NULL; + mutex_lock(&ebt_mutex); - list_del(&table->list); + list_for_each_entry(t, &ebt_net->tables, list) { + if (t == table) { + list_del(&t->list); + break; + } + } mutex_unlock(&ebt_mutex); + if (t != table) + return; audit_log_nfcfg(table->name, AF_BRIDGE, table->private->nentries, AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); - EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, + __EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, ebt_cleanup_entry, net, NULL); if (table->private->nentries) module_put(table->me);