diff options
| -rw-r--r-- | net/netlink/af_netlink.c | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 444ed223ee43..58d4ca42ac32 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -60,21 +60,24 @@ | |||
| 60 | #include <net/scm.h> | 60 | #include <net/scm.h> |
| 61 | 61 | ||
| 62 | #define Nprintk(a...) | 62 | #define Nprintk(a...) |
| 63 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) | ||
| 63 | 64 | ||
| 64 | struct netlink_sock { | 65 | struct netlink_sock { |
| 65 | /* struct sock has to be the first member of netlink_sock */ | 66 | /* struct sock has to be the first member of netlink_sock */ |
| 66 | struct sock sk; | 67 | struct sock sk; |
| 67 | u32 pid; | 68 | u32 pid; |
| 68 | unsigned int groups; | ||
| 69 | u32 dst_pid; | 69 | u32 dst_pid; |
| 70 | u32 dst_group; | 70 | u32 dst_group; |
| 71 | u32 flags; | ||
| 72 | u32 subscriptions; | ||
| 73 | u32 ngroups; | ||
| 74 | unsigned long *groups; | ||
| 71 | unsigned long state; | 75 | unsigned long state; |
| 72 | wait_queue_head_t wait; | 76 | wait_queue_head_t wait; |
| 73 | struct netlink_callback *cb; | 77 | struct netlink_callback *cb; |
| 74 | spinlock_t cb_lock; | 78 | spinlock_t cb_lock; |
| 75 | void (*data_ready)(struct sock *sk, int bytes); | 79 | void (*data_ready)(struct sock *sk, int bytes); |
| 76 | struct module *module; | 80 | struct module *module; |
| 77 | u32 flags; | ||
| 78 | }; | 81 | }; |
| 79 | 82 | ||
| 80 | #define NETLINK_KERNEL_SOCKET 0x1 | 83 | #define NETLINK_KERNEL_SOCKET 0x1 |
| @@ -101,6 +104,7 @@ struct netlink_table { | |||
| 101 | struct nl_pid_hash hash; | 104 | struct nl_pid_hash hash; |
| 102 | struct hlist_head mc_list; | 105 | struct hlist_head mc_list; |
| 103 | unsigned int nl_nonroot; | 106 | unsigned int nl_nonroot; |
| 107 | unsigned int groups; | ||
| 104 | struct module *module; | 108 | struct module *module; |
| 105 | int registered; | 109 | int registered; |
| 106 | }; | 110 | }; |
| @@ -138,6 +142,7 @@ static void netlink_sock_destruct(struct sock *sk) | |||
| 138 | BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); | 142 | BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); |
| 139 | BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); | 143 | BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); |
| 140 | BUG_TRAP(!nlk_sk(sk)->cb); | 144 | BUG_TRAP(!nlk_sk(sk)->cb); |
| 145 | BUG_TRAP(!nlk_sk(sk)->groups); | ||
| 141 | } | 146 | } |
| 142 | 147 | ||
| 143 | /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP. | 148 | /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP. |
| @@ -333,7 +338,7 @@ static void netlink_remove(struct sock *sk) | |||
| 333 | netlink_table_grab(); | 338 | netlink_table_grab(); |
| 334 | if (sk_del_node_init(sk)) | 339 | if (sk_del_node_init(sk)) |
| 335 | nl_table[sk->sk_protocol].hash.entries--; | 340 | nl_table[sk->sk_protocol].hash.entries--; |
| 336 | if (nlk_sk(sk)->groups) | 341 | if (nlk_sk(sk)->subscriptions) |
| 337 | __sk_del_bind_node(sk); | 342 | __sk_del_bind_node(sk); |
| 338 | netlink_table_ungrab(); | 343 | netlink_table_ungrab(); |
| 339 | } | 344 | } |
| @@ -369,6 +374,8 @@ static int __netlink_create(struct socket *sock, int protocol) | |||
| 369 | static int netlink_create(struct socket *sock, int protocol) | 374 | static int netlink_create(struct socket *sock, int protocol) |
| 370 | { | 375 | { |
| 371 | struct module *module = NULL; | 376 | struct module *module = NULL; |
| 377 | struct netlink_sock *nlk; | ||
| 378 | unsigned int groups; | ||
| 372 | int err = 0; | 379 | int err = 0; |
| 373 | 380 | ||
| 374 | sock->state = SS_UNCONNECTED; | 381 | sock->state = SS_UNCONNECTED; |
| @@ -392,15 +399,23 @@ static int netlink_create(struct socket *sock, int protocol) | |||
| 392 | module = nl_table[protocol].module; | 399 | module = nl_table[protocol].module; |
| 393 | else | 400 | else |
| 394 | err = -EPROTONOSUPPORT; | 401 | err = -EPROTONOSUPPORT; |
| 402 | groups = nl_table[protocol].groups; | ||
| 395 | netlink_unlock_table(); | 403 | netlink_unlock_table(); |
| 396 | 404 | ||
| 397 | if (err) | 405 | if (err || (err = __netlink_create(sock, protocol) < 0)) |
| 398 | goto out; | 406 | goto out_module; |
| 407 | |||
| 408 | nlk = nlk_sk(sock->sk); | ||
| 399 | 409 | ||
| 400 | if ((err = __netlink_create(sock, protocol) < 0)) | 410 | nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL); |
| 411 | if (nlk->groups == NULL) { | ||
| 412 | err = -ENOMEM; | ||
| 401 | goto out_module; | 413 | goto out_module; |
| 414 | } | ||
| 415 | memset(nlk->groups, 0, NLGRPSZ(groups)); | ||
| 416 | nlk->ngroups = groups; | ||
| 402 | 417 | ||
| 403 | nlk_sk(sock->sk)->module = module; | 418 | nlk->module = module; |
| 404 | out: | 419 | out: |
| 405 | return err; | 420 | return err; |
| 406 | 421 | ||
| @@ -437,7 +452,7 @@ static int netlink_release(struct socket *sock) | |||
| 437 | 452 | ||
| 438 | skb_queue_purge(&sk->sk_write_queue); | 453 | skb_queue_purge(&sk->sk_write_queue); |
| 439 | 454 | ||
| 440 | if (nlk->pid && !nlk->groups) { | 455 | if (nlk->pid && !nlk->subscriptions) { |
| 441 | struct netlink_notify n = { | 456 | struct netlink_notify n = { |
| 442 | .protocol = sk->sk_protocol, | 457 | .protocol = sk->sk_protocol, |
| 443 | .pid = nlk->pid, | 458 | .pid = nlk->pid, |
| @@ -455,6 +470,9 @@ static int netlink_release(struct socket *sock) | |||
| 455 | netlink_table_ungrab(); | 470 | netlink_table_ungrab(); |
| 456 | } | 471 | } |
| 457 | 472 | ||
| 473 | kfree(nlk->groups); | ||
| 474 | nlk->groups = NULL; | ||
| 475 | |||
| 458 | sock_put(sk); | 476 | sock_put(sk); |
| 459 | return 0; | 477 | return 0; |
| 460 | } | 478 | } |
| @@ -503,6 +521,18 @@ static inline int netlink_capable(struct socket *sock, unsigned int flag) | |||
| 503 | capable(CAP_NET_ADMIN); | 521 | capable(CAP_NET_ADMIN); |
| 504 | } | 522 | } |
| 505 | 523 | ||
| 524 | static void | ||
| 525 | netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions) | ||
| 526 | { | ||
| 527 | struct netlink_sock *nlk = nlk_sk(sk); | ||
| 528 | |||
| 529 | if (nlk->subscriptions && !subscriptions) | ||
| 530 | __sk_del_bind_node(sk); | ||
| 531 | else if (!nlk->subscriptions && subscriptions) | ||
| 532 | sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); | ||
| 533 | nlk->subscriptions = subscriptions; | ||
| 534 | } | ||
| 535 | |||
| 506 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | 536 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) |
| 507 | { | 537 | { |
| 508 | struct sock *sk = sock->sk; | 538 | struct sock *sk = sock->sk; |
| @@ -528,15 +558,14 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len | |||
| 528 | return err; | 558 | return err; |
| 529 | } | 559 | } |
| 530 | 560 | ||
| 531 | if (!nladdr->nl_groups && !nlk->groups) | 561 | if (!nladdr->nl_groups && !(u32)nlk->groups[0]) |
| 532 | return 0; | 562 | return 0; |
| 533 | 563 | ||
| 534 | netlink_table_grab(); | 564 | netlink_table_grab(); |
| 535 | if (nlk->groups && !nladdr->nl_groups) | 565 | netlink_update_subscriptions(sk, nlk->subscriptions + |
| 536 | __sk_del_bind_node(sk); | 566 | hweight32(nladdr->nl_groups) - |
| 537 | else if (!nlk->groups && nladdr->nl_groups) | 567 | hweight32(nlk->groups[0])); |
| 538 | sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); | 568 | nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; |
| 539 | nlk->groups = nladdr->nl_groups; | ||
| 540 | netlink_table_ungrab(); | 569 | netlink_table_ungrab(); |
| 541 | 570 | ||
| 542 | return 0; | 571 | return 0; |
| @@ -590,7 +619,7 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr | |||
| 590 | nladdr->nl_groups = netlink_group_mask(nlk->dst_group); | 619 | nladdr->nl_groups = netlink_group_mask(nlk->dst_group); |
| 591 | } else { | 620 | } else { |
| 592 | nladdr->nl_pid = nlk->pid; | 621 | nladdr->nl_pid = nlk->pid; |
| 593 | nladdr->nl_groups = nlk->groups; | 622 | nladdr->nl_groups = nlk->groups[0]; |
| 594 | } | 623 | } |
| 595 | return 0; | 624 | return 0; |
| 596 | } | 625 | } |
| @@ -791,7 +820,8 @@ static inline int do_one_broadcast(struct sock *sk, | |||
| 791 | if (p->exclude_sk == sk) | 820 | if (p->exclude_sk == sk) |
| 792 | goto out; | 821 | goto out; |
| 793 | 822 | ||
| 794 | if (nlk->pid == p->pid || !(nlk->groups & netlink_group_mask(p->group))) | 823 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || |
| 824 | !test_bit(p->group - 1, nlk->groups)) | ||
| 795 | goto out; | 825 | goto out; |
| 796 | 826 | ||
| 797 | if (p->failure) { | 827 | if (p->failure) { |
| @@ -887,7 +917,8 @@ static inline int do_one_set_err(struct sock *sk, | |||
| 887 | if (sk == p->exclude_sk) | 917 | if (sk == p->exclude_sk) |
| 888 | goto out; | 918 | goto out; |
| 889 | 919 | ||
| 890 | if (nlk->pid == p->pid || !(nlk->groups & netlink_group_mask(p->group))) | 920 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || |
| 921 | !test_bit(p->group - 1, nlk->groups)) | ||
| 891 | goto out; | 922 | goto out; |
| 892 | 923 | ||
| 893 | sk->sk_err = p->code; | 924 | sk->sk_err = p->code; |
| @@ -1112,6 +1143,7 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct | |||
| 1112 | nlk->flags |= NETLINK_KERNEL_SOCKET; | 1143 | nlk->flags |= NETLINK_KERNEL_SOCKET; |
| 1113 | 1144 | ||
| 1114 | netlink_table_grab(); | 1145 | netlink_table_grab(); |
| 1146 | nl_table[unit].groups = 32; | ||
| 1115 | nl_table[unit].module = module; | 1147 | nl_table[unit].module = module; |
| 1116 | nl_table[unit].registered = 1; | 1148 | nl_table[unit].registered = 1; |
| 1117 | netlink_table_ungrab(); | 1149 | netlink_table_ungrab(); |
| @@ -1358,7 +1390,8 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
| 1358 | s, | 1390 | s, |
| 1359 | s->sk_protocol, | 1391 | s->sk_protocol, |
| 1360 | nlk->pid, | 1392 | nlk->pid, |
| 1361 | nlk->groups, | 1393 | nlk->flags & NETLINK_KERNEL_SOCKET ? |
| 1394 | 0 : (unsigned int)nlk->groups[0], | ||
| 1362 | atomic_read(&s->sk_rmem_alloc), | 1395 | atomic_read(&s->sk_rmem_alloc), |
| 1363 | atomic_read(&s->sk_wmem_alloc), | 1396 | atomic_read(&s->sk_wmem_alloc), |
| 1364 | nlk->cb, | 1397 | nlk->cb, |
