aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2012-01-17 04:39:05 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2012-01-17 04:52:46 -0500
commit088067f4f14d6ee5c6a196b015a560cbe7744224 (patch)
tree1be34b941c1671b70834212d2188f8ce6b1c1f45 /net/netfilter
parent9bf04646b0b41c5438ed8a27c5f8dbe0ff40d756 (diff)
netfilter: ipset: autoload set type modules safely
Jan Engelhardt noticed when userspace requests a set type unknown to the kernel, it can lead to a loop due to the unsafe type module loading. The issue is fixed in this patch. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/ipset/ip_set_core.c36
1 files changed, 26 insertions, 10 deletions
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index 86137b558f45..0f8e5f2fa1ba 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -77,35 +77,42 @@ find_set_type(const char *name, u8 family, u8 revision)
77} 77}
78 78
79/* Unlock, try to load a set type module and lock again */ 79/* Unlock, try to load a set type module and lock again */
80static int 80static bool
81try_to_load_type(const char *name) 81load_settype(const char *name)
82{ 82{
83 nfnl_unlock(); 83 nfnl_unlock();
84 pr_debug("try to load ip_set_%s\n", name); 84 pr_debug("try to load ip_set_%s\n", name);
85 if (request_module("ip_set_%s", name) < 0) { 85 if (request_module("ip_set_%s", name) < 0) {
86 pr_warning("Can't find ip_set type %s\n", name); 86 pr_warning("Can't find ip_set type %s\n", name);
87 nfnl_lock(); 87 nfnl_lock();
88 return -IPSET_ERR_FIND_TYPE; 88 return false;
89 } 89 }
90 nfnl_lock(); 90 nfnl_lock();
91 return -EAGAIN; 91 return true;
92} 92}
93 93
94/* Find a set type and reference it */ 94/* Find a set type and reference it */
95#define find_set_type_get(name, family, revision, found) \
96 __find_set_type_get(name, family, revision, found, false)
97
95static int 98static int
96find_set_type_get(const char *name, u8 family, u8 revision, 99__find_set_type_get(const char *name, u8 family, u8 revision,
97 struct ip_set_type **found) 100 struct ip_set_type **found, bool retry)
98{ 101{
99 struct ip_set_type *type; 102 struct ip_set_type *type;
100 int err; 103 int err;
101 104
105 if (retry && !load_settype(name))
106 return -IPSET_ERR_FIND_TYPE;
107
102 rcu_read_lock(); 108 rcu_read_lock();
103 *found = find_set_type(name, family, revision); 109 *found = find_set_type(name, family, revision);
104 if (*found) { 110 if (*found) {
105 err = !try_module_get((*found)->me) ? -EFAULT : 0; 111 err = !try_module_get((*found)->me) ? -EFAULT : 0;
106 goto unlock; 112 goto unlock;
107 } 113 }
108 /* Make sure the type is loaded but we don't support the revision */ 114 /* Make sure the type is already loaded
115 * but we don't support the revision */
109 list_for_each_entry_rcu(type, &ip_set_type_list, list) 116 list_for_each_entry_rcu(type, &ip_set_type_list, list)
110 if (STREQ(type->name, name)) { 117 if (STREQ(type->name, name)) {
111 err = -IPSET_ERR_FIND_TYPE; 118 err = -IPSET_ERR_FIND_TYPE;
@@ -113,7 +120,8 @@ find_set_type_get(const char *name, u8 family, u8 revision,
113 } 120 }
114 rcu_read_unlock(); 121 rcu_read_unlock();
115 122
116 return try_to_load_type(name); 123 return retry ? -IPSET_ERR_FIND_TYPE :
124 __find_set_type_get(name, family, revision, found, true);
117 125
118unlock: 126unlock:
119 rcu_read_unlock(); 127 rcu_read_unlock();
@@ -124,12 +132,19 @@ unlock:
124 * If we succeeded, the supported minimal and maximum revisions are 132 * If we succeeded, the supported minimal and maximum revisions are
125 * filled out. 133 * filled out.
126 */ 134 */
135#define find_set_type_minmax(name, family, min, max) \
136 __find_set_type_minmax(name, family, min, max, false)
137
127static int 138static int
128find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max) 139__find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max,
140 bool retry)
129{ 141{
130 struct ip_set_type *type; 142 struct ip_set_type *type;
131 bool found = false; 143 bool found = false;
132 144
145 if (retry && !load_settype(name))
146 return -IPSET_ERR_FIND_TYPE;
147
133 *min = 255; *max = 0; 148 *min = 255; *max = 0;
134 rcu_read_lock(); 149 rcu_read_lock();
135 list_for_each_entry_rcu(type, &ip_set_type_list, list) 150 list_for_each_entry_rcu(type, &ip_set_type_list, list)
@@ -145,7 +160,8 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
145 if (found) 160 if (found)
146 return 0; 161 return 0;
147 162
148 return try_to_load_type(name); 163 return retry ? -IPSET_ERR_FIND_TYPE :
164 __find_set_type_minmax(name, family, min, max, true);
149} 165}
150 166
151#define family_name(f) ((f) == AF_INET ? "inet" : \ 167#define family_name(f) ((f) == AF_INET ? "inet" : \