diff options
Diffstat (limited to 'net/netlink/af_netlink.c')
| -rw-r--r-- | net/netlink/af_netlink.c | 59 |
1 files changed, 41 insertions, 18 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 62435ffc6184..a64e1d5ce3ca 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -398,24 +398,13 @@ static int netlink_create(struct socket *sock, int protocol) | |||
| 398 | if (nl_table[protocol].registered && | 398 | if (nl_table[protocol].registered && |
| 399 | try_module_get(nl_table[protocol].module)) | 399 | try_module_get(nl_table[protocol].module)) |
| 400 | module = nl_table[protocol].module; | 400 | module = nl_table[protocol].module; |
| 401 | else | ||
| 402 | err = -EPROTONOSUPPORT; | ||
| 403 | groups = nl_table[protocol].groups; | 401 | groups = nl_table[protocol].groups; |
| 404 | netlink_unlock_table(); | 402 | netlink_unlock_table(); |
| 405 | 403 | ||
| 406 | if (err || (err = __netlink_create(sock, protocol) < 0)) | 404 | if ((err = __netlink_create(sock, protocol) < 0)) |
| 407 | goto out_module; | 405 | goto out_module; |
| 408 | 406 | ||
| 409 | nlk = nlk_sk(sock->sk); | 407 | nlk = nlk_sk(sock->sk); |
| 410 | |||
| 411 | nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL); | ||
| 412 | if (nlk->groups == NULL) { | ||
| 413 | err = -ENOMEM; | ||
| 414 | goto out_module; | ||
| 415 | } | ||
| 416 | memset(nlk->groups, 0, NLGRPSZ(groups)); | ||
| 417 | nlk->ngroups = groups; | ||
| 418 | |||
| 419 | nlk->module = module; | 408 | nlk->module = module; |
| 420 | out: | 409 | out: |
| 421 | return err; | 410 | return err; |
| @@ -534,6 +523,29 @@ netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions) | |||
| 534 | nlk->subscriptions = subscriptions; | 523 | nlk->subscriptions = subscriptions; |
| 535 | } | 524 | } |
| 536 | 525 | ||
| 526 | static int netlink_alloc_groups(struct sock *sk) | ||
| 527 | { | ||
| 528 | struct netlink_sock *nlk = nlk_sk(sk); | ||
| 529 | unsigned int groups; | ||
| 530 | int err = 0; | ||
| 531 | |||
| 532 | netlink_lock_table(); | ||
| 533 | groups = nl_table[sk->sk_protocol].groups; | ||
| 534 | if (!nl_table[sk->sk_protocol].registered) | ||
| 535 | err = -ENOENT; | ||
| 536 | netlink_unlock_table(); | ||
| 537 | |||
| 538 | if (err) | ||
| 539 | return err; | ||
| 540 | |||
| 541 | nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL); | ||
| 542 | if (nlk->groups == NULL) | ||
| 543 | return -ENOMEM; | ||
| 544 | memset(nlk->groups, 0, NLGRPSZ(groups)); | ||
| 545 | nlk->ngroups = groups; | ||
| 546 | return 0; | ||
| 547 | } | ||
| 548 | |||
| 537 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | 549 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) |
| 538 | { | 550 | { |
| 539 | struct sock *sk = sock->sk; | 551 | struct sock *sk = sock->sk; |
| @@ -545,8 +557,15 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len | |||
| 545 | return -EINVAL; | 557 | return -EINVAL; |
| 546 | 558 | ||
| 547 | /* Only superuser is allowed to listen multicasts */ | 559 | /* Only superuser is allowed to listen multicasts */ |
| 548 | if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_RECV)) | 560 | if (nladdr->nl_groups) { |
| 549 | return -EPERM; | 561 | if (!netlink_capable(sock, NL_NONROOT_RECV)) |
| 562 | return -EPERM; | ||
| 563 | if (nlk->groups == NULL) { | ||
| 564 | err = netlink_alloc_groups(sk); | ||
| 565 | if (err) | ||
| 566 | return err; | ||
| 567 | } | ||
| 568 | } | ||
| 550 | 569 | ||
| 551 | if (nlk->pid) { | 570 | if (nlk->pid) { |
| 552 | if (nladdr->nl_pid != nlk->pid) | 571 | if (nladdr->nl_pid != nlk->pid) |
| @@ -559,7 +578,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len | |||
| 559 | return err; | 578 | return err; |
| 560 | } | 579 | } |
| 561 | 580 | ||
| 562 | if (!nladdr->nl_groups && !(u32)nlk->groups[0]) | 581 | if (!nladdr->nl_groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) |
| 563 | return 0; | 582 | return 0; |
| 564 | 583 | ||
| 565 | netlink_table_grab(); | 584 | netlink_table_grab(); |
| @@ -620,7 +639,7 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr | |||
| 620 | nladdr->nl_groups = netlink_group_mask(nlk->dst_group); | 639 | nladdr->nl_groups = netlink_group_mask(nlk->dst_group); |
| 621 | } else { | 640 | } else { |
| 622 | nladdr->nl_pid = nlk->pid; | 641 | nladdr->nl_pid = nlk->pid; |
| 623 | nladdr->nl_groups = nlk->groups[0]; | 642 | nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0; |
| 624 | } | 643 | } |
| 625 | return 0; | 644 | return 0; |
| 626 | } | 645 | } |
| @@ -976,6 +995,11 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, | |||
| 976 | 995 | ||
| 977 | if (!netlink_capable(sock, NL_NONROOT_RECV)) | 996 | if (!netlink_capable(sock, NL_NONROOT_RECV)) |
| 978 | return -EPERM; | 997 | return -EPERM; |
| 998 | if (nlk->groups == NULL) { | ||
| 999 | err = netlink_alloc_groups(sk); | ||
| 1000 | if (err) | ||
| 1001 | return err; | ||
| 1002 | } | ||
| 979 | if (!val || val - 1 >= nlk->ngroups) | 1003 | if (!val || val - 1 >= nlk->ngroups) |
| 980 | return -EINVAL; | 1004 | return -EINVAL; |
| 981 | netlink_table_grab(); | 1005 | netlink_table_grab(); |
| @@ -1483,8 +1507,7 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
| 1483 | s, | 1507 | s, |
| 1484 | s->sk_protocol, | 1508 | s->sk_protocol, |
| 1485 | nlk->pid, | 1509 | nlk->pid, |
| 1486 | nlk->flags & NETLINK_KERNEL_SOCKET ? | 1510 | nlk->groups ? (u32)nlk->groups[0] : 0, |
| 1487 | 0 : (unsigned int)nlk->groups[0], | ||
| 1488 | atomic_read(&s->sk_rmem_alloc), | 1511 | atomic_read(&s->sk_rmem_alloc), |
| 1489 | atomic_read(&s->sk_wmem_alloc), | 1512 | atomic_read(&s->sk_wmem_alloc), |
| 1490 | nlk->cb, | 1513 | nlk->cb, |
