aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2016-02-25 04:08:36 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2016-03-02 14:05:24 -0500
commitb9e69e127397187b70c813a4397cce7afb5e8cb1 (patch)
tree1a5a4769ef5ba3087fa15579d15cdd3aa3c3dabd /net/netfilter
parenta67dd266adf42a24df31380e9da78390bb4d65ef (diff)
netfilter: xtables: don't hook tables by default
delay hook registration until the table is being requested inside a namespace. Historically, a particular table (iptables mangle, ip6tables filter, etc) was registered on module load. When netns support was added to iptables only the ip/ip6tables ruleset was made namespace aware, not the actual hook points. This means f.e. that when ipt_filter table/module is loaded on a system, then each namespace on that system has an (empty) iptables filter ruleset. In other words, if a namespace sends a packet, such skb is 'caught' by netfilter machinery and fed to hooking points for that table (i.e. INPUT, FORWARD, etc). Thanks to Eric Biederman, hooks are no longer global, but per namespace. This means that we can avoid allocation of empty ruleset in a namespace and defer hook registration until we need the functionality. We register a tables hook entry points ONLY in the initial namespace. When an iptables get/setockopt is issued inside a given namespace, we check if the table is found in the per-namespace list. If not, we attempt to find it in the initial namespace, and, if found, create an empty default table in the requesting namespace and register the needed hooks. Hook points are destroyed only once namespace is deleted, there is no 'usage count' (it makes no sense since there is no 'remove table' operation in xtables api). Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/x_tables.c65
1 files changed, 40 insertions, 25 deletions
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index c8a0b7da5ff4..d0cd2b9bf844 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -694,12 +694,45 @@ EXPORT_SYMBOL(xt_free_table_info);
694struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, 694struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
695 const char *name) 695 const char *name)
696{ 696{
697 struct xt_table *t; 697 struct xt_table *t, *found = NULL;
698 698
699 mutex_lock(&xt[af].mutex); 699 mutex_lock(&xt[af].mutex);
700 list_for_each_entry(t, &net->xt.tables[af], list) 700 list_for_each_entry(t, &net->xt.tables[af], list)
701 if (strcmp(t->name, name) == 0 && try_module_get(t->me)) 701 if (strcmp(t->name, name) == 0 && try_module_get(t->me))
702 return t; 702 return t;
703
704 if (net == &init_net)
705 goto out;
706
707 /* Table doesn't exist in this netns, re-try init */
708 list_for_each_entry(t, &init_net.xt.tables[af], list) {
709 if (strcmp(t->name, name))
710 continue;
711 if (!try_module_get(t->me))
712 return NULL;
713
714 mutex_unlock(&xt[af].mutex);
715 if (t->table_init(net) != 0) {
716 module_put(t->me);
717 return NULL;
718 }
719
720 found = t;
721
722 mutex_lock(&xt[af].mutex);
723 break;
724 }
725
726 if (!found)
727 goto out;
728
729 /* and once again: */
730 list_for_each_entry(t, &net->xt.tables[af], list)
731 if (strcmp(t->name, name) == 0)
732 return t;
733
734 module_put(found->me);
735 out:
703 mutex_unlock(&xt[af].mutex); 736 mutex_unlock(&xt[af].mutex);
704 return NULL; 737 return NULL;
705} 738}
@@ -1170,20 +1203,20 @@ static const struct file_operations xt_target_ops = {
1170#endif /* CONFIG_PROC_FS */ 1203#endif /* CONFIG_PROC_FS */
1171 1204
1172/** 1205/**
1173 * xt_hook_link - set up hooks for a new table 1206 * xt_hook_ops_alloc - set up hooks for a new table
1174 * @table: table with metadata needed to set up hooks 1207 * @table: table with metadata needed to set up hooks
1175 * @fn: Hook function 1208 * @fn: Hook function
1176 * 1209 *
1177 * This function will take care of creating and registering the necessary 1210 * This function will create the nf_hook_ops that the x_table needs
1178 * Netfilter hooks for XT tables. 1211 * to hand to xt_hook_link_net().
1179 */ 1212 */
1180struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn) 1213struct nf_hook_ops *
1214xt_hook_ops_alloc(const struct xt_table *table, nf_hookfn *fn)
1181{ 1215{
1182 unsigned int hook_mask = table->valid_hooks; 1216 unsigned int hook_mask = table->valid_hooks;
1183 uint8_t i, num_hooks = hweight32(hook_mask); 1217 uint8_t i, num_hooks = hweight32(hook_mask);
1184 uint8_t hooknum; 1218 uint8_t hooknum;
1185 struct nf_hook_ops *ops; 1219 struct nf_hook_ops *ops;
1186 int ret;
1187 1220
1188 ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL); 1221 ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL);
1189 if (ops == NULL) 1222 if (ops == NULL)
@@ -1200,27 +1233,9 @@ struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
1200 ++i; 1233 ++i;
1201 } 1234 }
1202 1235
1203 ret = nf_register_hooks(ops, num_hooks);
1204 if (ret < 0) {
1205 kfree(ops);
1206 return ERR_PTR(ret);
1207 }
1208
1209 return ops; 1236 return ops;
1210} 1237}
1211EXPORT_SYMBOL_GPL(xt_hook_link); 1238EXPORT_SYMBOL_GPL(xt_hook_ops_alloc);
1212
1213/**
1214 * xt_hook_unlink - remove hooks for a table
1215 * @ops: nf_hook_ops array as returned by nf_hook_link
1216 * @hook_mask: the very same mask that was passed to nf_hook_link
1217 */
1218void xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops)
1219{
1220 nf_unregister_hooks(ops, hweight32(table->valid_hooks));
1221 kfree(ops);
1222}
1223EXPORT_SYMBOL_GPL(xt_hook_unlink);
1224 1239
1225int xt_proto_init(struct net *net, u_int8_t af) 1240int xt_proto_init(struct net *net, u_int8_t af)
1226{ 1241{