Skip to content

Commit

Permalink
Merge branch 'uaccess.net' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/viro/vfs

Al Viro says:

====================
uaccess-related stuff in net/*

Assorted uaccess-related work in net/*.  First, there's
getting rid of compat_alloc_user_space() mess in MCAST_...
[gs]etsockopt() - no need to play with copying to/from temporary
object on userland stack, etc., when ->compat_[sg]etsockopt()
instances in question can easly do everything without that.
That's the first 13 patches.  Then there's a trivial bit in
net/batman-adv (completely unrelated to everything else) and
finally getting the atm compat ioctls into simpler shape.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed May 21, 2020
2 parents f78cdbd + 0edecc0 commit c536fc7
Show file tree
Hide file tree
Showing 12 changed files with 567 additions and 472 deletions.
2 changes: 1 addition & 1 deletion include/linux/igmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ extern int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf,int ifindex);
extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
struct ip_msfilter __user *optval, int __user *optlen);
extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
struct group_filter __user *optval, int __user *optlen);
struct sockaddr_storage __user *p);
extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt,
int dif, int sdif);
extern void ip_mc_init_dev(struct in_device *);
Expand Down
29 changes: 23 additions & 6 deletions include/net/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,28 @@ int put_cmsg_compat(struct msghdr*, int, int, int, void *);
int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *,
unsigned char *, int);

int compat_mc_setsockopt(struct sock *, int, int, char __user *, unsigned int,
int (*)(struct sock *, int, int, char __user *,
unsigned int));
int compat_mc_getsockopt(struct sock *, int, int, char __user *, int __user *,
int (*)(struct sock *, int, int, char __user *,
int __user *));
struct compat_group_req {
__u32 gr_interface;
struct __kernel_sockaddr_storage gr_group
__aligned(4);
} __packed;

struct compat_group_source_req {
__u32 gsr_interface;
struct __kernel_sockaddr_storage gsr_group
__aligned(4);
struct __kernel_sockaddr_storage gsr_source
__aligned(4);
} __packed;

struct compat_group_filter {
__u32 gf_interface;
struct __kernel_sockaddr_storage gf_group
__aligned(4);
__u32 gf_fmode;
__u32 gf_numsrc;
struct __kernel_sockaddr_storage gf_slist[1]
__aligned(4);
} __packed;

#endif /* NET_COMPAT_H */
5 changes: 3 additions & 2 deletions include/net/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -1136,9 +1136,10 @@ struct group_filter;

int ip6_mc_source(int add, int omode, struct sock *sk,
struct group_source_req *pgsr);
int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf);
int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
struct sockaddr_storage *list);
int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
struct group_filter __user *optval, int __user *optlen);
struct sockaddr_storage __user *p);

#ifdef CONFIG_PROC_FS
int ac6_proc_init(struct net *net);
Expand Down
96 changes: 52 additions & 44 deletions net/atm/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
int error;
struct list_head *pos;
void __user *argp = (void __user *)arg;
void __user *buf;
int __user *len;

vcc = ATM_SD(sock);
switch (cmd) {
Expand Down Expand Up @@ -162,7 +164,49 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
if (error != -ENOIOCTLCMD)
goto done;

error = atm_dev_ioctl(cmd, argp, compat);
if (cmd == ATM_GETNAMES) {
if (IS_ENABLED(CONFIG_COMPAT) && compat) {
#ifdef CONFIG_COMPAT
struct compat_atm_iobuf __user *ciobuf = argp;
compat_uptr_t cbuf;
len = &ciobuf->length;
if (get_user(cbuf, &ciobuf->buffer))
return -EFAULT;
buf = compat_ptr(cbuf);
#endif
} else {
struct atm_iobuf __user *iobuf = argp;
len = &iobuf->length;
if (get_user(buf, &iobuf->buffer))
return -EFAULT;
}
error = atm_getnames(buf, len);
} else {
int number;

if (IS_ENABLED(CONFIG_COMPAT) && compat) {
#ifdef CONFIG_COMPAT
struct compat_atmif_sioc __user *csioc = argp;
compat_uptr_t carg;

len = &csioc->length;
if (get_user(carg, &csioc->arg))
return -EFAULT;
buf = compat_ptr(carg);
if (get_user(number, &csioc->number))
return -EFAULT;
#endif
} else {
struct atmif_sioc __user *sioc = argp;

len = &sioc->length;
if (get_user(buf, &sioc->arg))
return -EFAULT;
if (get_user(number, &sioc->number))
return -EFAULT;
}
error = atm_dev_ioctl(cmd, buf, len, number, compat);
}

done:
return error;
Expand Down Expand Up @@ -230,61 +274,25 @@ static struct {
static int do_atm_iobuf(struct socket *sock, unsigned int cmd,
unsigned long arg)
{
struct atm_iobuf __user *iobuf;
struct compat_atm_iobuf __user *iobuf32;
struct compat_atm_iobuf __user *iobuf32 = compat_ptr(arg);
u32 data;
void __user *datap;
int len, err;

iobuf = compat_alloc_user_space(sizeof(*iobuf));
iobuf32 = compat_ptr(arg);

if (get_user(len, &iobuf32->length) ||
get_user(data, &iobuf32->buffer))
if (get_user(data, &iobuf32->buffer))
return -EFAULT;
datap = compat_ptr(data);
if (put_user(len, &iobuf->length) ||
put_user(datap, &iobuf->buffer))
return -EFAULT;

err = do_vcc_ioctl(sock, cmd, (unsigned long) iobuf, 0);

if (!err) {
if (copy_in_user(&iobuf32->length, &iobuf->length,
sizeof(int)))
err = -EFAULT;
}

return err;
return atm_getnames(&iobuf32->length, compat_ptr(data));
}

static int do_atmif_sioc(struct socket *sock, unsigned int cmd,
unsigned long arg)
{
struct atmif_sioc __user *sioc;
struct compat_atmif_sioc __user *sioc32;
struct compat_atmif_sioc __user *sioc32 = compat_ptr(arg);
int number;
u32 data;
void __user *datap;
int err;

sioc = compat_alloc_user_space(sizeof(*sioc));
sioc32 = compat_ptr(arg);

if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) ||
get_user(data, &sioc32->arg))
if (get_user(data, &sioc32->arg) || get_user(number, &sioc32->number))
return -EFAULT;
datap = compat_ptr(data);
if (put_user(datap, &sioc->arg))
return -EFAULT;

err = do_vcc_ioctl(sock, cmd, (unsigned long) sioc, 0);

if (!err) {
if (copy_in_user(&sioc32->length, &sioc->length,
sizeof(int)))
err = -EFAULT;
}
return err;
return atm_dev_ioctl(cmd, compat_ptr(data), &sioc32->length, number, 0);
}

static int do_atm_ioctl(struct socket *sock, unsigned int cmd32,
Expand Down
108 changes: 34 additions & 74 deletions net/atm/resources.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,88 +193,48 @@ static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg,
return error ? -EFAULT : 0;
}

int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
int atm_getnames(void __user *buf, int __user *iobuf_len)
{
void __user *buf;
int error, len, number, size = 0;
int error, len, size = 0;
struct atm_dev *dev;
struct list_head *p;
int *tmp_buf, *tmp_p;
int __user *sioc_len;
int __user *iobuf_len;

switch (cmd) {
case ATM_GETNAMES:
if (IS_ENABLED(CONFIG_COMPAT) && compat) {
#ifdef CONFIG_COMPAT
struct compat_atm_iobuf __user *ciobuf = arg;
compat_uptr_t cbuf;
iobuf_len = &ciobuf->length;
if (get_user(cbuf, &ciobuf->buffer))
return -EFAULT;
buf = compat_ptr(cbuf);
#endif
} else {
struct atm_iobuf __user *iobuf = arg;
iobuf_len = &iobuf->length;
if (get_user(buf, &iobuf->buffer))
return -EFAULT;
}
if (get_user(len, iobuf_len))
return -EFAULT;
mutex_lock(&atm_dev_mutex);
list_for_each(p, &atm_devs)
size += sizeof(int);
if (size > len) {
mutex_unlock(&atm_dev_mutex);
return -E2BIG;
}
tmp_buf = kmalloc(size, GFP_ATOMIC);
if (!tmp_buf) {
mutex_unlock(&atm_dev_mutex);
return -ENOMEM;
}
tmp_p = tmp_buf;
list_for_each(p, &atm_devs) {
dev = list_entry(p, struct atm_dev, dev_list);
*tmp_p++ = dev->number;
}
if (get_user(len, iobuf_len))
return -EFAULT;
mutex_lock(&atm_dev_mutex);
list_for_each(p, &atm_devs)
size += sizeof(int);
if (size > len) {
mutex_unlock(&atm_dev_mutex);
error = ((copy_to_user(buf, tmp_buf, size)) ||
put_user(size, iobuf_len))
? -EFAULT : 0;
kfree(tmp_buf);
return error;
default:
break;
return -E2BIG;
}

if (IS_ENABLED(CONFIG_COMPAT) && compat) {
#ifdef CONFIG_COMPAT
struct compat_atmif_sioc __user *csioc = arg;
compat_uptr_t carg;

sioc_len = &csioc->length;
if (get_user(carg, &csioc->arg))
return -EFAULT;
buf = compat_ptr(carg);

if (get_user(len, &csioc->length))
return -EFAULT;
if (get_user(number, &csioc->number))
return -EFAULT;
#endif
} else {
struct atmif_sioc __user *sioc = arg;

sioc_len = &sioc->length;
if (get_user(buf, &sioc->arg))
return -EFAULT;
if (get_user(len, &sioc->length))
return -EFAULT;
if (get_user(number, &sioc->number))
return -EFAULT;
tmp_buf = kmalloc(size, GFP_ATOMIC);
if (!tmp_buf) {
mutex_unlock(&atm_dev_mutex);
return -ENOMEM;
}
tmp_p = tmp_buf;
list_for_each(p, &atm_devs) {
dev = list_entry(p, struct atm_dev, dev_list);
*tmp_p++ = dev->number;
}
mutex_unlock(&atm_dev_mutex);
error = ((copy_to_user(buf, tmp_buf, size)) ||
put_user(size, iobuf_len))
? -EFAULT : 0;
kfree(tmp_buf);
return error;
}

int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
int number, int compat)
{
int error, len, size = 0;
struct atm_dev *dev;

if (get_user(len, sioc_len))
return -EFAULT;

dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d",
number);
Expand Down
5 changes: 3 additions & 2 deletions net/atm/resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
extern struct list_head atm_devs;
extern struct mutex atm_dev_mutex;

int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat);

int atm_getnames(void __user *buf, int __user *iobuf_len);
int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
int number, int compat);

#ifdef CONFIG_PROC_FS

Expand Down
3 changes: 0 additions & 3 deletions net/batman-adv/icmp_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,6 @@ static ssize_t batadv_socket_read(struct file *file, char __user *buf,
if (!buf || count < sizeof(struct batadv_icmp_packet))
return -EINVAL;

if (!access_ok(buf, count))
return -EFAULT;

error = wait_event_interruptible(socket_client->queue_wait,
socket_client->queue_len);

Expand Down
Loading

0 comments on commit c536fc7

Please sign in to comment.