Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: Use netlink_ns_capable to verify the permisions of netlink messages

It is possible by passing a netlink socket to a more privileged
executable and then to fool that executable into writing to the socket
data that happens to be valid netlink message to do something that
privileged executable did not intend to do.

To keep this from happening replace bare capable and ns_capable calls
with netlink_capable, netlink_net_calls and netlink_ns_capable calls.
Which act the same as the previous calls except they verify that the
opener of the socket had the desired permissions as well.

Reported-by: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric W. Biederman and committed by
David S. Miller
90f62cf3 aa4cf945

+38 -36
+1 -1
crypto/crypto_user.c
··· 466 466 type -= CRYPTO_MSG_BASE; 467 467 link = &crypto_dispatch[type]; 468 468 469 - if (!capable(CAP_NET_ADMIN)) 469 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 470 470 return -EPERM; 471 471 472 472 if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
+1 -1
drivers/connector/cn_proc.c
··· 369 369 return; 370 370 371 371 /* Can only change if privileged. */ 372 - if (!capable(CAP_NET_ADMIN)) { 372 + if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) { 373 373 err = EPERM; 374 374 goto out; 375 375 }
+1 -1
drivers/scsi/scsi_netlink.c
··· 77 77 goto next_msg; 78 78 } 79 79 80 - if (!capable(CAP_SYS_ADMIN)) { 80 + if (!netlink_capable(skb, CAP_SYS_ADMIN)) { 81 81 err = -EPERM; 82 82 goto next_msg; 83 83 }
+2 -2
kernel/audit.c
··· 643 643 if ((task_active_pid_ns(current) != &init_pid_ns)) 644 644 return -EPERM; 645 645 646 - if (!capable(CAP_AUDIT_CONTROL)) 646 + if (!netlink_capable(skb, CAP_AUDIT_CONTROL)) 647 647 err = -EPERM; 648 648 break; 649 649 case AUDIT_USER: 650 650 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG: 651 651 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2: 652 - if (!capable(CAP_AUDIT_WRITE)) 652 + if (!netlink_capable(skb, CAP_AUDIT_WRITE)) 653 653 err = -EPERM; 654 654 break; 655 655 default: /* bad msg */
+2 -2
net/can/gw.c
··· 804 804 u8 limhops = 0; 805 805 int err = 0; 806 806 807 - if (!capable(CAP_NET_ADMIN)) 807 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 808 808 return -EPERM; 809 809 810 810 if (nlmsg_len(nlh) < sizeof(*r)) ··· 893 893 u8 limhops = 0; 894 894 int err = 0; 895 895 896 - if (!capable(CAP_NET_ADMIN)) 896 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 897 897 return -EPERM; 898 898 899 899 if (nlmsg_len(nlh) < sizeof(*r))
+11 -9
net/core/rtnetlink.c
··· 1395 1395 return 0; 1396 1396 } 1397 1397 1398 - static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, 1398 + static int do_setlink(const struct sk_buff *skb, 1399 + struct net_device *dev, struct ifinfomsg *ifm, 1399 1400 struct nlattr **tb, char *ifname, int modified) 1400 1401 { 1401 1402 const struct net_device_ops *ops = dev->netdev_ops; ··· 1408 1407 err = PTR_ERR(net); 1409 1408 goto errout; 1410 1409 } 1411 - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) { 1410 + if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { 1412 1411 err = -EPERM; 1413 1412 goto errout; 1414 1413 } ··· 1662 1661 if (err < 0) 1663 1662 goto errout; 1664 1663 1665 - err = do_setlink(dev, ifm, tb, ifname, 0); 1664 + err = do_setlink(skb, dev, ifm, tb, ifname, 0); 1666 1665 errout: 1667 1666 return err; 1668 1667 } ··· 1779 1778 } 1780 1779 EXPORT_SYMBOL(rtnl_create_link); 1781 1780 1782 - static int rtnl_group_changelink(struct net *net, int group, 1781 + static int rtnl_group_changelink(const struct sk_buff *skb, 1782 + struct net *net, int group, 1783 1783 struct ifinfomsg *ifm, 1784 1784 struct nlattr **tb) 1785 1785 { ··· 1789 1787 1790 1788 for_each_netdev(net, dev) { 1791 1789 if (dev->group == group) { 1792 - err = do_setlink(dev, ifm, tb, NULL, 0); 1790 + err = do_setlink(skb, dev, ifm, tb, NULL, 0); 1793 1791 if (err < 0) 1794 1792 return err; 1795 1793 } ··· 1931 1929 modified = 1; 1932 1930 } 1933 1931 1934 - return do_setlink(dev, ifm, tb, ifname, modified); 1932 + return do_setlink(skb, dev, ifm, tb, ifname, modified); 1935 1933 } 1936 1934 1937 1935 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { 1938 1936 if (ifm->ifi_index == 0 && tb[IFLA_GROUP]) 1939 - return rtnl_group_changelink(net, 1937 + return rtnl_group_changelink(skb, net, 1940 1938 nla_get_u32(tb[IFLA_GROUP]), 1941 1939 ifm, tb); 1942 1940 return -ENODEV; ··· 2323 2321 int err = -EINVAL; 2324 2322 __u8 *addr; 2325 2323 2326 - if (!capable(CAP_NET_ADMIN)) 2324 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 2327 2325 return -EPERM; 2328 2326 2329 2327 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); ··· 2775 2773 sz_idx = type>>2; 2776 2774 kind = type&3; 2777 2775 2778 - if (kind != 2 && !ns_capable(net->user_ns, CAP_NET_ADMIN)) 2776 + if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN)) 2779 2777 return -EPERM; 2780 2778 2781 2779 if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
+1 -1
net/dcb/dcbnl.c
··· 1669 1669 struct nlmsghdr *reply_nlh = NULL; 1670 1670 const struct reply_func *fn; 1671 1671 1672 - if ((nlh->nlmsg_type == RTM_SETDCB) && !capable(CAP_NET_ADMIN)) 1672 + if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN)) 1673 1673 return -EPERM; 1674 1674 1675 1675 ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
+2 -2
net/decnet/dn_dev.c
··· 574 574 struct dn_ifaddr __rcu **ifap; 575 575 int err = -EINVAL; 576 576 577 - if (!capable(CAP_NET_ADMIN)) 577 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 578 578 return -EPERM; 579 579 580 580 if (!net_eq(net, &init_net)) ··· 618 618 struct dn_ifaddr *ifa; 619 619 int err; 620 620 621 - if (!capable(CAP_NET_ADMIN)) 621 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 622 622 return -EPERM; 623 623 624 624 if (!net_eq(net, &init_net))
+2 -2
net/decnet/dn_fib.c
··· 505 505 struct nlattr *attrs[RTA_MAX+1]; 506 506 int err; 507 507 508 - if (!capable(CAP_NET_ADMIN)) 508 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 509 509 return -EPERM; 510 510 511 511 if (!net_eq(net, &init_net)) ··· 530 530 struct nlattr *attrs[RTA_MAX+1]; 531 531 int err; 532 532 533 - if (!capable(CAP_NET_ADMIN)) 533 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 534 534 return -EPERM; 535 535 536 536 if (!net_eq(net, &init_net))
+1 -1
net/decnet/netfilter/dn_rtmsg.c
··· 107 107 if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) 108 108 return; 109 109 110 - if (!capable(CAP_NET_ADMIN)) 110 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 111 111 RCV_SKB_FAIL(-EPERM); 112 112 113 113 /* Eventually we might send routing messages too */
+1 -1
net/netfilter/nfnetlink.c
··· 375 375 skb->len < nlh->nlmsg_len) 376 376 return; 377 377 378 - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) { 378 + if (!netlink_net_capable(skb, CAP_NET_ADMIN)) { 379 379 netlink_ack(skb, nlh, -EPERM); 380 380 return; 381 381 }
+1 -1
net/netlink/genetlink.c
··· 561 561 return -EOPNOTSUPP; 562 562 563 563 if ((ops->flags & GENL_ADMIN_PERM) && 564 - !capable(CAP_NET_ADMIN)) 564 + !netlink_capable(skb, CAP_NET_ADMIN)) 565 565 return -EPERM; 566 566 567 567 if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+1 -1
net/packet/diag.c
··· 194 194 195 195 net = sock_net(skb->sk); 196 196 req = nlmsg_data(cb->nlh); 197 - may_report_filterinfo = ns_capable(net->user_ns, CAP_NET_ADMIN); 197 + may_report_filterinfo = netlink_net_capable(cb->skb, CAP_NET_ADMIN); 198 198 199 199 mutex_lock(&net->packet.sklist_lock); 200 200 sk_for_each(sk, &net->packet.sklist) {
+4 -4
net/phonet/pn_netlink.c
··· 70 70 int err; 71 71 u8 pnaddr; 72 72 73 - if (!capable(CAP_NET_ADMIN)) 73 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 74 74 return -EPERM; 75 75 76 - if (!capable(CAP_SYS_ADMIN)) 76 + if (!netlink_capable(skb, CAP_SYS_ADMIN)) 77 77 return -EPERM; 78 78 79 79 ASSERT_RTNL(); ··· 233 233 int err; 234 234 u8 dst; 235 235 236 - if (!capable(CAP_NET_ADMIN)) 236 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 237 237 return -EPERM; 238 238 239 - if (!capable(CAP_SYS_ADMIN)) 239 + if (!netlink_capable(skb, CAP_SYS_ADMIN)) 240 240 return -EPERM; 241 241 242 242 ASSERT_RTNL();
+1 -1
net/sched/act_api.c
··· 948 948 u32 portid = skb ? NETLINK_CB(skb).portid : 0; 949 949 int ret = 0, ovr = 0; 950 950 951 - if ((n->nlmsg_type != RTM_GETACTION) && !capable(CAP_NET_ADMIN)) 951 + if ((n->nlmsg_type != RTM_GETACTION) && !netlink_capable(skb, CAP_NET_ADMIN)) 952 952 return -EPERM; 953 953 954 954 ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL);
+1 -1
net/sched/cls_api.c
··· 134 134 int err; 135 135 int tp_created = 0; 136 136 137 - if ((n->nlmsg_type != RTM_GETTFILTER) && !capable(CAP_NET_ADMIN)) 137 + if ((n->nlmsg_type != RTM_GETTFILTER) && !netlink_capable(skb, CAP_NET_ADMIN)) 138 138 return -EPERM; 139 139 140 140 replay:
+3 -3
net/sched/sch_api.c
··· 1084 1084 struct Qdisc *p = NULL; 1085 1085 int err; 1086 1086 1087 - if ((n->nlmsg_type != RTM_GETQDISC) && !capable(CAP_NET_ADMIN)) 1087 + if ((n->nlmsg_type != RTM_GETQDISC) && !netlink_capable(skb, CAP_NET_ADMIN)) 1088 1088 return -EPERM; 1089 1089 1090 1090 err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); ··· 1151 1151 struct Qdisc *q, *p; 1152 1152 int err; 1153 1153 1154 - if (!capable(CAP_NET_ADMIN)) 1154 + if (!netlink_capable(skb, CAP_NET_ADMIN)) 1155 1155 return -EPERM; 1156 1156 1157 1157 replay: ··· 1490 1490 u32 qid; 1491 1491 int err; 1492 1492 1493 - if ((n->nlmsg_type != RTM_GETTCLASS) && !capable(CAP_NET_ADMIN)) 1493 + if ((n->nlmsg_type != RTM_GETTCLASS) && !netlink_capable(skb, CAP_NET_ADMIN)) 1494 1494 return -EPERM; 1495 1495 1496 1496 err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
+1 -1
net/tipc/netlink.c
··· 47 47 int hdr_space = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN); 48 48 u16 cmd; 49 49 50 - if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN))) 50 + if ((req_userhdr->cmd & 0xC000) && (!netlink_capable(skb, CAP_NET_ADMIN))) 51 51 cmd = TIPC_CMD_NOT_NET_ADMIN; 52 52 else 53 53 cmd = req_userhdr->cmd;
+1 -1
net/xfrm/xfrm_user.c
··· 2377 2377 link = &xfrm_dispatch[type]; 2378 2378 2379 2379 /* All operations require privileges, even GET */ 2380 - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 2380 + if (!netlink_net_capable(skb, CAP_NET_ADMIN)) 2381 2381 return -EPERM; 2382 2382 2383 2383 if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||