| .. | .. |
|---|
| 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) |
|---|