mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
b67bfe0d42
I'm not sure why, but the hlist for each entry iterators were conceived list_for_each_entry(pos, head, member) The hlist ones were greedy and wanted an extra parameter: hlist_for_each_entry(tpos, pos, head, member) Why did they need an extra pos parameter? I'm not quite sure. Not only they don't really need it, it also prevents the iterator from looking exactly like the list iterator, which is unfortunate. Besides the semantic patch, there was some manual work required: - Fix up the actual hlist iterators in linux/list.h - Fix up the declaration of other iterators based on the hlist ones. - A very small amount of places were using the 'node' parameter, this was modified to use 'obj->member' instead. - Coccinelle didn't handle the hlist_for_each_entry_safe iterator properly, so those had to be fixed up manually. The semantic patch which is mostly the work of Peter Senna Tschudin is here: @@ iterator name hlist_for_each_entry, hlist_for_each_entry_continue, hlist_for_each_entry_from, hlist_for_each_entry_rcu, hlist_for_each_entry_rcu_bh, hlist_for_each_entry_continue_rcu_bh, for_each_busy_worker, ax25_uid_for_each, ax25_for_each, inet_bind_bucket_for_each, sctp_for_each_hentry, sk_for_each, sk_for_each_rcu, sk_for_each_from, sk_for_each_safe, sk_for_each_bound, hlist_for_each_entry_safe, hlist_for_each_entry_continue_rcu, nr_neigh_for_each, nr_neigh_for_each_safe, nr_node_for_each, nr_node_for_each_safe, for_each_gfn_indirect_valid_sp, for_each_gfn_sp, for_each_host; type T; expression a,c,d,e; identifier b; statement S; @@ -T b; <+... when != b ( hlist_for_each_entry(a, - b, c, d) S | hlist_for_each_entry_continue(a, - b, c) S | hlist_for_each_entry_from(a, - b, c) S | hlist_for_each_entry_rcu(a, - b, c, d) S | hlist_for_each_entry_rcu_bh(a, - b, c, d) S | hlist_for_each_entry_continue_rcu_bh(a, - b, c) S | for_each_busy_worker(a, c, - b, d) S | ax25_uid_for_each(a, - b, c) S | ax25_for_each(a, - b, c) S | inet_bind_bucket_for_each(a, - b, c) S | sctp_for_each_hentry(a, - b, c) S | sk_for_each(a, - b, c) S | sk_for_each_rcu(a, - b, c) S | sk_for_each_from -(a, b) +(a) S + sk_for_each_from(a) S | sk_for_each_safe(a, - b, c, d) S | sk_for_each_bound(a, - b, c) S | hlist_for_each_entry_safe(a, - b, c, d, e) S | hlist_for_each_entry_continue_rcu(a, - b, c) S | nr_neigh_for_each(a, - b, c) S | nr_neigh_for_each_safe(a, - b, c, d) S | nr_node_for_each(a, - b, c) S | nr_node_for_each_safe(a, - b, c, d) S | - for_each_gfn_sp(a, c, d, b) S + for_each_gfn_sp(a, c, d) S | - for_each_gfn_indirect_valid_sp(a, c, d, b) S + for_each_gfn_indirect_valid_sp(a, c, d) S | for_each_host(a, - b, c) S | for_each_host_safe(a, - b, c, d) S | for_each_mesh_entry(a, - b, c, d) S ) ...+> [akpm@linux-foundation.org: drop bogus change from net/ipv4/raw.c] [akpm@linux-foundation.org: drop bogus hunk from net/ipv6/raw.c] [akpm@linux-foundation.org: checkpatch fixes] [akpm@linux-foundation.org: fix warnings] [akpm@linux-foudnation.org: redo intrusive kvm changes] Tested-by: Peter Senna Tschudin <peter.senna@gmail.com> Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Signed-off-by: Sasha Levin <sasha.levin@oracle.com> Cc: Wu Fengguang <fengguang.wu@intel.com> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: Gleb Natapov <gleb@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
223 lines
4.8 KiB
C
223 lines
4.8 KiB
C
/*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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/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>
|
|
#include <linux/if_arp.h>
|
|
#include <linux/skbuff.h>
|
|
#include <net/sock.h>
|
|
#include <asm/uaccess.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>
|
|
|
|
/*
|
|
* Callsign/UID mapper. This is in kernel space for security on multi-amateur machines.
|
|
*/
|
|
|
|
static HLIST_HEAD(ax25_uid_list);
|
|
static DEFINE_RWLOCK(ax25_uid_lock);
|
|
|
|
int ax25_uid_policy;
|
|
|
|
EXPORT_SYMBOL(ax25_uid_policy);
|
|
|
|
ax25_uid_assoc *ax25_findbyuid(kuid_t uid)
|
|
{
|
|
ax25_uid_assoc *ax25_uid, *res = NULL;
|
|
|
|
read_lock(&ax25_uid_lock);
|
|
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 res;
|
|
}
|
|
|
|
EXPORT_SYMBOL(ax25_findbyuid);
|
|
|
|
int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
|
|
{
|
|
ax25_uid_assoc *ax25_uid;
|
|
ax25_uid_assoc *user;
|
|
unsigned long res;
|
|
|
|
switch (cmd) {
|
|
case SIOCAX25GETUID:
|
|
res = -ENOENT;
|
|
read_lock(&ax25_uid_lock);
|
|
ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
|
|
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
|
|
res = from_kuid_munged(current_user_ns(), ax25_uid->uid);
|
|
break;
|
|
}
|
|
}
|
|
read_unlock(&ax25_uid_lock);
|
|
|
|
return res;
|
|
|
|
case SIOCAX25ADDUID:
|
|
{
|
|
kuid_t sax25_kuid;
|
|
if (!capable(CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
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;
|
|
|
|
atomic_set(&ax25_uid->refcount, 1);
|
|
ax25_uid->uid = sax25_kuid;
|
|
ax25_uid->call = sax->sax25_call;
|
|
|
|
write_lock(&ax25_uid_lock);
|
|
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);
|
|
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;
|
|
}
|
|
hlist_del_init(&ax25_uid->uid_node);
|
|
ax25_uid_put(ax25_uid);
|
|
write_unlock(&ax25_uid_lock);
|
|
|
|
return 0;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return -EINVAL; /*NOTREACHED */
|
|
}
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
|
|
static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
|
|
__acquires(ax25_uid_lock)
|
|
{
|
|
read_lock(&ax25_uid_lock);
|
|
return seq_hlist_start_head(&ax25_uid_list, *pos);
|
|
}
|
|
|
|
static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|
{
|
|
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;
|
|
|
|
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 const struct seq_operations ax25_uid_seqops = {
|
|
.start = ax25_uid_seq_start,
|
|
.next = ax25_uid_seq_next,
|
|
.stop = ax25_uid_seq_stop,
|
|
.show = ax25_uid_seq_show,
|
|
};
|
|
|
|
static int ax25_uid_info_open(struct inode *inode, struct file *file)
|
|
{
|
|
return seq_open(file, &ax25_uid_seqops);
|
|
}
|
|
|
|
const struct file_operations ax25_uid_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = ax25_uid_info_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = seq_release,
|
|
};
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Free all memory associated with UID/Callsign structures.
|
|
*/
|
|
void __exit ax25_uid_free(void)
|
|
{
|
|
ax25_uid_assoc *ax25_uid;
|
|
|
|
write_lock(&ax25_uid_lock);
|
|
again:
|
|
ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
|
|
hlist_del_init(&ax25_uid->uid_node);
|
|
ax25_uid_put(ax25_uid);
|
|
goto again;
|
|
}
|
|
write_unlock(&ax25_uid_lock);
|
|
}
|