diff options
Diffstat (limited to 'net/ax25/ax25_uid.c')
| -rw-r--r-- | net/ax25/ax25_uid.c | 126 |
1 files changed, 60 insertions, 66 deletions
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c index cea6b7d1972..71c4badbc80 100644 --- a/net/ax25/ax25_uid.c +++ b/net/ax25/ax25_uid.c @@ -6,17 +6,19 @@ * * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ + +#include <linux/capability.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> #include <linux/net.h> #include <linux/spinlock.h> +#include <linux/slab.h> #include <net/ax25.h> #include <linux/inet.h> #include <linux/netdevice.h> @@ -24,16 +26,17 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> +#include <linux/list.h> #include <linux/notifier.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/stat.h> #include <linux/netfilter.h> #include <linux/sysctl.h> +#include <linux/export.h> #include <net/ip.h> #include <net/arp.h> @@ -41,40 +44,45 @@ * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines. */ -static ax25_uid_assoc *ax25_uid_list; +static HLIST_HEAD(ax25_uid_list); static DEFINE_RWLOCK(ax25_uid_lock); -int ax25_uid_policy = 0; +int ax25_uid_policy; + +EXPORT_SYMBOL(ax25_uid_policy); -ax25_address *ax25_findbyuid(uid_t uid) +ax25_uid_assoc *ax25_findbyuid(kuid_t uid) { - ax25_uid_assoc *ax25_uid; - ax25_address *res = NULL; + ax25_uid_assoc *ax25_uid, *res = NULL; read_lock(&ax25_uid_lock); - for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { - if (ax25_uid->uid == uid) { - res = &ax25_uid->call; + ax25_uid_for_each(ax25_uid, &ax25_uid_list) { + if (uid_eq(ax25_uid->uid, uid)) { + ax25_uid_hold(ax25_uid); + res = ax25_uid; break; } } read_unlock(&ax25_uid_lock); - return NULL; + return res; } +EXPORT_SYMBOL(ax25_findbyuid); + int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) { - ax25_uid_assoc *s, *ax25_uid; + ax25_uid_assoc *ax25_uid; + ax25_uid_assoc *user; unsigned long res; switch (cmd) { case SIOCAX25GETUID: res = -ENOENT; read_lock(&ax25_uid_lock); - for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { + ax25_uid_for_each(ax25_uid, &ax25_uid_list) { if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { - res = ax25_uid->uid; + res = from_kuid_munged(current_user_ns(), ax25_uid->uid); break; } } @@ -83,57 +91,52 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) return res; case SIOCAX25ADDUID: + { + kuid_t sax25_kuid; if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (ax25_findbyuid(sax->sax25_uid)) + sax25_kuid = make_kuid(current_user_ns(), sax->sax25_uid); + if (!uid_valid(sax25_kuid)) + return -EINVAL; + user = ax25_findbyuid(sax25_kuid); + if (user) { + ax25_uid_put(user); return -EEXIST; + } if (sax->sax25_uid == 0) return -EINVAL; if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL) return -ENOMEM; - ax25_uid->uid = sax->sax25_uid; + atomic_set(&ax25_uid->refcount, 1); + ax25_uid->uid = sax25_kuid; ax25_uid->call = sax->sax25_call; write_lock(&ax25_uid_lock); - ax25_uid->next = ax25_uid_list; - ax25_uid_list = ax25_uid; + hlist_add_head(&ax25_uid->uid_node, &ax25_uid_list); write_unlock(&ax25_uid_lock); return 0; - + } case SIOCAX25DELUID: if (!capable(CAP_NET_ADMIN)) return -EPERM; + ax25_uid = NULL; write_lock(&ax25_uid_lock); - for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { - if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { + ax25_uid_for_each(ax25_uid, &ax25_uid_list) { + if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) break; - } } if (ax25_uid == NULL) { write_unlock(&ax25_uid_lock); return -ENOENT; } - if ((s = ax25_uid_list) == ax25_uid) { - ax25_uid_list = s->next; - write_unlock(&ax25_uid_lock); - kfree(ax25_uid); - return 0; - } - while (s != NULL && s->next != NULL) { - if (s->next == ax25_uid) { - s->next = ax25_uid->next; - write_unlock(&ax25_uid_lock); - kfree(ax25_uid); - return 0; - } - s = s->next; - } + hlist_del_init(&ax25_uid->uid_node); + ax25_uid_put(ax25_uid); write_unlock(&ax25_uid_lock); - return -ENOENT; + return 0; default: return -EINVAL; @@ -145,48 +148,41 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) #ifdef CONFIG_PROC_FS static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(ax25_uid_lock) { - struct ax25_uid_assoc *pt; - int i = 1; - read_lock(&ax25_uid_lock); - if (*pos == 0) - return SEQ_START_TOKEN; - - for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { - if (i == *pos) - return pt; - ++i; - } - return NULL; + return seq_hlist_start_head(&ax25_uid_list, *pos); } static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - ++*pos; - return (v == SEQ_START_TOKEN) ? ax25_uid_list : - ((struct ax25_uid_assoc *) v)->next; + return seq_hlist_next(v, &ax25_uid_list, pos); } static void ax25_uid_seq_stop(struct seq_file *seq, void *v) + __releases(ax25_uid_lock) { read_unlock(&ax25_uid_lock); } static int ax25_uid_seq_show(struct seq_file *seq, void *v) { + char buf[11]; + if (v == SEQ_START_TOKEN) seq_printf(seq, "Policy: %d\n", ax25_uid_policy); else { - struct ax25_uid_assoc *pt = v; - + struct ax25_uid_assoc *pt; - seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call)); + pt = hlist_entry(v, struct ax25_uid_assoc, uid_node); + seq_printf(seq, "%6d %s\n", + from_kuid_munged(seq_user_ns(seq), pt->uid), + ax2asc(buf, &pt->call)); } return 0; } -static struct seq_operations ax25_uid_seqops = { +static const struct seq_operations ax25_uid_seqops = { .start = ax25_uid_seq_start, .next = ax25_uid_seq_next, .stop = ax25_uid_seq_stop, @@ -198,7 +194,7 @@ static int ax25_uid_info_open(struct inode *inode, struct file *file) return seq_open(file, &ax25_uid_seqops); } -struct file_operations ax25_uid_fops = { +const struct file_operations ax25_uid_fops = { .owner = THIS_MODULE, .open = ax25_uid_info_open, .read = seq_read, @@ -213,16 +209,14 @@ struct file_operations ax25_uid_fops = { */ void __exit ax25_uid_free(void) { - ax25_uid_assoc *s, *ax25_uid; + ax25_uid_assoc *ax25_uid; write_lock(&ax25_uid_lock); - ax25_uid = ax25_uid_list; - while (ax25_uid != NULL) { - s = ax25_uid; - ax25_uid = ax25_uid->next; - - kfree(s); +again: + ax25_uid_for_each(ax25_uid, &ax25_uid_list) { + hlist_del_init(&ax25_uid->uid_node); + ax25_uid_put(ax25_uid); + goto again; } - ax25_uid_list = NULL; write_unlock(&ax25_uid_lock); } |
