1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * Network interface table. 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Network interfaces (devices) do not have a security field, so we 5*1da177e4SLinus Torvalds * maintain a table associating each interface with a SID. 6*1da177e4SLinus Torvalds * 7*1da177e4SLinus Torvalds * Author: James Morris <jmorris@redhat.com> 8*1da177e4SLinus Torvalds * 9*1da177e4SLinus Torvalds * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 10*1da177e4SLinus Torvalds * 11*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 12*1da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2, 13*1da177e4SLinus Torvalds * as published by the Free Software Foundation. 14*1da177e4SLinus Torvalds */ 15*1da177e4SLinus Torvalds #include <linux/init.h> 16*1da177e4SLinus Torvalds #include <linux/types.h> 17*1da177e4SLinus Torvalds #include <linux/stddef.h> 18*1da177e4SLinus Torvalds #include <linux/kernel.h> 19*1da177e4SLinus Torvalds #include <linux/list.h> 20*1da177e4SLinus Torvalds #include <linux/notifier.h> 21*1da177e4SLinus Torvalds #include <linux/netdevice.h> 22*1da177e4SLinus Torvalds #include <linux/rcupdate.h> 23*1da177e4SLinus Torvalds 24*1da177e4SLinus Torvalds #include "security.h" 25*1da177e4SLinus Torvalds #include "objsec.h" 26*1da177e4SLinus Torvalds #include "netif.h" 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds #define SEL_NETIF_HASH_SIZE 64 29*1da177e4SLinus Torvalds #define SEL_NETIF_HASH_MAX 1024 30*1da177e4SLinus Torvalds 31*1da177e4SLinus Torvalds #undef DEBUG 32*1da177e4SLinus Torvalds 33*1da177e4SLinus Torvalds #ifdef DEBUG 34*1da177e4SLinus Torvalds #define DEBUGP printk 35*1da177e4SLinus Torvalds #else 36*1da177e4SLinus Torvalds #define DEBUGP(format, args...) 37*1da177e4SLinus Torvalds #endif 38*1da177e4SLinus Torvalds 39*1da177e4SLinus Torvalds struct sel_netif 40*1da177e4SLinus Torvalds { 41*1da177e4SLinus Torvalds struct list_head list; 42*1da177e4SLinus Torvalds struct netif_security_struct nsec; 43*1da177e4SLinus Torvalds struct rcu_head rcu_head; 44*1da177e4SLinus Torvalds }; 45*1da177e4SLinus Torvalds 46*1da177e4SLinus Torvalds static u32 sel_netif_total; 47*1da177e4SLinus Torvalds static LIST_HEAD(sel_netif_list); 48*1da177e4SLinus Torvalds static DEFINE_SPINLOCK(sel_netif_lock); 49*1da177e4SLinus Torvalds static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; 50*1da177e4SLinus Torvalds 51*1da177e4SLinus Torvalds static inline u32 sel_netif_hasfn(struct net_device *dev) 52*1da177e4SLinus Torvalds { 53*1da177e4SLinus Torvalds return (dev->ifindex & (SEL_NETIF_HASH_SIZE - 1)); 54*1da177e4SLinus Torvalds } 55*1da177e4SLinus Torvalds 56*1da177e4SLinus Torvalds /* 57*1da177e4SLinus Torvalds * All of the devices should normally fit in the hash, so we optimize 58*1da177e4SLinus Torvalds * for that case. 59*1da177e4SLinus Torvalds */ 60*1da177e4SLinus Torvalds static inline struct sel_netif *sel_netif_find(struct net_device *dev) 61*1da177e4SLinus Torvalds { 62*1da177e4SLinus Torvalds struct list_head *pos; 63*1da177e4SLinus Torvalds int idx = sel_netif_hasfn(dev); 64*1da177e4SLinus Torvalds 65*1da177e4SLinus Torvalds __list_for_each_rcu(pos, &sel_netif_hash[idx]) { 66*1da177e4SLinus Torvalds struct sel_netif *netif = list_entry(pos, 67*1da177e4SLinus Torvalds struct sel_netif, list); 68*1da177e4SLinus Torvalds if (likely(netif->nsec.dev == dev)) 69*1da177e4SLinus Torvalds return netif; 70*1da177e4SLinus Torvalds } 71*1da177e4SLinus Torvalds return NULL; 72*1da177e4SLinus Torvalds } 73*1da177e4SLinus Torvalds 74*1da177e4SLinus Torvalds static int sel_netif_insert(struct sel_netif *netif) 75*1da177e4SLinus Torvalds { 76*1da177e4SLinus Torvalds int idx, ret = 0; 77*1da177e4SLinus Torvalds 78*1da177e4SLinus Torvalds if (sel_netif_total >= SEL_NETIF_HASH_MAX) { 79*1da177e4SLinus Torvalds ret = -ENOSPC; 80*1da177e4SLinus Torvalds goto out; 81*1da177e4SLinus Torvalds } 82*1da177e4SLinus Torvalds 83*1da177e4SLinus Torvalds idx = sel_netif_hasfn(netif->nsec.dev); 84*1da177e4SLinus Torvalds list_add_rcu(&netif->list, &sel_netif_hash[idx]); 85*1da177e4SLinus Torvalds sel_netif_total++; 86*1da177e4SLinus Torvalds out: 87*1da177e4SLinus Torvalds return ret; 88*1da177e4SLinus Torvalds } 89*1da177e4SLinus Torvalds 90*1da177e4SLinus Torvalds static void sel_netif_free(struct rcu_head *p) 91*1da177e4SLinus Torvalds { 92*1da177e4SLinus Torvalds struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head); 93*1da177e4SLinus Torvalds 94*1da177e4SLinus Torvalds DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name); 95*1da177e4SLinus Torvalds kfree(netif); 96*1da177e4SLinus Torvalds } 97*1da177e4SLinus Torvalds 98*1da177e4SLinus Torvalds static void sel_netif_destroy(struct sel_netif *netif) 99*1da177e4SLinus Torvalds { 100*1da177e4SLinus Torvalds DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name); 101*1da177e4SLinus Torvalds 102*1da177e4SLinus Torvalds list_del_rcu(&netif->list); 103*1da177e4SLinus Torvalds sel_netif_total--; 104*1da177e4SLinus Torvalds call_rcu(&netif->rcu_head, sel_netif_free); 105*1da177e4SLinus Torvalds } 106*1da177e4SLinus Torvalds 107*1da177e4SLinus Torvalds static struct sel_netif *sel_netif_lookup(struct net_device *dev) 108*1da177e4SLinus Torvalds { 109*1da177e4SLinus Torvalds int ret; 110*1da177e4SLinus Torvalds struct sel_netif *netif, *new; 111*1da177e4SLinus Torvalds struct netif_security_struct *nsec; 112*1da177e4SLinus Torvalds 113*1da177e4SLinus Torvalds netif = sel_netif_find(dev); 114*1da177e4SLinus Torvalds if (likely(netif != NULL)) 115*1da177e4SLinus Torvalds goto out; 116*1da177e4SLinus Torvalds 117*1da177e4SLinus Torvalds new = kmalloc(sizeof(*new), GFP_ATOMIC); 118*1da177e4SLinus Torvalds if (!new) { 119*1da177e4SLinus Torvalds netif = ERR_PTR(-ENOMEM); 120*1da177e4SLinus Torvalds goto out; 121*1da177e4SLinus Torvalds } 122*1da177e4SLinus Torvalds 123*1da177e4SLinus Torvalds memset(new, 0, sizeof(*new)); 124*1da177e4SLinus Torvalds nsec = &new->nsec; 125*1da177e4SLinus Torvalds 126*1da177e4SLinus Torvalds ret = security_netif_sid(dev->name, &nsec->if_sid, &nsec->msg_sid); 127*1da177e4SLinus Torvalds if (ret < 0) { 128*1da177e4SLinus Torvalds kfree(new); 129*1da177e4SLinus Torvalds netif = ERR_PTR(ret); 130*1da177e4SLinus Torvalds goto out; 131*1da177e4SLinus Torvalds } 132*1da177e4SLinus Torvalds 133*1da177e4SLinus Torvalds nsec->dev = dev; 134*1da177e4SLinus Torvalds 135*1da177e4SLinus Torvalds spin_lock_bh(&sel_netif_lock); 136*1da177e4SLinus Torvalds 137*1da177e4SLinus Torvalds netif = sel_netif_find(dev); 138*1da177e4SLinus Torvalds if (netif) { 139*1da177e4SLinus Torvalds spin_unlock_bh(&sel_netif_lock); 140*1da177e4SLinus Torvalds kfree(new); 141*1da177e4SLinus Torvalds goto out; 142*1da177e4SLinus Torvalds } 143*1da177e4SLinus Torvalds 144*1da177e4SLinus Torvalds ret = sel_netif_insert(new); 145*1da177e4SLinus Torvalds spin_unlock_bh(&sel_netif_lock); 146*1da177e4SLinus Torvalds 147*1da177e4SLinus Torvalds if (ret) { 148*1da177e4SLinus Torvalds kfree(new); 149*1da177e4SLinus Torvalds netif = ERR_PTR(ret); 150*1da177e4SLinus Torvalds goto out; 151*1da177e4SLinus Torvalds } 152*1da177e4SLinus Torvalds 153*1da177e4SLinus Torvalds netif = new; 154*1da177e4SLinus Torvalds 155*1da177e4SLinus Torvalds DEBUGP("new: ifindex=%u name=%s if_sid=%u msg_sid=%u\n", dev->ifindex, dev->name, 156*1da177e4SLinus Torvalds nsec->if_sid, nsec->msg_sid); 157*1da177e4SLinus Torvalds out: 158*1da177e4SLinus Torvalds return netif; 159*1da177e4SLinus Torvalds } 160*1da177e4SLinus Torvalds 161*1da177e4SLinus Torvalds static void sel_netif_assign_sids(u32 if_sid_in, u32 msg_sid_in, u32 *if_sid_out, u32 *msg_sid_out) 162*1da177e4SLinus Torvalds { 163*1da177e4SLinus Torvalds if (if_sid_out) 164*1da177e4SLinus Torvalds *if_sid_out = if_sid_in; 165*1da177e4SLinus Torvalds if (msg_sid_out) 166*1da177e4SLinus Torvalds *msg_sid_out = msg_sid_in; 167*1da177e4SLinus Torvalds } 168*1da177e4SLinus Torvalds 169*1da177e4SLinus Torvalds static int sel_netif_sids_slow(struct net_device *dev, u32 *if_sid, u32 *msg_sid) 170*1da177e4SLinus Torvalds { 171*1da177e4SLinus Torvalds int ret = 0; 172*1da177e4SLinus Torvalds u32 tmp_if_sid, tmp_msg_sid; 173*1da177e4SLinus Torvalds 174*1da177e4SLinus Torvalds ret = security_netif_sid(dev->name, &tmp_if_sid, &tmp_msg_sid); 175*1da177e4SLinus Torvalds if (!ret) 176*1da177e4SLinus Torvalds sel_netif_assign_sids(tmp_if_sid, tmp_msg_sid, if_sid, msg_sid); 177*1da177e4SLinus Torvalds return ret; 178*1da177e4SLinus Torvalds } 179*1da177e4SLinus Torvalds 180*1da177e4SLinus Torvalds int sel_netif_sids(struct net_device *dev, u32 *if_sid, u32 *msg_sid) 181*1da177e4SLinus Torvalds { 182*1da177e4SLinus Torvalds int ret = 0; 183*1da177e4SLinus Torvalds struct sel_netif *netif; 184*1da177e4SLinus Torvalds 185*1da177e4SLinus Torvalds rcu_read_lock(); 186*1da177e4SLinus Torvalds netif = sel_netif_lookup(dev); 187*1da177e4SLinus Torvalds if (IS_ERR(netif)) { 188*1da177e4SLinus Torvalds rcu_read_unlock(); 189*1da177e4SLinus Torvalds ret = sel_netif_sids_slow(dev, if_sid, msg_sid); 190*1da177e4SLinus Torvalds goto out; 191*1da177e4SLinus Torvalds } 192*1da177e4SLinus Torvalds sel_netif_assign_sids(netif->nsec.if_sid, netif->nsec.msg_sid, if_sid, msg_sid); 193*1da177e4SLinus Torvalds rcu_read_unlock(); 194*1da177e4SLinus Torvalds out: 195*1da177e4SLinus Torvalds return ret; 196*1da177e4SLinus Torvalds } 197*1da177e4SLinus Torvalds 198*1da177e4SLinus Torvalds static void sel_netif_kill(struct net_device *dev) 199*1da177e4SLinus Torvalds { 200*1da177e4SLinus Torvalds struct sel_netif *netif; 201*1da177e4SLinus Torvalds 202*1da177e4SLinus Torvalds spin_lock_bh(&sel_netif_lock); 203*1da177e4SLinus Torvalds netif = sel_netif_find(dev); 204*1da177e4SLinus Torvalds if (netif) 205*1da177e4SLinus Torvalds sel_netif_destroy(netif); 206*1da177e4SLinus Torvalds spin_unlock_bh(&sel_netif_lock); 207*1da177e4SLinus Torvalds } 208*1da177e4SLinus Torvalds 209*1da177e4SLinus Torvalds static void sel_netif_flush(void) 210*1da177e4SLinus Torvalds { 211*1da177e4SLinus Torvalds int idx; 212*1da177e4SLinus Torvalds 213*1da177e4SLinus Torvalds spin_lock_bh(&sel_netif_lock); 214*1da177e4SLinus Torvalds for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) { 215*1da177e4SLinus Torvalds struct sel_netif *netif; 216*1da177e4SLinus Torvalds 217*1da177e4SLinus Torvalds list_for_each_entry(netif, &sel_netif_hash[idx], list) 218*1da177e4SLinus Torvalds sel_netif_destroy(netif); 219*1da177e4SLinus Torvalds } 220*1da177e4SLinus Torvalds spin_unlock_bh(&sel_netif_lock); 221*1da177e4SLinus Torvalds } 222*1da177e4SLinus Torvalds 223*1da177e4SLinus Torvalds static int sel_netif_avc_callback(u32 event, u32 ssid, u32 tsid, 224*1da177e4SLinus Torvalds u16 class, u32 perms, u32 *retained) 225*1da177e4SLinus Torvalds { 226*1da177e4SLinus Torvalds if (event == AVC_CALLBACK_RESET) { 227*1da177e4SLinus Torvalds sel_netif_flush(); 228*1da177e4SLinus Torvalds synchronize_net(); 229*1da177e4SLinus Torvalds } 230*1da177e4SLinus Torvalds return 0; 231*1da177e4SLinus Torvalds } 232*1da177e4SLinus Torvalds 233*1da177e4SLinus Torvalds static int sel_netif_netdev_notifier_handler(struct notifier_block *this, 234*1da177e4SLinus Torvalds unsigned long event, void *ptr) 235*1da177e4SLinus Torvalds { 236*1da177e4SLinus Torvalds struct net_device *dev = ptr; 237*1da177e4SLinus Torvalds 238*1da177e4SLinus Torvalds if (event == NETDEV_DOWN) 239*1da177e4SLinus Torvalds sel_netif_kill(dev); 240*1da177e4SLinus Torvalds 241*1da177e4SLinus Torvalds return NOTIFY_DONE; 242*1da177e4SLinus Torvalds } 243*1da177e4SLinus Torvalds 244*1da177e4SLinus Torvalds static struct notifier_block sel_netif_netdev_notifier = { 245*1da177e4SLinus Torvalds .notifier_call = sel_netif_netdev_notifier_handler, 246*1da177e4SLinus Torvalds }; 247*1da177e4SLinus Torvalds 248*1da177e4SLinus Torvalds static __init int sel_netif_init(void) 249*1da177e4SLinus Torvalds { 250*1da177e4SLinus Torvalds int i, err = 0; 251*1da177e4SLinus Torvalds 252*1da177e4SLinus Torvalds if (!selinux_enabled) 253*1da177e4SLinus Torvalds goto out; 254*1da177e4SLinus Torvalds 255*1da177e4SLinus Torvalds for (i = 0; i < SEL_NETIF_HASH_SIZE; i++) 256*1da177e4SLinus Torvalds INIT_LIST_HEAD(&sel_netif_hash[i]); 257*1da177e4SLinus Torvalds 258*1da177e4SLinus Torvalds register_netdevice_notifier(&sel_netif_netdev_notifier); 259*1da177e4SLinus Torvalds 260*1da177e4SLinus Torvalds err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET, 261*1da177e4SLinus Torvalds SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); 262*1da177e4SLinus Torvalds if (err) 263*1da177e4SLinus Torvalds panic("avc_add_callback() failed, error %d\n", err); 264*1da177e4SLinus Torvalds 265*1da177e4SLinus Torvalds out: 266*1da177e4SLinus Torvalds return err; 267*1da177e4SLinus Torvalds } 268*1da177e4SLinus Torvalds 269*1da177e4SLinus Torvalds __initcall(sel_netif_init); 270*1da177e4SLinus Torvalds 271