|
@@ -1492,8 +1492,10 @@ static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
|
|
|
return xt_compat_match_to_user(m, dstptr, size);
|
|
|
}
|
|
|
|
|
|
-static int compat_copy_entry_to_user(struct ipt_entry *e,
|
|
|
- void __user **dstptr, compat_uint_t *size)
|
|
|
+static int
|
|
|
+compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
|
|
|
+ compat_uint_t *size, struct xt_counters *counters,
|
|
|
+ unsigned int *i)
|
|
|
{
|
|
|
struct ipt_entry_target *t;
|
|
|
struct compat_ipt_entry __user *ce;
|
|
@@ -1507,6 +1509,9 @@ static int compat_copy_entry_to_user(struct ipt_entry *e,
|
|
|
if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
|
|
|
goto out;
|
|
|
|
|
|
+ if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
|
|
|
+ goto out;
|
|
|
+
|
|
|
*dstptr += sizeof(struct compat_ipt_entry);
|
|
|
ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
|
|
|
target_offset = e->target_offset - (origsize - *size);
|
|
@@ -1522,6 +1527,8 @@ static int compat_copy_entry_to_user(struct ipt_entry *e,
|
|
|
goto out;
|
|
|
if (put_user(next_offset, &ce->next_offset))
|
|
|
goto out;
|
|
|
+
|
|
|
+ (*i)++;
|
|
|
return 0;
|
|
|
out:
|
|
|
return ret;
|
|
@@ -1937,14 +1944,13 @@ struct compat_ipt_get_entries
|
|
|
static int compat_copy_entries_to_user(unsigned int total_size,
|
|
|
struct xt_table *table, void __user *userptr)
|
|
|
{
|
|
|
- unsigned int off, num;
|
|
|
- struct compat_ipt_entry e;
|
|
|
struct xt_counters *counters;
|
|
|
struct xt_table_info *private = table->private;
|
|
|
void __user *pos;
|
|
|
unsigned int size;
|
|
|
int ret = 0;
|
|
|
void *loc_cpu_entry;
|
|
|
+ unsigned int i = 0;
|
|
|
|
|
|
counters = alloc_counters(table);
|
|
|
if (IS_ERR(counters))
|
|
@@ -1958,48 +1964,9 @@ static int compat_copy_entries_to_user(unsigned int total_size,
|
|
|
pos = userptr;
|
|
|
size = total_size;
|
|
|
ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
|
|
|
- compat_copy_entry_to_user, &pos, &size);
|
|
|
- if (ret)
|
|
|
- goto free_counters;
|
|
|
-
|
|
|
- /* ... then go back and fix counters and names */
|
|
|
- for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
|
|
|
- unsigned int i;
|
|
|
- struct ipt_entry_match m;
|
|
|
- struct ipt_entry_target t;
|
|
|
+ compat_copy_entry_to_user,
|
|
|
+ &pos, &size, counters, &i);
|
|
|
|
|
|
- ret = -EFAULT;
|
|
|
- if (copy_from_user(&e, userptr + off,
|
|
|
- sizeof(struct compat_ipt_entry)))
|
|
|
- goto free_counters;
|
|
|
- if (copy_to_user(userptr + off +
|
|
|
- offsetof(struct compat_ipt_entry, counters),
|
|
|
- &counters[num], sizeof(counters[num])))
|
|
|
- goto free_counters;
|
|
|
-
|
|
|
- for (i = sizeof(struct compat_ipt_entry);
|
|
|
- i < e.target_offset; i += m.u.match_size) {
|
|
|
- if (copy_from_user(&m, userptr + off + i,
|
|
|
- sizeof(struct ipt_entry_match)))
|
|
|
- goto free_counters;
|
|
|
- if (copy_to_user(userptr + off + i +
|
|
|
- offsetof(struct ipt_entry_match, u.user.name),
|
|
|
- m.u.kernel.match->name,
|
|
|
- strlen(m.u.kernel.match->name) + 1))
|
|
|
- goto free_counters;
|
|
|
- }
|
|
|
-
|
|
|
- if (copy_from_user(&t, userptr + off + e.target_offset,
|
|
|
- sizeof(struct ipt_entry_target)))
|
|
|
- goto free_counters;
|
|
|
- if (copy_to_user(userptr + off + e.target_offset +
|
|
|
- offsetof(struct ipt_entry_target, u.user.name),
|
|
|
- t.u.kernel.target->name,
|
|
|
- strlen(t.u.kernel.target->name) + 1))
|
|
|
- goto free_counters;
|
|
|
- }
|
|
|
- ret = 0;
|
|
|
-free_counters:
|
|
|
vfree(counters);
|
|
|
return ret;
|
|
|
}
|