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);
|
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
|
#ifdef CONFIG_COMPAT
|
||||||
/* 32 bit-userspace compatibility definitions. */
|
/* 32 bit-userspace compatibility definitions. */
|
||||||
struct compat_ebt_replace {
|
struct compat_ebt_replace {
|
||||||
|
@ -2314,28 +2234,6 @@ static int compat_update_counters(struct net *net, void __user *user,
|
||||||
hlp.num_counters, user, len);
|
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,
|
static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
|
||||||
void __user *user, int *len)
|
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 ebt_table *t;
|
||||||
struct net *net = sock_net(sk);
|
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)))
|
if (copy_from_user(&tmp, user, sizeof(tmp)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
@ -2413,20 +2303,112 @@ static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
|
||||||
}
|
}
|
||||||
#endif
|
#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 = {
|
static struct nf_sockopt_ops ebt_sockopts = {
|
||||||
.pf = PF_INET,
|
.pf = PF_INET,
|
||||||
.set_optmin = EBT_BASE_CTL,
|
.set_optmin = EBT_BASE_CTL,
|
||||||
.set_optmax = EBT_SO_SET_MAX + 1,
|
.set_optmax = EBT_SO_SET_MAX + 1,
|
||||||
.set = do_ebt_set_ctl,
|
.set = do_ebt_set_ctl,
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
.compat_set = compat_do_ebt_set_ctl,
|
|
||||||
#endif
|
|
||||||
.get_optmin = EBT_BASE_CTL,
|
.get_optmin = EBT_BASE_CTL,
|
||||||
.get_optmax = EBT_SO_GET_MAX + 1,
|
.get_optmax = EBT_SO_GET_MAX + 1,
|
||||||
.get = do_ebt_get_ctl,
|
.get = do_ebt_get_ctl,
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
.compat_get = compat_do_ebt_get_ctl,
|
|
||||||
#endif
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче