netfilter/ebtables: clean up compat {get, set}sockopt handling
Merge the native and compat {get,set}sockopt handlers using in_compat_syscall(). Note that this required moving a fair amout of code around to be done sanely. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
f415e76fd7
Коммит
fc66de8e16
|
@ -1451,86 +1451,6 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user,
|
|||
ebt_entry_to_user, entries, tmp.entries);
|
||||
}
|
||||
|
||||
static int do_ebt_set_ctl(struct sock *sk,
|
||||
int cmd, void __user *user, unsigned int len)
|
||||
{
|
||||
int ret;
|
||||
struct net *net = sock_net(sk);
|
||||
|
||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
switch (cmd) {
|
||||
case EBT_SO_SET_ENTRIES:
|
||||
ret = do_replace(net, user, len);
|
||||
break;
|
||||
case EBT_SO_SET_COUNTERS:
|
||||
ret = update_counters(net, user, len);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
|
||||
{
|
||||
int ret;
|
||||
struct ebt_replace tmp;
|
||||
struct ebt_table *t;
|
||||
struct net *net = sock_net(sk);
|
||||
|
||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&tmp, user, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
|
||||
tmp.name[sizeof(tmp.name) - 1] = '\0';
|
||||
|
||||
t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
|
||||
if (!t)
|
||||
return ret;
|
||||
|
||||
switch (cmd) {
|
||||
case EBT_SO_GET_INFO:
|
||||
case EBT_SO_GET_INIT_INFO:
|
||||
if (*len != sizeof(struct ebt_replace)) {
|
||||
ret = -EINVAL;
|
||||
mutex_unlock(&ebt_mutex);
|
||||
break;
|
||||
}
|
||||
if (cmd == EBT_SO_GET_INFO) {
|
||||
tmp.nentries = t->private->nentries;
|
||||
tmp.entries_size = t->private->entries_size;
|
||||
tmp.valid_hooks = t->valid_hooks;
|
||||
} else {
|
||||
tmp.nentries = t->table->nentries;
|
||||
tmp.entries_size = t->table->entries_size;
|
||||
tmp.valid_hooks = t->table->valid_hooks;
|
||||
}
|
||||
mutex_unlock(&ebt_mutex);
|
||||
if (copy_to_user(user, &tmp, *len) != 0) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case EBT_SO_GET_ENTRIES:
|
||||
case EBT_SO_GET_INIT_ENTRIES:
|
||||
ret = copy_everything_to_user(t, user, len, cmd);
|
||||
mutex_unlock(&ebt_mutex);
|
||||
break;
|
||||
|
||||
default:
|
||||
mutex_unlock(&ebt_mutex);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
/* 32 bit-userspace compatibility definitions. */
|
||||
struct compat_ebt_replace {
|
||||
|
@ -2314,28 +2234,6 @@ static int compat_update_counters(struct net *net, void __user *user,
|
|||
hlp.num_counters, user, len);
|
||||
}
|
||||
|
||||
static int compat_do_ebt_set_ctl(struct sock *sk,
|
||||
int cmd, void __user *user, unsigned int len)
|
||||
{
|
||||
int ret;
|
||||
struct net *net = sock_net(sk);
|
||||
|
||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
switch (cmd) {
|
||||
case EBT_SO_SET_ENTRIES:
|
||||
ret = compat_do_replace(net, user, len);
|
||||
break;
|
||||
case EBT_SO_SET_COUNTERS:
|
||||
ret = compat_update_counters(net, user, len);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
|
||||
void __user *user, int *len)
|
||||
{
|
||||
|
@ -2344,14 +2242,6 @@ static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
|
|||
struct ebt_table *t;
|
||||
struct net *net = sock_net(sk);
|
||||
|
||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
/* try real handler in case userland supplied needed padding */
|
||||
if ((cmd == EBT_SO_GET_INFO ||
|
||||
cmd == EBT_SO_GET_INIT_INFO) && *len != sizeof(tmp))
|
||||
return do_ebt_get_ctl(sk, cmd, user, len);
|
||||
|
||||
if (copy_from_user(&tmp, user, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
|
||||
|
@ -2413,20 +2303,112 @@ static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
|
||||
{
|
||||
struct net *net = sock_net(sk);
|
||||
struct ebt_replace tmp;
|
||||
struct ebt_table *t;
|
||||
int ret;
|
||||
|
||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
/* try real handler in case userland supplied needed padding */
|
||||
if (in_compat_syscall() &&
|
||||
((cmd != EBT_SO_GET_INFO && cmd != EBT_SO_GET_INIT_INFO) ||
|
||||
*len != sizeof(tmp)))
|
||||
return compat_do_ebt_get_ctl(sk, cmd, user, len);
|
||||
#endif
|
||||
|
||||
if (copy_from_user(&tmp, user, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
|
||||
tmp.name[sizeof(tmp.name) - 1] = '\0';
|
||||
|
||||
t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
|
||||
if (!t)
|
||||
return ret;
|
||||
|
||||
switch (cmd) {
|
||||
case EBT_SO_GET_INFO:
|
||||
case EBT_SO_GET_INIT_INFO:
|
||||
if (*len != sizeof(struct ebt_replace)) {
|
||||
ret = -EINVAL;
|
||||
mutex_unlock(&ebt_mutex);
|
||||
break;
|
||||
}
|
||||
if (cmd == EBT_SO_GET_INFO) {
|
||||
tmp.nentries = t->private->nentries;
|
||||
tmp.entries_size = t->private->entries_size;
|
||||
tmp.valid_hooks = t->valid_hooks;
|
||||
} else {
|
||||
tmp.nentries = t->table->nentries;
|
||||
tmp.entries_size = t->table->entries_size;
|
||||
tmp.valid_hooks = t->table->valid_hooks;
|
||||
}
|
||||
mutex_unlock(&ebt_mutex);
|
||||
if (copy_to_user(user, &tmp, *len) != 0) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case EBT_SO_GET_ENTRIES:
|
||||
case EBT_SO_GET_INIT_ENTRIES:
|
||||
ret = copy_everything_to_user(t, user, len, cmd);
|
||||
mutex_unlock(&ebt_mutex);
|
||||
break;
|
||||
|
||||
default:
|
||||
mutex_unlock(&ebt_mutex);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_ebt_set_ctl(struct sock *sk, int cmd, void __user *user,
|
||||
unsigned int len)
|
||||
{
|
||||
struct net *net = sock_net(sk);
|
||||
int ret;
|
||||
|
||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
switch (cmd) {
|
||||
case EBT_SO_SET_ENTRIES:
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (in_compat_syscall())
|
||||
ret = compat_do_replace(net, user, len);
|
||||
else
|
||||
#endif
|
||||
ret = do_replace(net, user, len);
|
||||
break;
|
||||
case EBT_SO_SET_COUNTERS:
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (in_compat_syscall())
|
||||
ret = compat_update_counters(net, user, len);
|
||||
else
|
||||
#endif
|
||||
ret = update_counters(net, user, len);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct nf_sockopt_ops ebt_sockopts = {
|
||||
.pf = PF_INET,
|
||||
.set_optmin = EBT_BASE_CTL,
|
||||
.set_optmax = EBT_SO_SET_MAX + 1,
|
||||
.set = do_ebt_set_ctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_set = compat_do_ebt_set_ctl,
|
||||
#endif
|
||||
.get_optmin = EBT_BASE_CTL,
|
||||
.get_optmax = EBT_SO_GET_MAX + 1,
|
||||
.get = do_ebt_get_ctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_get = compat_do_ebt_get_ctl,
|
||||
#endif
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче