diff options
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r-- | net/netlink/af_netlink.c | 80 |
1 files changed, 75 insertions, 5 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 894cda0206bb..f22757a29cd0 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -1360,7 +1360,74 @@ retry: | |||
1360 | return err; | 1360 | return err; |
1361 | } | 1361 | } |
1362 | 1362 | ||
1363 | static inline int netlink_capable(const struct socket *sock, unsigned int flag) | 1363 | /** |
1364 | * __netlink_ns_capable - General netlink message capability test | ||
1365 | * @nsp: NETLINK_CB of the socket buffer holding a netlink command from userspace. | ||
1366 | * @user_ns: The user namespace of the capability to use | ||
1367 | * @cap: The capability to use | ||
1368 | * | ||
1369 | * Test to see if the opener of the socket we received the message | ||
1370 | * from had when the netlink socket was created and the sender of the | ||
1371 | * message has has the capability @cap in the user namespace @user_ns. | ||
1372 | */ | ||
1373 | bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, | ||
1374 | struct user_namespace *user_ns, int cap) | ||
1375 | { | ||
1376 | return ((nsp->flags & NETLINK_SKB_DST) || | ||
1377 | file_ns_capable(nsp->sk->sk_socket->file, user_ns, cap)) && | ||
1378 | ns_capable(user_ns, cap); | ||
1379 | } | ||
1380 | EXPORT_SYMBOL(__netlink_ns_capable); | ||
1381 | |||
1382 | /** | ||
1383 | * netlink_ns_capable - General netlink message capability test | ||
1384 | * @skb: socket buffer holding a netlink command from userspace | ||
1385 | * @user_ns: The user namespace of the capability to use | ||
1386 | * @cap: The capability to use | ||
1387 | * | ||
1388 | * Test to see if the opener of the socket we received the message | ||
1389 | * from had when the netlink socket was created and the sender of the | ||
1390 | * message has has the capability @cap in the user namespace @user_ns. | ||
1391 | */ | ||
1392 | bool netlink_ns_capable(const struct sk_buff *skb, | ||
1393 | struct user_namespace *user_ns, int cap) | ||
1394 | { | ||
1395 | return __netlink_ns_capable(&NETLINK_CB(skb), user_ns, cap); | ||
1396 | } | ||
1397 | EXPORT_SYMBOL(netlink_ns_capable); | ||
1398 | |||
1399 | /** | ||
1400 | * netlink_capable - Netlink global message capability test | ||
1401 | * @skb: socket buffer holding a netlink command from userspace | ||
1402 | * @cap: The capability to use | ||
1403 | * | ||
1404 | * Test to see if the opener of the socket we received the message | ||
1405 | * from had when the netlink socket was created and the sender of the | ||
1406 | * message has has the capability @cap in all user namespaces. | ||
1407 | */ | ||
1408 | bool netlink_capable(const struct sk_buff *skb, int cap) | ||
1409 | { | ||
1410 | return netlink_ns_capable(skb, &init_user_ns, cap); | ||
1411 | } | ||
1412 | EXPORT_SYMBOL(netlink_capable); | ||
1413 | |||
1414 | /** | ||
1415 | * netlink_net_capable - Netlink network namespace message capability test | ||
1416 | * @skb: socket buffer holding a netlink command from userspace | ||
1417 | * @cap: The capability to use | ||
1418 | * | ||
1419 | * Test to see if the opener of the socket we received the message | ||
1420 | * from had when the netlink socket was created and the sender of the | ||
1421 | * message has has the capability @cap over the network namespace of | ||
1422 | * the socket we received the message from. | ||
1423 | */ | ||
1424 | bool netlink_net_capable(const struct sk_buff *skb, int cap) | ||
1425 | { | ||
1426 | return netlink_ns_capable(skb, sock_net(skb->sk)->user_ns, cap); | ||
1427 | } | ||
1428 | EXPORT_SYMBOL(netlink_net_capable); | ||
1429 | |||
1430 | static inline int netlink_allowed(const struct socket *sock, unsigned int flag) | ||
1364 | { | 1431 | { |
1365 | return (nl_table[sock->sk->sk_protocol].flags & flag) || | 1432 | return (nl_table[sock->sk->sk_protocol].flags & flag) || |
1366 | ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN); | 1433 | ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN); |
@@ -1428,7 +1495,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, | |||
1428 | 1495 | ||
1429 | /* Only superuser is allowed to listen multicasts */ | 1496 | /* Only superuser is allowed to listen multicasts */ |
1430 | if (nladdr->nl_groups) { | 1497 | if (nladdr->nl_groups) { |
1431 | if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV)) | 1498 | if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV)) |
1432 | return -EPERM; | 1499 | return -EPERM; |
1433 | err = netlink_realloc_groups(sk); | 1500 | err = netlink_realloc_groups(sk); |
1434 | if (err) | 1501 | if (err) |
@@ -1490,7 +1557,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, | |||
1490 | return -EINVAL; | 1557 | return -EINVAL; |
1491 | 1558 | ||
1492 | if ((nladdr->nl_groups || nladdr->nl_pid) && | 1559 | if ((nladdr->nl_groups || nladdr->nl_pid) && |
1493 | !netlink_capable(sock, NL_CFG_F_NONROOT_SEND)) | 1560 | !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) |
1494 | return -EPERM; | 1561 | return -EPERM; |
1495 | 1562 | ||
1496 | if (!nlk->portid) | 1563 | if (!nlk->portid) |
@@ -2096,7 +2163,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, | |||
2096 | break; | 2163 | break; |
2097 | case NETLINK_ADD_MEMBERSHIP: | 2164 | case NETLINK_ADD_MEMBERSHIP: |
2098 | case NETLINK_DROP_MEMBERSHIP: { | 2165 | case NETLINK_DROP_MEMBERSHIP: { |
2099 | if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV)) | 2166 | if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV)) |
2100 | return -EPERM; | 2167 | return -EPERM; |
2101 | err = netlink_realloc_groups(sk); | 2168 | err = netlink_realloc_groups(sk); |
2102 | if (err) | 2169 | if (err) |
@@ -2228,6 +2295,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
2228 | struct sk_buff *skb; | 2295 | struct sk_buff *skb; |
2229 | int err; | 2296 | int err; |
2230 | struct scm_cookie scm; | 2297 | struct scm_cookie scm; |
2298 | u32 netlink_skb_flags = 0; | ||
2231 | 2299 | ||
2232 | if (msg->msg_flags&MSG_OOB) | 2300 | if (msg->msg_flags&MSG_OOB) |
2233 | return -EOPNOTSUPP; | 2301 | return -EOPNOTSUPP; |
@@ -2247,8 +2315,9 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
2247 | dst_group = ffs(addr->nl_groups); | 2315 | dst_group = ffs(addr->nl_groups); |
2248 | err = -EPERM; | 2316 | err = -EPERM; |
2249 | if ((dst_group || dst_portid) && | 2317 | if ((dst_group || dst_portid) && |
2250 | !netlink_capable(sock, NL_CFG_F_NONROOT_SEND)) | 2318 | !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) |
2251 | goto out; | 2319 | goto out; |
2320 | netlink_skb_flags |= NETLINK_SKB_DST; | ||
2252 | } else { | 2321 | } else { |
2253 | dst_portid = nlk->dst_portid; | 2322 | dst_portid = nlk->dst_portid; |
2254 | dst_group = nlk->dst_group; | 2323 | dst_group = nlk->dst_group; |
@@ -2278,6 +2347,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
2278 | NETLINK_CB(skb).portid = nlk->portid; | 2347 | NETLINK_CB(skb).portid = nlk->portid; |
2279 | NETLINK_CB(skb).dst_group = dst_group; | 2348 | NETLINK_CB(skb).dst_group = dst_group; |
2280 | NETLINK_CB(skb).creds = siocb->scm->creds; | 2349 | NETLINK_CB(skb).creds = siocb->scm->creds; |
2350 | NETLINK_CB(skb).flags = netlink_skb_flags; | ||
2281 | 2351 | ||
2282 | err = -EFAULT; | 2352 | err = -EFAULT; |
2283 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | 2353 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { |