netfilter: nft_set_rbtree: add missing rb_erase() in GC routine
[linux-2.6-microblaze.git] / net / socket.c
index 8563362..01f3f8f 100644 (file)
@@ -89,6 +89,7 @@
 #include <linux/magic.h>
 #include <linux/slab.h>
 #include <linux/xattr.h>
+#include <linux/nospec.h>
 
 #include <linux/uaccess.h>
 #include <asm/unistd.h>
@@ -251,7 +252,7 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
        init_waitqueue_head(&wq->wait);
        wq->fasync_list = NULL;
        wq->flags = 0;
-       RCU_INIT_POINTER(ei->socket.wq, wq);
+       ei->socket.wq = wq;
 
        ei->socket.state = SS_UNCONNECTED;
        ei->socket.flags = 0;
@@ -265,11 +266,9 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
 static void sock_destroy_inode(struct inode *inode)
 {
        struct socket_alloc *ei;
-       struct socket_wq *wq;
 
        ei = container_of(inode, struct socket_alloc, vfs_inode);
-       wq = rcu_dereference_protected(ei->socket.wq, 1);
-       kfree_rcu(wq, rcu);
+       kfree_rcu(ei->socket.wq, rcu);
        kmem_cache_free(sock_inode_cachep, ei);
 }
 
@@ -387,39 +386,20 @@ static struct file_system_type sock_fs_type = {
 
 struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname)
 {
-       struct qstr name = { .name = "" };
-       struct path path;
        struct file *file;
 
-       if (dname) {
-               name.name = dname;
-               name.len = strlen(name.name);
-       } else if (sock->sk) {
-               name.name = sock->sk->sk_prot_creator->name;
-               name.len = strlen(name.name);
-       }
-       path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name);
-       if (unlikely(!path.dentry)) {
-               sock_release(sock);
-               return ERR_PTR(-ENOMEM);
-       }
-       path.mnt = mntget(sock_mnt);
-
-       d_instantiate(path.dentry, SOCK_INODE(sock));
+       if (!dname)
+               dname = sock->sk ? sock->sk->sk_prot_creator->name : "";
 
-       file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
-                 &socket_file_ops);
+       file = alloc_file_pseudo(SOCK_INODE(sock), sock_mnt, dname,
+                               O_RDWR | (flags & O_NONBLOCK),
+                               &socket_file_ops);
        if (IS_ERR(file)) {
-               /* drop dentry, keep inode for a bit */
-               ihold(d_inode(path.dentry));
-               path_put(&path);
-               /* ... and now kill it properly */
                sock_release(sock);
                return file;
        }
 
        sock->file = file;
-       file->f_flags = O_RDWR | (flags & O_NONBLOCK);
        file->private_data = sock;
        return file;
 }
@@ -603,7 +583,7 @@ static void __sock_release(struct socket *sock, struct inode *inode)
                module_put(owner);
        }
 
-       if (rcu_dereference_protected(sock->wq, 1)->fasync_list)
+       if (sock->wq->fasync_list)
                pr_err("%s: fasync list not empty!\n", __func__);
 
        if (!sock->file) {
@@ -961,7 +941,8 @@ void dlci_ioctl_set(int (*hook) (unsigned int, void __user *))
 EXPORT_SYMBOL(dlci_ioctl_set);
 
 static long sock_do_ioctl(struct net *net, struct socket *sock,
-                                unsigned int cmd, unsigned long arg)
+                         unsigned int cmd, unsigned long arg,
+                         unsigned int ifreq_size)
 {
        int err;
        void __user *argp = (void __user *)arg;
@@ -987,11 +968,11 @@ static long sock_do_ioctl(struct net *net, struct socket *sock,
        } else {
                struct ifreq ifr;
                bool need_copyout;
-               if (copy_from_user(&ifr, argp, sizeof(struct ifreq)))
+               if (copy_from_user(&ifr, argp, ifreq_size))
                        return -EFAULT;
                err = dev_ioctl(net, cmd, &ifr, &need_copyout);
                if (!err && need_copyout)
-                       if (copy_to_user(argp, &ifr, sizeof(struct ifreq)))
+                       if (copy_to_user(argp, &ifr, ifreq_size))
                                return -EFAULT;
        }
        return err;
@@ -1090,7 +1071,8 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                        err = open_related_ns(&net->ns, get_net_ns);
                        break;
                default:
-                       err = sock_do_ioctl(net, sock, cmd, arg);
+                       err = sock_do_ioctl(net, sock, cmd, arg,
+                                           sizeof(struct ifreq));
                        break;
                }
        return err;
@@ -1130,12 +1112,21 @@ EXPORT_SYMBOL(sock_create_lite);
 static __poll_t sock_poll(struct file *file, poll_table *wait)
 {
        struct socket *sock = file->private_data;
-       __poll_t events = poll_requested_events(wait);
+       __poll_t events = poll_requested_events(wait), flag = 0;
 
-       sock_poll_busy_loop(sock, events);
        if (!sock->ops->poll)
                return 0;
-       return sock->ops->poll(file, sock, wait) | sock_poll_busy_flag(sock);
+
+       if (sk_can_busy_loop(sock->sk)) {
+               /* poll once if requested by the syscall */
+               if (events & POLL_BUSY_LOOP)
+                       sk_busy_loop(sock->sk, 1);
+
+               /* if this socket can poll_ll, tell the system call */
+               flag = POLL_BUSY_LOOP;
+       }
+
+       return sock->ops->poll(file, sock, wait) | flag;
 }
 
 static int sock_mmap(struct file *file, struct vm_area_struct *vma)
@@ -1172,7 +1163,7 @@ static int sock_fasync(int fd, struct file *filp, int on)
                return -EINVAL;
 
        lock_sock(sk);
-       wq = rcu_dereference_protected(sock->wq, lockdep_sock_is_held(sk));
+       wq = sock->wq;
        fasync_helper(fd, filp, on, &wq->fasync_list);
 
        if (!wq->fasync_list)
@@ -2522,6 +2513,7 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
 
        if (call < 1 || call > SYS_SENDMMSG)
                return -EINVAL;
+       call = array_index_nospec(call, SYS_SENDMMSG + 1);
 
        len = nargs[call];
        if (len > sizeof(a))
@@ -2760,7 +2752,8 @@ static int do_siocgstamp(struct net *net, struct socket *sock,
        int err;
 
        set_fs(KERNEL_DS);
-       err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv);
+       err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv,
+                           sizeof(struct compat_ifreq));
        set_fs(old_fs);
        if (!err)
                err = compat_put_timeval(&ktv, up);
@@ -2776,7 +2769,8 @@ static int do_siocgstampns(struct net *net, struct socket *sock,
        int err;
 
        set_fs(KERNEL_DS);
-       err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts);
+       err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts,
+                           sizeof(struct compat_ifreq));
        set_fs(old_fs);
        if (!err)
                err = compat_put_timespec(&kts, up);
@@ -3082,7 +3076,8 @@ static int routing_ioctl(struct net *net, struct socket *sock,
        }
 
        set_fs(KERNEL_DS);
-       ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r);
+       ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r,
+                           sizeof(struct compat_ifreq));
        set_fs(old_fs);
 
 out:
@@ -3195,7 +3190,8 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
        case SIOCBONDSETHWADDR:
        case SIOCBONDCHANGEACTIVE:
        case SIOCGIFNAME:
-               return sock_do_ioctl(net, sock, cmd, arg);
+               return sock_do_ioctl(net, sock, cmd, arg,
+                                    sizeof(struct compat_ifreq));
        }
 
        return -ENOIOCTLCMD;