aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter/x_tables.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2007-12-12 10:35:16 -0800
committerDavid S. Miller <davem@sunset.davemloft.net>2007-12-14 13:54:35 -0800
commita18aa31b7774d8b36048e256a02d9d689533fc96 (patch)
tree095e8f12e838b819961adea85738c0a6e72048a9 /net/netfilter/x_tables.c
parentf2a89004da23a5ed2d78ac5550ccda5b714fe7d0 (diff)
downloadlinux-a18aa31b7774d8b36048e256a02d9d689533fc96.tar.gz
[NETFILTER]: ip_tables: fix compat copy race
When copying entries to user, the kernel makes two passes through the data, first copying all the entries, then fixing up names and counters. On the second pass it copies the kernel and match data from userspace to the kernel again to find the corresponding structures, expecting that kernel pointers contained in the data are still valid. This is obviously broken, fix by avoiding the second pass completely and fixing names and counters while dumping the ruleset, using the kernel-internal data structures. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netfilter/x_tables.c')
-rw-r--r--net/netfilter/x_tables.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index d9a3bded0d00a..b6160e41eb1ca 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -377,7 +377,9 @@ int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr,
u_int16_t msize = m->u.user.match_size - off;
if (copy_to_user(cm, m, sizeof(*cm)) ||
- put_user(msize, &cm->u.user.match_size))
+ put_user(msize, &cm->u.user.match_size) ||
+ copy_to_user(cm->u.user.name, m->u.kernel.match->name,
+ strlen(m->u.kernel.match->name) + 1))
return -EFAULT;
if (match->compat_to_user) {
@@ -468,7 +470,9 @@ int xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr,
u_int16_t tsize = t->u.user.target_size - off;
if (copy_to_user(ct, t, sizeof(*ct)) ||
- put_user(tsize, &ct->u.user.target_size))
+ put_user(tsize, &ct->u.user.target_size) ||
+ copy_to_user(ct->u.user.name, t->u.kernel.target->name,
+ strlen(t->u.kernel.target->name) + 1))
return -EFAULT;
if (target->compat_to_user) {