.. | .. |
---|
570 | 570 | if (nlk_sk(sk)->bound) |
---|
571 | 571 | goto err; |
---|
572 | 572 | |
---|
573 | | - nlk_sk(sk)->portid = portid; |
---|
| 573 | + /* portid can be read locklessly from netlink_getname(). */ |
---|
| 574 | + WRITE_ONCE(nlk_sk(sk)->portid, portid); |
---|
| 575 | + |
---|
574 | 576 | sock_hold(sk); |
---|
575 | 577 | |
---|
576 | 578 | err = __netlink_insert(table, sk); |
---|
.. | .. |
---|
1079 | 1081 | return -EINVAL; |
---|
1080 | 1082 | |
---|
1081 | 1083 | if (addr->sa_family == AF_UNSPEC) { |
---|
1082 | | - sk->sk_state = NETLINK_UNCONNECTED; |
---|
1083 | | - nlk->dst_portid = 0; |
---|
1084 | | - nlk->dst_group = 0; |
---|
| 1084 | + /* paired with READ_ONCE() in netlink_getsockbyportid() */ |
---|
| 1085 | + WRITE_ONCE(sk->sk_state, NETLINK_UNCONNECTED); |
---|
| 1086 | + /* dst_portid and dst_group can be read locklessly */ |
---|
| 1087 | + WRITE_ONCE(nlk->dst_portid, 0); |
---|
| 1088 | + WRITE_ONCE(nlk->dst_group, 0); |
---|
1085 | 1089 | return 0; |
---|
1086 | 1090 | } |
---|
1087 | 1091 | if (addr->sa_family != AF_NETLINK) |
---|
.. | .. |
---|
1102 | 1106 | err = netlink_autobind(sock); |
---|
1103 | 1107 | |
---|
1104 | 1108 | if (err == 0) { |
---|
1105 | | - sk->sk_state = NETLINK_CONNECTED; |
---|
1106 | | - nlk->dst_portid = nladdr->nl_pid; |
---|
1107 | | - nlk->dst_group = ffs(nladdr->nl_groups); |
---|
| 1109 | + /* paired with READ_ONCE() in netlink_getsockbyportid() */ |
---|
| 1110 | + WRITE_ONCE(sk->sk_state, NETLINK_CONNECTED); |
---|
| 1111 | + /* dst_portid and dst_group can be read locklessly */ |
---|
| 1112 | + WRITE_ONCE(nlk->dst_portid, nladdr->nl_pid); |
---|
| 1113 | + WRITE_ONCE(nlk->dst_group, ffs(nladdr->nl_groups)); |
---|
1108 | 1114 | } |
---|
1109 | 1115 | |
---|
1110 | 1116 | return err; |
---|
.. | .. |
---|
1121 | 1127 | nladdr->nl_pad = 0; |
---|
1122 | 1128 | |
---|
1123 | 1129 | if (peer) { |
---|
1124 | | - nladdr->nl_pid = nlk->dst_portid; |
---|
1125 | | - nladdr->nl_groups = netlink_group_mask(nlk->dst_group); |
---|
| 1130 | + /* Paired with WRITE_ONCE() in netlink_connect() */ |
---|
| 1131 | + nladdr->nl_pid = READ_ONCE(nlk->dst_portid); |
---|
| 1132 | + nladdr->nl_groups = netlink_group_mask(READ_ONCE(nlk->dst_group)); |
---|
1126 | 1133 | } else { |
---|
1127 | | - nladdr->nl_pid = nlk->portid; |
---|
| 1134 | + /* Paired with WRITE_ONCE() in netlink_insert() */ |
---|
| 1135 | + nladdr->nl_pid = READ_ONCE(nlk->portid); |
---|
1128 | 1136 | netlink_lock_table(); |
---|
1129 | 1137 | nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0; |
---|
1130 | 1138 | netlink_unlock_table(); |
---|
.. | .. |
---|
1151 | 1159 | |
---|
1152 | 1160 | /* Don't bother queuing skb if kernel socket has no input function */ |
---|
1153 | 1161 | nlk = nlk_sk(sock); |
---|
1154 | | - if (sock->sk_state == NETLINK_CONNECTED && |
---|
1155 | | - nlk->dst_portid != nlk_sk(ssk)->portid) { |
---|
| 1162 | + /* dst_portid and sk_state can be changed in netlink_connect() */ |
---|
| 1163 | + if (READ_ONCE(sock->sk_state) == NETLINK_CONNECTED && |
---|
| 1164 | + READ_ONCE(nlk->dst_portid) != nlk_sk(ssk)->portid) { |
---|
1156 | 1165 | sock_put(sock); |
---|
1157 | 1166 | return ERR_PTR(-ECONNREFUSED); |
---|
1158 | 1167 | } |
---|
.. | .. |
---|
1593 | 1602 | int netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code) |
---|
1594 | 1603 | { |
---|
1595 | 1604 | struct netlink_set_err_data info; |
---|
| 1605 | + unsigned long flags; |
---|
1596 | 1606 | struct sock *sk; |
---|
1597 | 1607 | int ret = 0; |
---|
1598 | 1608 | |
---|
.. | .. |
---|
1602 | 1612 | /* sk->sk_err wants a positive error value */ |
---|
1603 | 1613 | info.code = -code; |
---|
1604 | 1614 | |
---|
1605 | | - read_lock(&nl_table_lock); |
---|
| 1615 | + read_lock_irqsave(&nl_table_lock, flags); |
---|
1606 | 1616 | |
---|
1607 | 1617 | sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) |
---|
1608 | 1618 | ret += do_one_set_err(sk, &info); |
---|
1609 | 1619 | |
---|
1610 | | - read_unlock(&nl_table_lock); |
---|
| 1620 | + read_unlock_irqrestore(&nl_table_lock, flags); |
---|
1611 | 1621 | return ret; |
---|
1612 | 1622 | } |
---|
1613 | 1623 | EXPORT_SYMBOL(netlink_set_err); |
---|
.. | .. |
---|
1735 | 1745 | { |
---|
1736 | 1746 | struct sock *sk = sock->sk; |
---|
1737 | 1747 | struct netlink_sock *nlk = nlk_sk(sk); |
---|
1738 | | - int len, val, err; |
---|
| 1748 | + unsigned int flag; |
---|
| 1749 | + int len, val; |
---|
1739 | 1750 | |
---|
1740 | 1751 | if (level != SOL_NETLINK) |
---|
1741 | 1752 | return -ENOPROTOOPT; |
---|
.. | .. |
---|
1747 | 1758 | |
---|
1748 | 1759 | switch (optname) { |
---|
1749 | 1760 | case NETLINK_PKTINFO: |
---|
1750 | | - if (len < sizeof(int)) |
---|
1751 | | - return -EINVAL; |
---|
1752 | | - len = sizeof(int); |
---|
1753 | | - val = nlk->flags & NETLINK_F_RECV_PKTINFO ? 1 : 0; |
---|
1754 | | - if (put_user(len, optlen) || |
---|
1755 | | - put_user(val, optval)) |
---|
1756 | | - return -EFAULT; |
---|
1757 | | - err = 0; |
---|
| 1761 | + flag = NETLINK_F_RECV_PKTINFO; |
---|
1758 | 1762 | break; |
---|
1759 | 1763 | case NETLINK_BROADCAST_ERROR: |
---|
1760 | | - if (len < sizeof(int)) |
---|
1761 | | - return -EINVAL; |
---|
1762 | | - len = sizeof(int); |
---|
1763 | | - val = nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR ? 1 : 0; |
---|
1764 | | - if (put_user(len, optlen) || |
---|
1765 | | - put_user(val, optval)) |
---|
1766 | | - return -EFAULT; |
---|
1767 | | - err = 0; |
---|
| 1764 | + flag = NETLINK_F_BROADCAST_SEND_ERROR; |
---|
1768 | 1765 | break; |
---|
1769 | 1766 | case NETLINK_NO_ENOBUFS: |
---|
1770 | | - if (len < sizeof(int)) |
---|
1771 | | - return -EINVAL; |
---|
1772 | | - len = sizeof(int); |
---|
1773 | | - val = nlk->flags & NETLINK_F_RECV_NO_ENOBUFS ? 1 : 0; |
---|
1774 | | - if (put_user(len, optlen) || |
---|
1775 | | - put_user(val, optval)) |
---|
1776 | | - return -EFAULT; |
---|
1777 | | - err = 0; |
---|
| 1767 | + flag = NETLINK_F_RECV_NO_ENOBUFS; |
---|
1778 | 1768 | break; |
---|
1779 | 1769 | case NETLINK_LIST_MEMBERSHIPS: { |
---|
1780 | | - int pos, idx, shift; |
---|
| 1770 | + int pos, idx, shift, err = 0; |
---|
1781 | 1771 | |
---|
1782 | | - err = 0; |
---|
1783 | 1772 | netlink_lock_table(); |
---|
1784 | 1773 | for (pos = 0; pos * 8 < nlk->ngroups; pos += sizeof(u32)) { |
---|
1785 | 1774 | if (len - pos < sizeof(u32)) |
---|
.. | .. |
---|
1793 | 1782 | break; |
---|
1794 | 1783 | } |
---|
1795 | 1784 | } |
---|
1796 | | - if (put_user(ALIGN(nlk->ngroups / 8, sizeof(u32)), optlen)) |
---|
| 1785 | + if (put_user(ALIGN(BITS_TO_BYTES(nlk->ngroups), sizeof(u32)), optlen)) |
---|
1797 | 1786 | err = -EFAULT; |
---|
1798 | 1787 | netlink_unlock_table(); |
---|
1799 | | - break; |
---|
| 1788 | + return err; |
---|
1800 | 1789 | } |
---|
1801 | 1790 | case NETLINK_CAP_ACK: |
---|
1802 | | - if (len < sizeof(int)) |
---|
1803 | | - return -EINVAL; |
---|
1804 | | - len = sizeof(int); |
---|
1805 | | - val = nlk->flags & NETLINK_F_CAP_ACK ? 1 : 0; |
---|
1806 | | - if (put_user(len, optlen) || |
---|
1807 | | - put_user(val, optval)) |
---|
1808 | | - return -EFAULT; |
---|
1809 | | - err = 0; |
---|
| 1791 | + flag = NETLINK_F_CAP_ACK; |
---|
1810 | 1792 | break; |
---|
1811 | 1793 | case NETLINK_EXT_ACK: |
---|
1812 | | - if (len < sizeof(int)) |
---|
1813 | | - return -EINVAL; |
---|
1814 | | - len = sizeof(int); |
---|
1815 | | - val = nlk->flags & NETLINK_F_EXT_ACK ? 1 : 0; |
---|
1816 | | - if (put_user(len, optlen) || put_user(val, optval)) |
---|
1817 | | - return -EFAULT; |
---|
1818 | | - err = 0; |
---|
| 1794 | + flag = NETLINK_F_EXT_ACK; |
---|
1819 | 1795 | break; |
---|
1820 | 1796 | case NETLINK_GET_STRICT_CHK: |
---|
1821 | | - if (len < sizeof(int)) |
---|
1822 | | - return -EINVAL; |
---|
1823 | | - len = sizeof(int); |
---|
1824 | | - val = nlk->flags & NETLINK_F_STRICT_CHK ? 1 : 0; |
---|
1825 | | - if (put_user(len, optlen) || put_user(val, optval)) |
---|
1826 | | - return -EFAULT; |
---|
1827 | | - err = 0; |
---|
| 1797 | + flag = NETLINK_F_STRICT_CHK; |
---|
1828 | 1798 | break; |
---|
1829 | 1799 | default: |
---|
1830 | | - err = -ENOPROTOOPT; |
---|
| 1800 | + return -ENOPROTOOPT; |
---|
1831 | 1801 | } |
---|
1832 | | - return err; |
---|
| 1802 | + |
---|
| 1803 | + if (len < sizeof(int)) |
---|
| 1804 | + return -EINVAL; |
---|
| 1805 | + |
---|
| 1806 | + len = sizeof(int); |
---|
| 1807 | + val = nlk->flags & flag ? 1 : 0; |
---|
| 1808 | + |
---|
| 1809 | + if (put_user(len, optlen) || |
---|
| 1810 | + copy_to_user(optval, &val, len)) |
---|
| 1811 | + return -EFAULT; |
---|
| 1812 | + |
---|
| 1813 | + return 0; |
---|
1833 | 1814 | } |
---|
1834 | 1815 | |
---|
1835 | 1816 | static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) |
---|
.. | .. |
---|
1888 | 1869 | goto out; |
---|
1889 | 1870 | netlink_skb_flags |= NETLINK_SKB_DST; |
---|
1890 | 1871 | } else { |
---|
1891 | | - dst_portid = nlk->dst_portid; |
---|
1892 | | - dst_group = nlk->dst_group; |
---|
| 1872 | + /* Paired with WRITE_ONCE() in netlink_connect() */ |
---|
| 1873 | + dst_portid = READ_ONCE(nlk->dst_portid); |
---|
| 1874 | + dst_group = READ_ONCE(nlk->dst_group); |
---|
1893 | 1875 | } |
---|
1894 | 1876 | |
---|
1895 | 1877 | /* Paired with WRITE_ONCE() in netlink_insert() */ |
---|
.. | .. |
---|
2011 | 1993 | |
---|
2012 | 1994 | skb_free_datagram(sk, skb); |
---|
2013 | 1995 | |
---|
2014 | | - if (nlk->cb_running && |
---|
| 1996 | + if (READ_ONCE(nlk->cb_running) && |
---|
2015 | 1997 | atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { |
---|
2016 | 1998 | ret = netlink_dump(sk); |
---|
2017 | 1999 | if (ret) { |
---|
.. | .. |
---|
2323 | 2305 | if (cb->done) |
---|
2324 | 2306 | cb->done(cb); |
---|
2325 | 2307 | |
---|
2326 | | - nlk->cb_running = false; |
---|
| 2308 | + WRITE_ONCE(nlk->cb_running, false); |
---|
2327 | 2309 | module = cb->module; |
---|
2328 | 2310 | skb = cb->skb; |
---|
2329 | 2311 | mutex_unlock(nlk->cb_mutex); |
---|
.. | .. |
---|
2386 | 2368 | goto error_put; |
---|
2387 | 2369 | } |
---|
2388 | 2370 | |
---|
2389 | | - nlk->cb_running = true; |
---|
| 2371 | + WRITE_ONCE(nlk->cb_running, true); |
---|
2390 | 2372 | nlk->dump_done_errno = INT_MAX; |
---|
2391 | 2373 | |
---|
2392 | 2374 | mutex_unlock(nlk->cb_mutex); |
---|
.. | .. |
---|
2672 | 2654 | nlk->groups ? (u32)nlk->groups[0] : 0, |
---|
2673 | 2655 | sk_rmem_alloc_get(s), |
---|
2674 | 2656 | sk_wmem_alloc_get(s), |
---|
2675 | | - nlk->cb_running, |
---|
| 2657 | + READ_ONCE(nlk->cb_running), |
---|
2676 | 2658 | refcount_read(&s->sk_refcnt), |
---|
2677 | 2659 | atomic_read(&s->sk_drops), |
---|
2678 | 2660 | sock_i_ino(s) |
---|