aboutsummaryrefslogtreecommitdiffstats
path: root/net/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/socket.c')
-rw-r--r--net/socket.c147
1 files changed, 127 insertions, 20 deletions
diff --git a/net/socket.c b/net/socket.c
index ac2219f90d5d..310d16b1b3c9 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -240,17 +240,19 @@ static struct kmem_cache *sock_inode_cachep __read_mostly;
240static struct inode *sock_alloc_inode(struct super_block *sb) 240static struct inode *sock_alloc_inode(struct super_block *sb)
241{ 241{
242 struct socket_alloc *ei; 242 struct socket_alloc *ei;
243 struct socket_wq *wq;
243 244
244 ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); 245 ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);
245 if (!ei) 246 if (!ei)
246 return NULL; 247 return NULL;
247 ei->socket.wq = kmalloc(sizeof(struct socket_wq), GFP_KERNEL); 248 wq = kmalloc(sizeof(*wq), GFP_KERNEL);
248 if (!ei->socket.wq) { 249 if (!wq) {
249 kmem_cache_free(sock_inode_cachep, ei); 250 kmem_cache_free(sock_inode_cachep, ei);
250 return NULL; 251 return NULL;
251 } 252 }
252 init_waitqueue_head(&ei->socket.wq->wait); 253 init_waitqueue_head(&wq->wait);
253 ei->socket.wq->fasync_list = NULL; 254 wq->fasync_list = NULL;
255 RCU_INIT_POINTER(ei->socket.wq, wq);
254 256
255 ei->socket.state = SS_UNCONNECTED; 257 ei->socket.state = SS_UNCONNECTED;
256 ei->socket.flags = 0; 258 ei->socket.flags = 0;
@@ -273,9 +275,11 @@ static void wq_free_rcu(struct rcu_head *head)
273static void sock_destroy_inode(struct inode *inode) 275static void sock_destroy_inode(struct inode *inode)
274{ 276{
275 struct socket_alloc *ei; 277 struct socket_alloc *ei;
278 struct socket_wq *wq;
276 279
277 ei = container_of(inode, struct socket_alloc, vfs_inode); 280 ei = container_of(inode, struct socket_alloc, vfs_inode);
278 call_rcu(&ei->socket.wq->rcu, wq_free_rcu); 281 wq = rcu_dereference_protected(ei->socket.wq, 1);
282 call_rcu(&wq->rcu, wq_free_rcu);
279 kmem_cache_free(sock_inode_cachep, ei); 283 kmem_cache_free(sock_inode_cachep, ei);
280} 284}
281 285
@@ -524,7 +528,7 @@ void sock_release(struct socket *sock)
524 module_put(owner); 528 module_put(owner);
525 } 529 }
526 530
527 if (sock->wq->fasync_list) 531 if (rcu_dereference_protected(sock->wq, 1)->fasync_list)
528 printk(KERN_ERR "sock_release: fasync list not empty!\n"); 532 printk(KERN_ERR "sock_release: fasync list not empty!\n");
529 533
530 percpu_sub(sockets_in_use, 1); 534 percpu_sub(sockets_in_use, 1);
@@ -1108,15 +1112,16 @@ static int sock_fasync(int fd, struct file *filp, int on)
1108{ 1112{
1109 struct socket *sock = filp->private_data; 1113 struct socket *sock = filp->private_data;
1110 struct sock *sk = sock->sk; 1114 struct sock *sk = sock->sk;
1115 struct socket_wq *wq;
1111 1116
1112 if (sk == NULL) 1117 if (sk == NULL)
1113 return -EINVAL; 1118 return -EINVAL;
1114 1119
1115 lock_sock(sk); 1120 lock_sock(sk);
1121 wq = rcu_dereference_protected(sock->wq, sock_owned_by_user(sk));
1122 fasync_helper(fd, filp, on, &wq->fasync_list);
1116 1123
1117 fasync_helper(fd, filp, on, &sock->wq->fasync_list); 1124 if (!wq->fasync_list)
1118
1119 if (!sock->wq->fasync_list)
1120 sock_reset_flag(sk, SOCK_FASYNC); 1125 sock_reset_flag(sk, SOCK_FASYNC);
1121 else 1126 else
1122 sock_set_flag(sk, SOCK_FASYNC); 1127 sock_set_flag(sk, SOCK_FASYNC);
@@ -2583,23 +2588,123 @@ static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
2583 2588
2584static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) 2589static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
2585{ 2590{
2591 struct compat_ethtool_rxnfc __user *compat_rxnfc;
2592 bool convert_in = false, convert_out = false;
2593 size_t buf_size = ALIGN(sizeof(struct ifreq), 8);
2594 struct ethtool_rxnfc __user *rxnfc;
2586 struct ifreq __user *ifr; 2595 struct ifreq __user *ifr;
2596 u32 rule_cnt = 0, actual_rule_cnt;
2597 u32 ethcmd;
2587 u32 data; 2598 u32 data;
2588 void __user *datap; 2599 int ret;
2589 2600
2590 ifr = compat_alloc_user_space(sizeof(*ifr)); 2601 if (get_user(data, &ifr32->ifr_ifru.ifru_data))
2602 return -EFAULT;
2591 2603
2592 if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) 2604 compat_rxnfc = compat_ptr(data);
2605
2606 if (get_user(ethcmd, &compat_rxnfc->cmd))
2593 return -EFAULT; 2607 return -EFAULT;
2594 2608
2595 if (get_user(data, &ifr32->ifr_ifru.ifru_data)) 2609 /* Most ethtool structures are defined without padding.
2610 * Unfortunately struct ethtool_rxnfc is an exception.
2611 */
2612 switch (ethcmd) {
2613 default:
2614 break;
2615 case ETHTOOL_GRXCLSRLALL:
2616 /* Buffer size is variable */
2617 if (get_user(rule_cnt, &compat_rxnfc->rule_cnt))
2618 return -EFAULT;
2619 if (rule_cnt > KMALLOC_MAX_SIZE / sizeof(u32))
2620 return -ENOMEM;
2621 buf_size += rule_cnt * sizeof(u32);
2622 /* fall through */
2623 case ETHTOOL_GRXRINGS:
2624 case ETHTOOL_GRXCLSRLCNT:
2625 case ETHTOOL_GRXCLSRULE:
2626 convert_out = true;
2627 /* fall through */
2628 case ETHTOOL_SRXCLSRLDEL:
2629 case ETHTOOL_SRXCLSRLINS:
2630 buf_size += sizeof(struct ethtool_rxnfc);
2631 convert_in = true;
2632 break;
2633 }
2634
2635 ifr = compat_alloc_user_space(buf_size);
2636 rxnfc = (void *)ifr + ALIGN(sizeof(struct ifreq), 8);
2637
2638 if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ))
2596 return -EFAULT; 2639 return -EFAULT;
2597 2640
2598 datap = compat_ptr(data); 2641 if (put_user(convert_in ? rxnfc : compat_ptr(data),
2599 if (put_user(datap, &ifr->ifr_ifru.ifru_data)) 2642 &ifr->ifr_ifru.ifru_data))
2600 return -EFAULT; 2643 return -EFAULT;
2601 2644
2602 return dev_ioctl(net, SIOCETHTOOL, ifr); 2645 if (convert_in) {
2646 /* We expect there to be holes between fs.m_u and
2647 * fs.ring_cookie and at the end of fs, but nowhere else.
2648 */
2649 BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_u) +
2650 sizeof(compat_rxnfc->fs.m_u) !=
2651 offsetof(struct ethtool_rxnfc, fs.m_u) +
2652 sizeof(rxnfc->fs.m_u));
2653 BUILD_BUG_ON(
2654 offsetof(struct compat_ethtool_rxnfc, fs.location) -
2655 offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) !=
2656 offsetof(struct ethtool_rxnfc, fs.location) -
2657 offsetof(struct ethtool_rxnfc, fs.ring_cookie));
2658
2659 if (copy_in_user(rxnfc, compat_rxnfc,
2660 (void *)(&rxnfc->fs.m_u + 1) -
2661 (void *)rxnfc) ||
2662 copy_in_user(&rxnfc->fs.ring_cookie,
2663 &compat_rxnfc->fs.ring_cookie,
2664 (void *)(&rxnfc->fs.location + 1) -
2665 (void *)&rxnfc->fs.ring_cookie) ||
2666 copy_in_user(&rxnfc->rule_cnt, &compat_rxnfc->rule_cnt,
2667 sizeof(rxnfc->rule_cnt)))
2668 return -EFAULT;
2669 }
2670
2671 ret = dev_ioctl(net, SIOCETHTOOL, ifr);
2672 if (ret)
2673 return ret;
2674
2675 if (convert_out) {
2676 if (copy_in_user(compat_rxnfc, rxnfc,
2677 (const void *)(&rxnfc->fs.m_u + 1) -
2678 (const void *)rxnfc) ||
2679 copy_in_user(&compat_rxnfc->fs.ring_cookie,
2680 &rxnfc->fs.ring_cookie,
2681 (const void *)(&rxnfc->fs.location + 1) -
2682 (const void *)&rxnfc->fs.ring_cookie) ||
2683 copy_in_user(&compat_rxnfc->rule_cnt, &rxnfc->rule_cnt,
2684 sizeof(rxnfc->rule_cnt)))
2685 return -EFAULT;
2686
2687 if (ethcmd == ETHTOOL_GRXCLSRLALL) {
2688 /* As an optimisation, we only copy the actual
2689 * number of rules that the underlying
2690 * function returned. Since Mallory might
2691 * change the rule count in user memory, we
2692 * check that it is less than the rule count
2693 * originally given (as the user buffer size),
2694 * which has been range-checked.
2695 */
2696 if (get_user(actual_rule_cnt, &rxnfc->rule_cnt))
2697 return -EFAULT;
2698 if (actual_rule_cnt < rule_cnt)
2699 rule_cnt = actual_rule_cnt;
2700 if (copy_in_user(&compat_rxnfc->rule_locs[0],
2701 &rxnfc->rule_locs[0],
2702 rule_cnt * sizeof(u32)))
2703 return -EFAULT;
2704 }
2705 }
2706
2707 return 0;
2603} 2708}
2604 2709
2605static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32) 2710static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32)
@@ -2643,7 +2748,8 @@ static int bond_ioctl(struct net *net, unsigned int cmd,
2643 2748
2644 old_fs = get_fs(); 2749 old_fs = get_fs();
2645 set_fs(KERNEL_DS); 2750 set_fs(KERNEL_DS);
2646 err = dev_ioctl(net, cmd, &kifr); 2751 err = dev_ioctl(net, cmd,
2752 (struct ifreq __user __force *) &kifr);
2647 set_fs(old_fs); 2753 set_fs(old_fs);
2648 2754
2649 return err; 2755 return err;
@@ -2752,7 +2858,7 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
2752 2858
2753 old_fs = get_fs(); 2859 old_fs = get_fs();
2754 set_fs(KERNEL_DS); 2860 set_fs(KERNEL_DS);
2755 err = dev_ioctl(net, cmd, (void __user *)&ifr); 2861 err = dev_ioctl(net, cmd, (void __user __force *)&ifr);
2756 set_fs(old_fs); 2862 set_fs(old_fs);
2757 2863
2758 if (cmd == SIOCGIFMAP && !err) { 2864 if (cmd == SIOCGIFMAP && !err) {
@@ -2857,7 +2963,8 @@ static int routing_ioctl(struct net *net, struct socket *sock,
2857 ret |= __get_user(rtdev, &(ur4->rt_dev)); 2963 ret |= __get_user(rtdev, &(ur4->rt_dev));
2858 if (rtdev) { 2964 if (rtdev) {
2859 ret |= copy_from_user(devname, compat_ptr(rtdev), 15); 2965 ret |= copy_from_user(devname, compat_ptr(rtdev), 15);
2860 r4.rt_dev = devname; devname[15] = 0; 2966 r4.rt_dev = (char __user __force *)devname;
2967 devname[15] = 0;
2861 } else 2968 } else
2862 r4.rt_dev = NULL; 2969 r4.rt_dev = NULL;
2863 2970
@@ -2879,7 +2986,7 @@ out:
2879 2986
2880/* Since old style bridge ioctl's endup using SIOCDEVPRIVATE 2987/* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
2881 * for some operations; this forces use of the newer bridge-utils that 2988 * for some operations; this forces use of the newer bridge-utils that
2882 * use compatiable ioctls 2989 * use compatible ioctls
2883 */ 2990 */
2884static int old_bridge_ioctl(compat_ulong_t __user *argp) 2991static int old_bridge_ioctl(compat_ulong_t __user *argp)
2885{ 2992{