diff options
Diffstat (limited to 'net')
-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, |