aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink/af_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r--net/netlink/af_netlink.c59
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;
420out: 409out:
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
526static 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
537static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) 549static 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,