aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2005-08-23 13:11:45 -0400
committerDavid S. Miller <davem@davemloft.net>2005-08-23 13:11:45 -0400
commit01d7dd0e9f8c5f1888619d2649c7da389232b408 (patch)
treeee4f22a33557bae4883eb2f4fb1359e97ac74186 /net
parent53b924b31fa53ac3007df3fef6870d5074a9adf8 (diff)
[AX25]: UID fixes
o Brown paperbag bug - ax25_findbyuid() was always returning a NULL pointer as the result. Breaks ROSE completly and AX.25 if UID policy set to deny. o While the list structure of AX.25's UID to callsign mapping table was properly protected by a spinlock, it's elements were not refcounted resulting in a race between removal and usage of an element. Signed-off-by: Ralf Baechle DL5RB <ralf@linux-mips.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ax25/af_ax25.c20
-rw-r--r--net/ax25/ax25_route.c12
-rw-r--r--net/ax25/ax25_uid.c83
-rw-r--r--net/netrom/af_netrom.c24
-rw-r--r--net/rose/af_rose.c20
5 files changed, 84 insertions, 75 deletions
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 7d8ecadba668..a5c94f11547c 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1002,7 +1002,8 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
1002 struct sock *sk = sock->sk; 1002 struct sock *sk = sock->sk;
1003 struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; 1003 struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
1004 ax25_dev *ax25_dev = NULL; 1004 ax25_dev *ax25_dev = NULL;
1005 ax25_address *call; 1005 ax25_uid_assoc *user;
1006 ax25_address call;
1006 ax25_cb *ax25; 1007 ax25_cb *ax25;
1007 int err = 0; 1008 int err = 0;
1008 1009
@@ -1021,9 +1022,15 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
1021 if (addr->fsa_ax25.sax25_family != AF_AX25) 1022 if (addr->fsa_ax25.sax25_family != AF_AX25)
1022 return -EINVAL; 1023 return -EINVAL;
1023 1024
1024 call = ax25_findbyuid(current->euid); 1025 user = ax25_findbyuid(current->euid);
1025 if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) { 1026 if (user) {
1026 return -EACCES; 1027 call = user->call;
1028 ax25_uid_put(user);
1029 } else {
1030 if (ax25_uid_policy && !capable(CAP_NET_ADMIN))
1031 return -EACCES;
1032
1033 call = addr->fsa_ax25.sax25_call;
1027 } 1034 }
1028 1035
1029 lock_sock(sk); 1036 lock_sock(sk);
@@ -1034,10 +1041,7 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
1034 goto out; 1041 goto out;
1035 } 1042 }
1036 1043
1037 if (call == NULL) 1044 ax25->source_addr = call;
1038 ax25->source_addr = addr->fsa_ax25.sax25_call;
1039 else
1040 ax25->source_addr = *call;
1041 1045
1042 /* 1046 /*
1043 * User already set interface with SO_BINDTODEVICE 1047 * User already set interface with SO_BINDTODEVICE
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 44b99b1ff9f8..c288526da4ce 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -422,8 +422,8 @@ static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
422 */ 422 */
423int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) 423int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
424{ 424{
425 ax25_uid_assoc *user;
425 ax25_route *ax25_rt; 426 ax25_route *ax25_rt;
426 ax25_address *call;
427 int err; 427 int err;
428 428
429 if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL) 429 if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL)
@@ -434,16 +434,18 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
434 goto put; 434 goto put;
435 } 435 }
436 436
437 if ((call = ax25_findbyuid(current->euid)) == NULL) { 437 user = ax25_findbyuid(current->euid);
438 if (user) {
439 ax25->source_addr = user->call;
440 ax25_uid_put(user);
441 } else {
438 if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) { 442 if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
439 err = -EPERM; 443 err = -EPERM;
440 goto put; 444 goto put;
441 } 445 }
442 call = (ax25_address *)ax25->ax25_dev->dev->dev_addr; 446 ax25->source_addr = *(ax25_address *)ax25->ax25_dev->dev->dev_addr;
443 } 447 }
444 448
445 ax25->source_addr = *call;
446
447 if (ax25_rt->digipeat != NULL) { 449 if (ax25_rt->digipeat != NULL) {
448 if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { 450 if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
449 err = -ENOMEM; 451 err = -ENOMEM;
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c
index cea6b7d19729..a8b3822f3ee4 100644
--- a/net/ax25/ax25_uid.c
+++ b/net/ax25/ax25_uid.c
@@ -28,6 +28,7 @@
28#include <linux/fcntl.h> 28#include <linux/fcntl.h>
29#include <linux/mm.h> 29#include <linux/mm.h>
30#include <linux/interrupt.h> 30#include <linux/interrupt.h>
31#include <linux/list.h>
31#include <linux/notifier.h> 32#include <linux/notifier.h>
32#include <linux/proc_fs.h> 33#include <linux/proc_fs.h>
33#include <linux/seq_file.h> 34#include <linux/seq_file.h>
@@ -41,38 +42,41 @@
41 * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines. 42 * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines.
42 */ 43 */
43 44
44static ax25_uid_assoc *ax25_uid_list; 45HLIST_HEAD(ax25_uid_list);
45static DEFINE_RWLOCK(ax25_uid_lock); 46static DEFINE_RWLOCK(ax25_uid_lock);
46 47
47int ax25_uid_policy = 0; 48int ax25_uid_policy = 0;
48 49
49ax25_address *ax25_findbyuid(uid_t uid) 50ax25_uid_assoc *ax25_findbyuid(uid_t uid)
50{ 51{
51 ax25_uid_assoc *ax25_uid; 52 ax25_uid_assoc *ax25_uid, *res = NULL;
52 ax25_address *res = NULL; 53 struct hlist_node *node;
53 54
54 read_lock(&ax25_uid_lock); 55 read_lock(&ax25_uid_lock);
55 for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { 56 ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
56 if (ax25_uid->uid == uid) { 57 if (ax25_uid->uid == uid) {
57 res = &ax25_uid->call; 58 ax25_uid_hold(ax25_uid);
59 res = ax25_uid;
58 break; 60 break;
59 } 61 }
60 } 62 }
61 read_unlock(&ax25_uid_lock); 63 read_unlock(&ax25_uid_lock);
62 64
63 return NULL; 65 return res;
64} 66}
65 67
66int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) 68int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
67{ 69{
68 ax25_uid_assoc *s, *ax25_uid; 70 ax25_uid_assoc *ax25_uid;
71 struct hlist_node *node;
72 ax25_uid_assoc *user;
69 unsigned long res; 73 unsigned long res;
70 74
71 switch (cmd) { 75 switch (cmd) {
72 case SIOCAX25GETUID: 76 case SIOCAX25GETUID:
73 res = -ENOENT; 77 res = -ENOENT;
74 read_lock(&ax25_uid_lock); 78 read_lock(&ax25_uid_lock);
75 for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { 79 ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
76 if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { 80 if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
77 res = ax25_uid->uid; 81 res = ax25_uid->uid;
78 break; 82 break;
@@ -85,19 +89,22 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
85 case SIOCAX25ADDUID: 89 case SIOCAX25ADDUID:
86 if (!capable(CAP_NET_ADMIN)) 90 if (!capable(CAP_NET_ADMIN))
87 return -EPERM; 91 return -EPERM;
88 if (ax25_findbyuid(sax->sax25_uid)) 92 user = ax25_findbyuid(sax->sax25_uid);
93 if (user) {
94 ax25_uid_put(user);
89 return -EEXIST; 95 return -EEXIST;
96 }
90 if (sax->sax25_uid == 0) 97 if (sax->sax25_uid == 0)
91 return -EINVAL; 98 return -EINVAL;
92 if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL) 99 if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
93 return -ENOMEM; 100 return -ENOMEM;
94 101
102 atomic_set(&ax25_uid->refcount, 1);
95 ax25_uid->uid = sax->sax25_uid; 103 ax25_uid->uid = sax->sax25_uid;
96 ax25_uid->call = sax->sax25_call; 104 ax25_uid->call = sax->sax25_call;
97 105
98 write_lock(&ax25_uid_lock); 106 write_lock(&ax25_uid_lock);
99 ax25_uid->next = ax25_uid_list; 107 hlist_add_head(&ax25_uid->uid_node, &ax25_uid_list);
100 ax25_uid_list = ax25_uid;
101 write_unlock(&ax25_uid_lock); 108 write_unlock(&ax25_uid_lock);
102 109
103 return 0; 110 return 0;
@@ -106,34 +113,21 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
106 if (!capable(CAP_NET_ADMIN)) 113 if (!capable(CAP_NET_ADMIN))
107 return -EPERM; 114 return -EPERM;
108 115
116 ax25_uid = NULL;
109 write_lock(&ax25_uid_lock); 117 write_lock(&ax25_uid_lock);
110 for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { 118 ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
111 if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { 119 if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
112 break; 120 break;
113 }
114 } 121 }
115 if (ax25_uid == NULL) { 122 if (ax25_uid == NULL) {
116 write_unlock(&ax25_uid_lock); 123 write_unlock(&ax25_uid_lock);
117 return -ENOENT; 124 return -ENOENT;
118 } 125 }
119 if ((s = ax25_uid_list) == ax25_uid) { 126 hlist_del_init(&ax25_uid->uid_node);
120 ax25_uid_list = s->next; 127 ax25_uid_put(ax25_uid);
121 write_unlock(&ax25_uid_lock);
122 kfree(ax25_uid);
123 return 0;
124 }
125 while (s != NULL && s->next != NULL) {
126 if (s->next == ax25_uid) {
127 s->next = ax25_uid->next;
128 write_unlock(&ax25_uid_lock);
129 kfree(ax25_uid);
130 return 0;
131 }
132 s = s->next;
133 }
134 write_unlock(&ax25_uid_lock); 128 write_unlock(&ax25_uid_lock);
135 129
136 return -ENOENT; 130 return 0;
137 131
138 default: 132 default:
139 return -EINVAL; 133 return -EINVAL;
@@ -147,13 +141,11 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
147static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) 141static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
148{ 142{
149 struct ax25_uid_assoc *pt; 143 struct ax25_uid_assoc *pt;
150 int i = 1; 144 struct hlist_node *node;
145 int i = 0;
151 146
152 read_lock(&ax25_uid_lock); 147 read_lock(&ax25_uid_lock);
153 if (*pos == 0) 148 ax25_uid_for_each(pt, node, &ax25_uid_list) {
154 return SEQ_START_TOKEN;
155
156 for (pt = ax25_uid_list; pt != NULL; pt = pt->next) {
157 if (i == *pos) 149 if (i == *pos)
158 return pt; 150 return pt;
159 ++i; 151 ++i;
@@ -164,8 +156,9 @@ static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
164static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) 156static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
165{ 157{
166 ++*pos; 158 ++*pos;
167 return (v == SEQ_START_TOKEN) ? ax25_uid_list : 159
168 ((struct ax25_uid_assoc *) v)->next; 160 return hlist_entry(((ax25_uid_assoc *)v)->uid_node.next,
161 ax25_uid_assoc, uid_node);
169} 162}
170 163
171static void ax25_uid_seq_stop(struct seq_file *seq, void *v) 164static void ax25_uid_seq_stop(struct seq_file *seq, void *v)
@@ -179,7 +172,6 @@ static int ax25_uid_seq_show(struct seq_file *seq, void *v)
179 seq_printf(seq, "Policy: %d\n", ax25_uid_policy); 172 seq_printf(seq, "Policy: %d\n", ax25_uid_policy);
180 else { 173 else {
181 struct ax25_uid_assoc *pt = v; 174 struct ax25_uid_assoc *pt = v;
182
183 175
184 seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call)); 176 seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call));
185 } 177 }
@@ -213,16 +205,13 @@ struct file_operations ax25_uid_fops = {
213 */ 205 */
214void __exit ax25_uid_free(void) 206void __exit ax25_uid_free(void)
215{ 207{
216 ax25_uid_assoc *s, *ax25_uid; 208 ax25_uid_assoc *ax25_uid;
209 struct hlist_node *node;
217 210
218 write_lock(&ax25_uid_lock); 211 write_lock(&ax25_uid_lock);
219 ax25_uid = ax25_uid_list; 212 ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
220 while (ax25_uid != NULL) { 213 hlist_del_init(&ax25_uid->uid_node);
221 s = ax25_uid; 214 ax25_uid_put(ax25_uid);
222 ax25_uid = ax25_uid->next;
223
224 kfree(s);
225 } 215 }
226 ax25_uid_list = NULL;
227 write_unlock(&ax25_uid_lock); 216 write_unlock(&ax25_uid_lock);
228} 217}
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 5385835e9267..162a85fed150 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -536,7 +536,8 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
536 struct nr_sock *nr = nr_sk(sk); 536 struct nr_sock *nr = nr_sk(sk);
537 struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; 537 struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
538 struct net_device *dev; 538 struct net_device *dev;
539 ax25_address *user, *source; 539 ax25_uid_assoc *user;
540 ax25_address *source;
540 541
541 lock_sock(sk); 542 lock_sock(sk);
542 if (!sock_flag(sk, SOCK_ZAPPED)) { 543 if (!sock_flag(sk, SOCK_ZAPPED)) {
@@ -575,16 +576,19 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
575 } else { 576 } else {
576 source = &addr->fsa_ax25.sax25_call; 577 source = &addr->fsa_ax25.sax25_call;
577 578
578 if ((user = ax25_findbyuid(current->euid)) == NULL) { 579 user = ax25_findbyuid(current->euid);
580 if (user) {
581 nr->user_addr = user->call;
582 ax25_uid_put(user);
583 } else {
579 if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) { 584 if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
580 release_sock(sk); 585 release_sock(sk);
581 dev_put(dev); 586 dev_put(dev);
582 return -EPERM; 587 return -EPERM;
583 } 588 }
584 user = source; 589 nr->user_addr = *source;
585 } 590 }
586 591
587 nr->user_addr = *user;
588 nr->source_addr = *source; 592 nr->source_addr = *source;
589 } 593 }
590 594
@@ -604,7 +608,8 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
604 struct sock *sk = sock->sk; 608 struct sock *sk = sock->sk;
605 struct nr_sock *nr = nr_sk(sk); 609 struct nr_sock *nr = nr_sk(sk);
606 struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr; 610 struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;
607 ax25_address *user, *source = NULL; 611 ax25_address *source = NULL;
612 ax25_uid_assoc *user;
608 struct net_device *dev; 613 struct net_device *dev;
609 614
610 lock_sock(sk); 615 lock_sock(sk);
@@ -645,16 +650,19 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
645 } 650 }
646 source = (ax25_address *)dev->dev_addr; 651 source = (ax25_address *)dev->dev_addr;
647 652
648 if ((user = ax25_findbyuid(current->euid)) == NULL) { 653 user = ax25_findbyuid(current->euid);
654 if (user) {
655 nr->user_addr = user->call;
656 ax25_uid_put(user);
657 } else {
649 if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) { 658 if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
650 dev_put(dev); 659 dev_put(dev);
651 release_sock(sk); 660 release_sock(sk);
652 return -EPERM; 661 return -EPERM;
653 } 662 }
654 user = source; 663 nr->user_addr = *source;
655 } 664 }
656 665
657 nr->user_addr = *user;
658 nr->source_addr = *source; 666 nr->source_addr = *source;
659 nr->device = dev; 667 nr->device = dev;
660 668
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 3fe7e562125a..5480caf8ccc2 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -626,7 +626,8 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
626 struct rose_sock *rose = rose_sk(sk); 626 struct rose_sock *rose = rose_sk(sk);
627 struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; 627 struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
628 struct net_device *dev; 628 struct net_device *dev;
629 ax25_address *user, *source; 629 ax25_address *source;
630 ax25_uid_assoc *user;
630 int n; 631 int n;
631 632
632 if (!sock_flag(sk, SOCK_ZAPPED)) 633 if (!sock_flag(sk, SOCK_ZAPPED))
@@ -651,14 +652,17 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
651 652
652 source = &addr->srose_call; 653 source = &addr->srose_call;
653 654
654 if ((user = ax25_findbyuid(current->euid)) == NULL) { 655 user = ax25_findbyuid(current->euid);
656 if (user) {
657 rose->source_call = user->call;
658 ax25_uid_put(user);
659 } else {
655 if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) 660 if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE))
656 return -EACCES; 661 return -EACCES;
657 user = source; 662 rose->source_call = *source;
658 } 663 }
659 664
660 rose->source_addr = addr->srose_addr; 665 rose->source_addr = addr->srose_addr;
661 rose->source_call = *user;
662 rose->device = dev; 666 rose->device = dev;
663 rose->source_ndigis = addr->srose_ndigis; 667 rose->source_ndigis = addr->srose_ndigis;
664 668
@@ -685,8 +689,8 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
685 struct rose_sock *rose = rose_sk(sk); 689 struct rose_sock *rose = rose_sk(sk);
686 struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; 690 struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
687 unsigned char cause, diagnostic; 691 unsigned char cause, diagnostic;
688 ax25_address *user;
689 struct net_device *dev; 692 struct net_device *dev;
693 ax25_uid_assoc *user;
690 int n; 694 int n;
691 695
692 if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { 696 if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
@@ -736,12 +740,14 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
736 if ((dev = rose_dev_first()) == NULL) 740 if ((dev = rose_dev_first()) == NULL)
737 return -ENETUNREACH; 741 return -ENETUNREACH;
738 742
739 if ((user = ax25_findbyuid(current->euid)) == NULL) 743 user = ax25_findbyuid(current->euid);
744 if (!user)
740 return -EINVAL; 745 return -EINVAL;
741 746
742 memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN); 747 memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN);
743 rose->source_call = *user; 748 rose->source_call = user->call;
744 rose->device = dev; 749 rose->device = dev;
750 ax25_uid_put(user);
745 751
746 rose_insert_socket(sk); /* Finish the bind */ 752 rose_insert_socket(sk); /* Finish the bind */
747 } 753 }