diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-03-22 18:40:01 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-03-22 19:52:01 -0400 |
commit | c1ebd7dff700277e4d0a3da36833a406142e31d4 (patch) | |
tree | fbcfed48280d81744fe77efebb91900c7db1c776 /net | |
parent | a0f65a267dd62aef4e003f833ea6290fd1e07b34 (diff) |
netfilter: cttimeout: fix dependency with l4protocol conntrack module
This patch introduces nf_conntrack_l4proto_find_get() and
nf_conntrack_l4proto_put() to fix module dependencies between
timeout objects and l4-protocol conntrack modules.
Thus, we make sure that the module cannot be removed if it is
used by any of the cttimeout objects.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_conntrack_proto.c | 21 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_cttimeout.c | 45 | ||||
-rw-r--r-- | net/netfilter/xt_CT.c | 6 |
3 files changed, 48 insertions, 24 deletions
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 5701c8dd783c..be3da2c8cdc5 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
@@ -127,6 +127,27 @@ void nf_ct_l3proto_module_put(unsigned short l3proto) | |||
127 | } | 127 | } |
128 | EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); | 128 | EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); |
129 | 129 | ||
130 | struct nf_conntrack_l4proto * | ||
131 | nf_ct_l4proto_find_get(u_int16_t l3num, u_int8_t l4num) | ||
132 | { | ||
133 | struct nf_conntrack_l4proto *p; | ||
134 | |||
135 | rcu_read_lock(); | ||
136 | p = __nf_ct_l4proto_find(l3num, l4num); | ||
137 | if (!try_module_get(p->me)) | ||
138 | p = &nf_conntrack_l4proto_generic; | ||
139 | rcu_read_unlock(); | ||
140 | |||
141 | return p; | ||
142 | } | ||
143 | EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); | ||
144 | |||
145 | void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) | ||
146 | { | ||
147 | module_put(p->me); | ||
148 | } | ||
149 | EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); | ||
150 | |||
130 | static int kill_l3proto(struct nf_conn *i, void *data) | 151 | static int kill_l3proto(struct nf_conn *i, void *data) |
131 | { | 152 | { |
132 | return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto; | 153 | return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto; |
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index fec29a43de4d..2b9e79f5ef05 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c | |||
@@ -98,11 +98,13 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, | |||
98 | break; | 98 | break; |
99 | } | 99 | } |
100 | 100 | ||
101 | l4proto = __nf_ct_l4proto_find(l3num, l4num); | 101 | l4proto = nf_ct_l4proto_find_get(l3num, l4num); |
102 | 102 | ||
103 | /* This protocol is not supportted, skip. */ | 103 | /* This protocol is not supportted, skip. */ |
104 | if (l4proto->l4proto != l4num) | 104 | if (l4proto->l4proto != l4num) { |
105 | return -EOPNOTSUPP; | 105 | ret = -EOPNOTSUPP; |
106 | goto err_proto_put; | ||
107 | } | ||
106 | 108 | ||
107 | if (matching) { | 109 | if (matching) { |
108 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { | 110 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { |
@@ -110,20 +112,25 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, | |||
110 | * different kind, sorry. | 112 | * different kind, sorry. |
111 | */ | 113 | */ |
112 | if (matching->l3num != l3num || | 114 | if (matching->l3num != l3num || |
113 | matching->l4num != l4num) | 115 | matching->l4proto->l4proto != l4num) { |
114 | return -EINVAL; | 116 | ret = -EINVAL; |
117 | goto err_proto_put; | ||
118 | } | ||
115 | 119 | ||
116 | ret = ctnl_timeout_parse_policy(matching, l4proto, | 120 | ret = ctnl_timeout_parse_policy(matching, l4proto, |
117 | cda[CTA_TIMEOUT_DATA]); | 121 | cda[CTA_TIMEOUT_DATA]); |
118 | return ret; | 122 | return ret; |
119 | } | 123 | } |
120 | return -EBUSY; | 124 | ret = -EBUSY; |
125 | goto err_proto_put; | ||
121 | } | 126 | } |
122 | 127 | ||
123 | timeout = kzalloc(sizeof(struct ctnl_timeout) + | 128 | timeout = kzalloc(sizeof(struct ctnl_timeout) + |
124 | l4proto->ctnl_timeout.obj_size, GFP_KERNEL); | 129 | l4proto->ctnl_timeout.obj_size, GFP_KERNEL); |
125 | if (timeout == NULL) | 130 | if (timeout == NULL) { |
126 | return -ENOMEM; | 131 | ret = -ENOMEM; |
132 | goto err_proto_put; | ||
133 | } | ||
127 | 134 | ||
128 | ret = ctnl_timeout_parse_policy(timeout, l4proto, | 135 | ret = ctnl_timeout_parse_policy(timeout, l4proto, |
129 | cda[CTA_TIMEOUT_DATA]); | 136 | cda[CTA_TIMEOUT_DATA]); |
@@ -132,13 +139,15 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, | |||
132 | 139 | ||
133 | strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); | 140 | strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); |
134 | timeout->l3num = l3num; | 141 | timeout->l3num = l3num; |
135 | timeout->l4num = l4num; | 142 | timeout->l4proto = l4proto; |
136 | atomic_set(&timeout->refcnt, 1); | 143 | atomic_set(&timeout->refcnt, 1); |
137 | list_add_tail_rcu(&timeout->head, &cttimeout_list); | 144 | list_add_tail_rcu(&timeout->head, &cttimeout_list); |
138 | 145 | ||
139 | return 0; | 146 | return 0; |
140 | err: | 147 | err: |
141 | kfree(timeout); | 148 | kfree(timeout); |
149 | err_proto_put: | ||
150 | nf_ct_l4proto_put(l4proto); | ||
142 | return ret; | 151 | return ret; |
143 | } | 152 | } |
144 | 153 | ||
@@ -149,7 +158,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, | |||
149 | struct nlmsghdr *nlh; | 158 | struct nlmsghdr *nlh; |
150 | struct nfgenmsg *nfmsg; | 159 | struct nfgenmsg *nfmsg; |
151 | unsigned int flags = pid ? NLM_F_MULTI : 0; | 160 | unsigned int flags = pid ? NLM_F_MULTI : 0; |
152 | struct nf_conntrack_l4proto *l4proto; | 161 | struct nf_conntrack_l4proto *l4proto = timeout->l4proto; |
153 | 162 | ||
154 | event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; | 163 | event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; |
155 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); | 164 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); |
@@ -163,20 +172,10 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, | |||
163 | 172 | ||
164 | NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name); | 173 | NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name); |
165 | NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)); | 174 | NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)); |
166 | NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num); | 175 | NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto); |
167 | NLA_PUT_BE32(skb, CTA_TIMEOUT_USE, | 176 | NLA_PUT_BE32(skb, CTA_TIMEOUT_USE, |
168 | htonl(atomic_read(&timeout->refcnt))); | 177 | htonl(atomic_read(&timeout->refcnt))); |
169 | 178 | ||
170 | l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num); | ||
171 | |||
172 | /* If the timeout object does not match the layer 4 protocol tracker, | ||
173 | * then skip dumping the data part since we don't know how to | ||
174 | * interpret it. This may happen for UPDlite, SCTP and DCCP since | ||
175 | * you can unload the module. | ||
176 | */ | ||
177 | if (timeout->l4num != l4proto->l4proto) | ||
178 | goto out; | ||
179 | |||
180 | if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { | 179 | if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { |
181 | struct nlattr *nest_parms; | 180 | struct nlattr *nest_parms; |
182 | int ret; | 181 | int ret; |
@@ -192,7 +191,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, | |||
192 | 191 | ||
193 | nla_nest_end(skb, nest_parms); | 192 | nla_nest_end(skb, nest_parms); |
194 | } | 193 | } |
195 | out: | 194 | |
196 | nlmsg_end(skb, nlh); | 195 | nlmsg_end(skb, nlh); |
197 | return skb->len; | 196 | return skb->len; |
198 | 197 | ||
@@ -293,6 +292,7 @@ static int ctnl_timeout_try_del(struct ctnl_timeout *timeout) | |||
293 | if (atomic_dec_and_test(&timeout->refcnt)) { | 292 | if (atomic_dec_and_test(&timeout->refcnt)) { |
294 | /* We are protected by nfnl mutex. */ | 293 | /* We are protected by nfnl mutex. */ |
295 | list_del_rcu(&timeout->head); | 294 | list_del_rcu(&timeout->head); |
295 | nf_ct_l4proto_put(timeout->l4proto); | ||
296 | kfree_rcu(timeout, rcu_head); | 296 | kfree_rcu(timeout, rcu_head); |
297 | } else { | 297 | } else { |
298 | /* still in use, restore reference counter. */ | 298 | /* still in use, restore reference counter. */ |
@@ -417,6 +417,7 @@ static void __exit cttimeout_exit(void) | |||
417 | /* We are sure that our objects have no clients at this point, | 417 | /* We are sure that our objects have no clients at this point, |
418 | * it's safe to release them all without checking refcnt. | 418 | * it's safe to release them all without checking refcnt. |
419 | */ | 419 | */ |
420 | nf_ct_l4proto_put(cur->l4proto); | ||
420 | kfree_rcu(cur, rcu_head); | 421 | kfree_rcu(cur, rcu_head); |
421 | } | 422 | } |
422 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 423 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index b873445df444..80c39f0f6e91 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <net/netfilter/nf_conntrack.h> | 16 | #include <net/netfilter/nf_conntrack.h> |
17 | #include <net/netfilter/nf_conntrack_helper.h> | 17 | #include <net/netfilter/nf_conntrack_helper.h> |
18 | #include <net/netfilter/nf_conntrack_ecache.h> | 18 | #include <net/netfilter/nf_conntrack_ecache.h> |
19 | #include <net/netfilter/nf_conntrack_l4proto.h> | ||
19 | #include <net/netfilter/nf_conntrack_timeout.h> | 20 | #include <net/netfilter/nf_conntrack_timeout.h> |
20 | #include <net/netfilter/nf_conntrack_zones.h> | 21 | #include <net/netfilter/nf_conntrack_zones.h> |
21 | 22 | ||
@@ -243,11 +244,12 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) | |||
243 | info->timeout, timeout->l3num); | 244 | info->timeout, timeout->l3num); |
244 | goto err3; | 245 | goto err3; |
245 | } | 246 | } |
246 | if (timeout->l4num != e->ip.proto) { | 247 | if (timeout->l4proto->l4proto != e->ip.proto) { |
247 | ret = -EINVAL; | 248 | ret = -EINVAL; |
248 | pr_info("Timeout policy `%s' can only be " | 249 | pr_info("Timeout policy `%s' can only be " |
249 | "used by L4 protocol number %d\n", | 250 | "used by L4 protocol number %d\n", |
250 | info->timeout, timeout->l4num); | 251 | info->timeout, |
252 | timeout->l4proto->l4proto); | ||
251 | goto err3; | 253 | goto err3; |
252 | } | 254 | } |
253 | timeout_ext = nf_ct_timeout_ext_add(ct, timeout, | 255 | timeout_ext = nf_ct_timeout_ext_add(ct, timeout, |