1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds *
41da177e4SLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
51da177e4SLinus Torvalds */
64fc268d2SRandy Dunlap
74fc268d2SRandy Dunlap #include <linux/capability.h>
81da177e4SLinus Torvalds #include <linux/errno.h>
91da177e4SLinus Torvalds #include <linux/types.h>
101da177e4SLinus Torvalds #include <linux/socket.h>
111da177e4SLinus Torvalds #include <linux/in.h>
121da177e4SLinus Torvalds #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/timer.h>
141da177e4SLinus Torvalds #include <linux/string.h>
151da177e4SLinus Torvalds #include <linux/sockios.h>
161da177e4SLinus Torvalds #include <linux/net.h>
171da177e4SLinus Torvalds #include <linux/spinlock.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
191da177e4SLinus Torvalds #include <net/ax25.h>
201da177e4SLinus Torvalds #include <linux/inet.h>
211da177e4SLinus Torvalds #include <linux/netdevice.h>
221da177e4SLinus Torvalds #include <linux/if_arp.h>
231da177e4SLinus Torvalds #include <linux/skbuff.h>
241da177e4SLinus Torvalds #include <net/sock.h>
257c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
261da177e4SLinus Torvalds #include <linux/fcntl.h>
271da177e4SLinus Torvalds #include <linux/mm.h>
281da177e4SLinus Torvalds #include <linux/interrupt.h>
2901d7dd0eSRalf Baechle #include <linux/list.h>
301da177e4SLinus Torvalds #include <linux/notifier.h>
311da177e4SLinus Torvalds #include <linux/proc_fs.h>
321da177e4SLinus Torvalds #include <linux/seq_file.h>
331da177e4SLinus Torvalds #include <linux/stat.h>
341da177e4SLinus Torvalds #include <linux/sysctl.h>
35bc3b2d7fSPaul Gortmaker #include <linux/export.h>
361da177e4SLinus Torvalds #include <net/ip.h>
371da177e4SLinus Torvalds #include <net/arp.h>
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds /*
401da177e4SLinus Torvalds * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines.
411da177e4SLinus Torvalds */
421da177e4SLinus Torvalds
43f16f3026SEric Dumazet static HLIST_HEAD(ax25_uid_list);
441da177e4SLinus Torvalds static DEFINE_RWLOCK(ax25_uid_lock);
451da177e4SLinus Torvalds
46f16f3026SEric Dumazet int ax25_uid_policy;
471da177e4SLinus Torvalds
4870868eacSRalf Baechle EXPORT_SYMBOL(ax25_uid_policy);
4970868eacSRalf Baechle
ax25_findbyuid(kuid_t uid)50d13fda85SEric W. Biederman ax25_uid_assoc *ax25_findbyuid(kuid_t uid)
511da177e4SLinus Torvalds {
5201d7dd0eSRalf Baechle ax25_uid_assoc *ax25_uid, *res = NULL;
531da177e4SLinus Torvalds
541da177e4SLinus Torvalds read_lock(&ax25_uid_lock);
55b67bfe0dSSasha Levin ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
56d13fda85SEric W. Biederman if (uid_eq(ax25_uid->uid, uid)) {
5701d7dd0eSRalf Baechle ax25_uid_hold(ax25_uid);
5801d7dd0eSRalf Baechle res = ax25_uid;
591da177e4SLinus Torvalds break;
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds read_unlock(&ax25_uid_lock);
631da177e4SLinus Torvalds
6401d7dd0eSRalf Baechle return res;
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds
6770868eacSRalf Baechle EXPORT_SYMBOL(ax25_findbyuid);
6870868eacSRalf Baechle
ax25_uid_ioctl(int cmd,struct sockaddr_ax25 * sax)691da177e4SLinus Torvalds int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
701da177e4SLinus Torvalds {
7101d7dd0eSRalf Baechle ax25_uid_assoc *ax25_uid;
7201d7dd0eSRalf Baechle ax25_uid_assoc *user;
731da177e4SLinus Torvalds unsigned long res;
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds switch (cmd) {
761da177e4SLinus Torvalds case SIOCAX25GETUID:
771da177e4SLinus Torvalds res = -ENOENT;
781da177e4SLinus Torvalds read_lock(&ax25_uid_lock);
79b67bfe0dSSasha Levin ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
801da177e4SLinus Torvalds if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
81d13fda85SEric W. Biederman res = from_kuid_munged(current_user_ns(), ax25_uid->uid);
821da177e4SLinus Torvalds break;
831da177e4SLinus Torvalds }
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds read_unlock(&ax25_uid_lock);
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds return res;
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds case SIOCAX25ADDUID:
90d13fda85SEric W. Biederman {
91d13fda85SEric W. Biederman kuid_t sax25_kuid;
921da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN))
931da177e4SLinus Torvalds return -EPERM;
94d13fda85SEric W. Biederman sax25_kuid = make_kuid(current_user_ns(), sax->sax25_uid);
95d13fda85SEric W. Biederman if (!uid_valid(sax25_kuid))
96d13fda85SEric W. Biederman return -EINVAL;
97d13fda85SEric W. Biederman user = ax25_findbyuid(sax25_kuid);
9801d7dd0eSRalf Baechle if (user) {
9901d7dd0eSRalf Baechle ax25_uid_put(user);
1001da177e4SLinus Torvalds return -EEXIST;
10101d7dd0eSRalf Baechle }
1021da177e4SLinus Torvalds if (sax->sax25_uid == 0)
1031da177e4SLinus Torvalds return -EINVAL;
1041da177e4SLinus Torvalds if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
1051da177e4SLinus Torvalds return -ENOMEM;
1061da177e4SLinus Torvalds
10707f2282fSReshetova, Elena refcount_set(&ax25_uid->refcount, 1);
108d13fda85SEric W. Biederman ax25_uid->uid = sax25_kuid;
1091da177e4SLinus Torvalds ax25_uid->call = sax->sax25_call;
1101da177e4SLinus Torvalds
1111da177e4SLinus Torvalds write_lock(&ax25_uid_lock);
11201d7dd0eSRalf Baechle hlist_add_head(&ax25_uid->uid_node, &ax25_uid_list);
1131da177e4SLinus Torvalds write_unlock(&ax25_uid_lock);
1141da177e4SLinus Torvalds
1151da177e4SLinus Torvalds return 0;
116d13fda85SEric W. Biederman }
1171da177e4SLinus Torvalds case SIOCAX25DELUID:
1181da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN))
1191da177e4SLinus Torvalds return -EPERM;
1201da177e4SLinus Torvalds
12101d7dd0eSRalf Baechle ax25_uid = NULL;
1221da177e4SLinus Torvalds write_lock(&ax25_uid_lock);
123b67bfe0dSSasha Levin ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
12401d7dd0eSRalf Baechle if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
1251da177e4SLinus Torvalds break;
1261da177e4SLinus Torvalds }
1271da177e4SLinus Torvalds if (ax25_uid == NULL) {
1281da177e4SLinus Torvalds write_unlock(&ax25_uid_lock);
1291da177e4SLinus Torvalds return -ENOENT;
1301da177e4SLinus Torvalds }
13101d7dd0eSRalf Baechle hlist_del_init(&ax25_uid->uid_node);
13201d7dd0eSRalf Baechle ax25_uid_put(ax25_uid);
1331da177e4SLinus Torvalds write_unlock(&ax25_uid_lock);
1341da177e4SLinus Torvalds
13501d7dd0eSRalf Baechle return 0;
1361da177e4SLinus Torvalds
1371da177e4SLinus Torvalds default:
1381da177e4SLinus Torvalds return -EINVAL;
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds
1411da177e4SLinus Torvalds return -EINVAL; /*NOTREACHED */
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
1451da177e4SLinus Torvalds
ax25_uid_seq_start(struct seq_file * seq,loff_t * pos)1461da177e4SLinus Torvalds static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
147f16f3026SEric Dumazet __acquires(ax25_uid_lock)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds read_lock(&ax25_uid_lock);
150b512f3d8SLi Zefan return seq_hlist_start_head(&ax25_uid_list, *pos);
1511da177e4SLinus Torvalds }
1521da177e4SLinus Torvalds
ax25_uid_seq_next(struct seq_file * seq,void * v,loff_t * pos)1531da177e4SLinus Torvalds static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1541da177e4SLinus Torvalds {
155b512f3d8SLi Zefan return seq_hlist_next(v, &ax25_uid_list, pos);
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds
ax25_uid_seq_stop(struct seq_file * seq,void * v)1581da177e4SLinus Torvalds static void ax25_uid_seq_stop(struct seq_file *seq, void *v)
159f16f3026SEric Dumazet __releases(ax25_uid_lock)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds read_unlock(&ax25_uid_lock);
1621da177e4SLinus Torvalds }
1631da177e4SLinus Torvalds
ax25_uid_seq_show(struct seq_file * seq,void * v)1641da177e4SLinus Torvalds static int ax25_uid_seq_show(struct seq_file *seq, void *v)
1651da177e4SLinus Torvalds {
166f75268cdSRalf Baechle char buf[11];
167f75268cdSRalf Baechle
1681da177e4SLinus Torvalds if (v == SEQ_START_TOKEN)
1691da177e4SLinus Torvalds seq_printf(seq, "Policy: %d\n", ax25_uid_policy);
1701da177e4SLinus Torvalds else {
171b512f3d8SLi Zefan struct ax25_uid_assoc *pt;
1721da177e4SLinus Torvalds
173b512f3d8SLi Zefan pt = hlist_entry(v, struct ax25_uid_assoc, uid_node);
174d13fda85SEric W. Biederman seq_printf(seq, "%6d %s\n",
175d13fda85SEric W. Biederman from_kuid_munged(seq_user_ns(seq), pt->uid),
176d13fda85SEric W. Biederman ax2asc(buf, &pt->call));
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds return 0;
1791da177e4SLinus Torvalds }
1801da177e4SLinus Torvalds
181fddda2b7SChristoph Hellwig const struct seq_operations ax25_uid_seqops = {
1821da177e4SLinus Torvalds .start = ax25_uid_seq_start,
1831da177e4SLinus Torvalds .next = ax25_uid_seq_next,
1841da177e4SLinus Torvalds .stop = ax25_uid_seq_stop,
1851da177e4SLinus Torvalds .show = ax25_uid_seq_show,
1861da177e4SLinus Torvalds };
1871da177e4SLinus Torvalds #endif
1881da177e4SLinus Torvalds
1891da177e4SLinus Torvalds /*
1901da177e4SLinus Torvalds * Free all memory associated with UID/Callsign structures.
1911da177e4SLinus Torvalds */
ax25_uid_free(void)1921da177e4SLinus Torvalds void __exit ax25_uid_free(void)
1931da177e4SLinus Torvalds {
19401d7dd0eSRalf Baechle ax25_uid_assoc *ax25_uid;
1951da177e4SLinus Torvalds
1961da177e4SLinus Torvalds write_lock(&ax25_uid_lock);
197ae1b6a31SPavel Emelyanov again:
198b67bfe0dSSasha Levin ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
19901d7dd0eSRalf Baechle hlist_del_init(&ax25_uid->uid_node);
20001d7dd0eSRalf Baechle ax25_uid_put(ax25_uid);
201ae1b6a31SPavel Emelyanov goto again;
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds write_unlock(&ax25_uid_lock);
2041da177e4SLinus Torvalds }
205