Blame view
security/selinux/netif.c
7.21 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 |
/* * Network interface table. * * Network interfaces (devices) do not have a security field, so we * maintain a table associating each interface with a SID. * * Author: James Morris <jmorris@redhat.com> * * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
e8bfdb9d0 SELinux: Convert ... |
10 |
* Copyright (C) 2007 Hewlett-Packard Development Company, L.P. |
82c21bfab doc: Update the e... |
11 |
* Paul Moore <paul@paul-moore.com> |
1da177e4c Linux-2.6.12-rc2 |
12 13 14 15 16 17 18 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * as published by the Free Software Foundation. */ #include <linux/init.h> #include <linux/types.h> |
5a0e3ad6a include cleanup: ... |
19 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
20 21 22 23 24 25 |
#include <linux/stddef.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/notifier.h> #include <linux/netdevice.h> #include <linux/rcupdate.h> |
e9dc86534 [NET]: Make devic... |
26 |
#include <net/net_namespace.h> |
1da177e4c Linux-2.6.12-rc2 |
27 28 29 30 31 32 33 |
#include "security.h" #include "objsec.h" #include "netif.h" #define SEL_NETIF_HASH_SIZE 64 #define SEL_NETIF_HASH_MAX 1024 |
338366cbb SELinux: netif.c ... |
34 |
struct sel_netif { |
1da177e4c Linux-2.6.12-rc2 |
35 36 37 38 39 40 41 42 43 |
struct list_head list; struct netif_security_struct nsec; struct rcu_head rcu_head; }; static u32 sel_netif_total; static LIST_HEAD(sel_netif_list); static DEFINE_SPINLOCK(sel_netif_lock); static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; |
e8bfdb9d0 SELinux: Convert ... |
44 45 46 47 48 49 50 51 52 53 |
/** * sel_netif_hashfn - Hashing function for the interface table * @ifindex: the network interface * * Description: * This is the hashing function for the network interface table, it returns the * bucket number for the given interface. * */ static inline u32 sel_netif_hashfn(int ifindex) |
1da177e4c Linux-2.6.12-rc2 |
54 |
{ |
e8bfdb9d0 SELinux: Convert ... |
55 |
return (ifindex & (SEL_NETIF_HASH_SIZE - 1)); |
1da177e4c Linux-2.6.12-rc2 |
56 |
} |
e8bfdb9d0 SELinux: Convert ... |
57 58 59 60 61 62 63 64 |
/** * sel_netif_find - Search for an interface record * @ifindex: the network interface * * Description: * Search the network interface table and return the record matching @ifindex. * If an entry can not be found in the table return NULL. * |
1da177e4c Linux-2.6.12-rc2 |
65 |
*/ |
e8bfdb9d0 SELinux: Convert ... |
66 |
static inline struct sel_netif *sel_netif_find(int ifindex) |
1da177e4c Linux-2.6.12-rc2 |
67 |
{ |
e8bfdb9d0 SELinux: Convert ... |
68 69 |
int idx = sel_netif_hashfn(ifindex); struct sel_netif *netif; |
1da177e4c Linux-2.6.12-rc2 |
70 |
|
e8bfdb9d0 SELinux: Convert ... |
71 72 73 74 |
list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list) /* all of the devices should normally fit in the hash, so we * optimize for that case */ if (likely(netif->nsec.ifindex == ifindex)) |
1da177e4c Linux-2.6.12-rc2 |
75 |
return netif; |
e8bfdb9d0 SELinux: Convert ... |
76 |
|
1da177e4c Linux-2.6.12-rc2 |
77 78 |
return NULL; } |
e8bfdb9d0 SELinux: Convert ... |
79 80 81 82 83 84 85 86 87 |
/** * sel_netif_insert - Insert a new interface into the table * @netif: the new interface record * * Description: * Add a new interface record to the network interface hash table. Returns * zero on success, negative values on failure. * */ |
1da177e4c Linux-2.6.12-rc2 |
88 89 |
static int sel_netif_insert(struct sel_netif *netif) { |
e8bfdb9d0 SELinux: Convert ... |
90 |
int idx; |
338366cbb SELinux: netif.c ... |
91 |
|
e8bfdb9d0 SELinux: Convert ... |
92 93 |
if (sel_netif_total >= SEL_NETIF_HASH_MAX) return -ENOSPC; |
338366cbb SELinux: netif.c ... |
94 |
|
e8bfdb9d0 SELinux: Convert ... |
95 |
idx = sel_netif_hashfn(netif->nsec.ifindex); |
1da177e4c Linux-2.6.12-rc2 |
96 97 |
list_add_rcu(&netif->list, &sel_netif_hash[idx]); sel_netif_total++; |
e8bfdb9d0 SELinux: Convert ... |
98 99 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
100 |
} |
e8bfdb9d0 SELinux: Convert ... |
101 |
/** |
e8bfdb9d0 SELinux: Convert ... |
102 103 104 105 106 107 108 |
* sel_netif_destroy - Remove an interface record from the table * @netif: the existing interface record * * Description: * Remove an existing interface record from the network interface table. * */ |
1da177e4c Linux-2.6.12-rc2 |
109 110 |
static void sel_netif_destroy(struct sel_netif *netif) { |
1da177e4c Linux-2.6.12-rc2 |
111 112 |
list_del_rcu(&netif->list); sel_netif_total--; |
690273fc7 security,rcu: con... |
113 |
kfree_rcu(netif, rcu_head); |
1da177e4c Linux-2.6.12-rc2 |
114 |
} |
e8bfdb9d0 SELinux: Convert ... |
115 116 117 118 119 120 121 122 123 124 125 126 127 |
/** * sel_netif_sid_slow - Lookup the SID of a network interface using the policy * @ifindex: the network interface * @sid: interface SID * * Description: * This function determines the SID of a network interface by quering the * security policy. The result is added to the network interface table to * speedup future queries. Returns zero on success, negative values on * failure. * */ static int sel_netif_sid_slow(int ifindex, u32 *sid) |
1da177e4c Linux-2.6.12-rc2 |
128 129 |
{ int ret; |
e8bfdb9d0 SELinux: Convert ... |
130 131 132 |
struct sel_netif *netif; struct sel_netif *new = NULL; struct net_device *dev; |
1da177e4c Linux-2.6.12-rc2 |
133 |
|
e8bfdb9d0 SELinux: Convert ... |
134 135 |
/* NOTE: we always use init's network namespace since we don't * currently support containers */ |
1da177e4c Linux-2.6.12-rc2 |
136 |
|
e8bfdb9d0 SELinux: Convert ... |
137 |
dev = dev_get_by_index(&init_net, ifindex); |
71f1cb05f SELinux: Add warn... |
138 139 140 141 142 |
if (unlikely(dev == NULL)) { printk(KERN_WARNING "SELinux: failure in sel_netif_sid_slow()," " invalid network interface (%d) ", ifindex); |
e8bfdb9d0 SELinux: Convert ... |
143 |
return -ENOENT; |
71f1cb05f SELinux: Add warn... |
144 |
} |
1da177e4c Linux-2.6.12-rc2 |
145 |
|
1da177e4c Linux-2.6.12-rc2 |
146 |
spin_lock_bh(&sel_netif_lock); |
e8bfdb9d0 SELinux: Convert ... |
147 148 149 150 |
netif = sel_netif_find(ifindex); if (netif != NULL) { *sid = netif->nsec.sid; ret = 0; |
1da177e4c Linux-2.6.12-rc2 |
151 152 |
goto out; } |
e8bfdb9d0 SELinux: Convert ... |
153 154 155 |
new = kzalloc(sizeof(*new), GFP_ATOMIC); if (new == NULL) { ret = -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
156 157 |
goto out; } |
e8bfdb9d0 SELinux: Convert ... |
158 159 160 161 162 163 164 165 |
ret = security_netif_sid(dev->name, &new->nsec.sid); if (ret != 0) goto out; new->nsec.ifindex = ifindex; ret = sel_netif_insert(new); if (ret != 0) goto out; *sid = new->nsec.sid; |
1da177e4c Linux-2.6.12-rc2 |
166 |
|
1da177e4c Linux-2.6.12-rc2 |
167 |
out: |
e8bfdb9d0 SELinux: Convert ... |
168 169 |
spin_unlock_bh(&sel_netif_lock); dev_put(dev); |
71f1cb05f SELinux: Add warn... |
170 171 172 173 174 175 |
if (unlikely(ret)) { printk(KERN_WARNING "SELinux: failure in sel_netif_sid_slow()," " unable to determine network interface label (%d) ", ifindex); |
e8bfdb9d0 SELinux: Convert ... |
176 |
kfree(new); |
71f1cb05f SELinux: Add warn... |
177 |
} |
1da177e4c Linux-2.6.12-rc2 |
178 179 |
return ret; } |
e8bfdb9d0 SELinux: Convert ... |
180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
/** * sel_netif_sid - Lookup the SID of a network interface * @ifindex: the network interface * @sid: interface SID * * Description: * This function determines the SID of a network interface using the fastest * method possible. First the interface table is queried, but if an entry * can't be found then the policy is queried and the result is added to the * table to speedup future queries. Returns zero on success, negative values * on failure. * */ int sel_netif_sid(int ifindex, u32 *sid) |
1da177e4c Linux-2.6.12-rc2 |
194 |
{ |
1da177e4c Linux-2.6.12-rc2 |
195 196 197 |
struct sel_netif *netif; rcu_read_lock(); |
e8bfdb9d0 SELinux: Convert ... |
198 199 200 |
netif = sel_netif_find(ifindex); if (likely(netif != NULL)) { *sid = netif->nsec.sid; |
1da177e4c Linux-2.6.12-rc2 |
201 |
rcu_read_unlock(); |
e8bfdb9d0 SELinux: Convert ... |
202 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
203 |
} |
1da177e4c Linux-2.6.12-rc2 |
204 |
rcu_read_unlock(); |
e8bfdb9d0 SELinux: Convert ... |
205 206 |
return sel_netif_sid_slow(ifindex, sid); |
1da177e4c Linux-2.6.12-rc2 |
207 |
} |
e8bfdb9d0 SELinux: Convert ... |
208 209 210 211 212 213 214 215 216 217 |
/** * sel_netif_kill - Remove an entry from the network interface table * @ifindex: the network interface * * Description: * This function removes the entry matching @ifindex from the network interface * table if it exists. * */ static void sel_netif_kill(int ifindex) |
1da177e4c Linux-2.6.12-rc2 |
218 219 |
{ struct sel_netif *netif; |
618442509 SELinux fixups ne... |
220 |
rcu_read_lock(); |
1da177e4c Linux-2.6.12-rc2 |
221 |
spin_lock_bh(&sel_netif_lock); |
e8bfdb9d0 SELinux: Convert ... |
222 |
netif = sel_netif_find(ifindex); |
1da177e4c Linux-2.6.12-rc2 |
223 224 225 |
if (netif) sel_netif_destroy(netif); spin_unlock_bh(&sel_netif_lock); |
618442509 SELinux fixups ne... |
226 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
227 |
} |
e8bfdb9d0 SELinux: Convert ... |
228 229 230 231 232 233 234 |
/** * sel_netif_flush - Flush the entire network interface table * * Description: * Remove all entries from the network interface table. * */ |
1da177e4c Linux-2.6.12-rc2 |
235 236 237 |
static void sel_netif_flush(void) { int idx; |
e8bfdb9d0 SELinux: Convert ... |
238 |
struct sel_netif *netif; |
1da177e4c Linux-2.6.12-rc2 |
239 240 |
spin_lock_bh(&sel_netif_lock); |
e8bfdb9d0 SELinux: Convert ... |
241 |
for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) |
1da177e4c Linux-2.6.12-rc2 |
242 243 |
list_for_each_entry(netif, &sel_netif_hash[idx], list) sel_netif_destroy(netif); |
1da177e4c Linux-2.6.12-rc2 |
244 245 246 247 |
spin_unlock_bh(&sel_netif_lock); } static int sel_netif_avc_callback(u32 event, u32 ssid, u32 tsid, |
338366cbb SELinux: netif.c ... |
248 |
u16 class, u32 perms, u32 *retained) |
1da177e4c Linux-2.6.12-rc2 |
249 250 251 252 253 254 255 256 257 |
{ if (event == AVC_CALLBACK_RESET) { sel_netif_flush(); synchronize_net(); } return 0; } static int sel_netif_netdev_notifier_handler(struct notifier_block *this, |
338366cbb SELinux: netif.c ... |
258 |
unsigned long event, void *ptr) |
1da177e4c Linux-2.6.12-rc2 |
259 260 |
{ struct net_device *dev = ptr; |
c346dca10 [NET] NETNS: Omit... |
261 |
if (dev_net(dev) != &init_net) |
e9dc86534 [NET]: Make devic... |
262 |
return NOTIFY_DONE; |
1da177e4c Linux-2.6.12-rc2 |
263 |
if (event == NETDEV_DOWN) |
e8bfdb9d0 SELinux: Convert ... |
264 |
sel_netif_kill(dev->ifindex); |
1da177e4c Linux-2.6.12-rc2 |
265 266 267 268 269 270 271 272 273 274 |
return NOTIFY_DONE; } static struct notifier_block sel_netif_netdev_notifier = { .notifier_call = sel_netif_netdev_notifier_handler, }; static __init int sel_netif_init(void) { |
e8bfdb9d0 SELinux: Convert ... |
275 |
int i, err; |
338366cbb SELinux: netif.c ... |
276 |
|
1da177e4c Linux-2.6.12-rc2 |
277 |
if (!selinux_enabled) |
e8bfdb9d0 SELinux: Convert ... |
278 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
279 280 281 282 283 |
for (i = 0; i < SEL_NETIF_HASH_SIZE; i++) INIT_LIST_HEAD(&sel_netif_hash[i]); register_netdevice_notifier(&sel_netif_netdev_notifier); |
338366cbb SELinux: netif.c ... |
284 |
|
1da177e4c Linux-2.6.12-rc2 |
285 |
err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET, |
338366cbb SELinux: netif.c ... |
286 |
SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); |
1da177e4c Linux-2.6.12-rc2 |
287 288 289 |
if (err) panic("avc_add_callback() failed, error %d ", err); |
1da177e4c Linux-2.6.12-rc2 |
290 291 292 293 |
return err; } __initcall(sel_netif_init); |