Blame view

security/selinux/netif.c 7.21 KB
1da177e4c   Linus Torvalds   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   Paul Moore   SELinux: Convert ...
10
   * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
82c21bfab   Paul Moore   doc: Update the e...
11
   *		      Paul Moore <paul@paul-moore.com>
1da177e4c   Linus Torvalds   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   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   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   Eric W. Biederman   [NET]: Make devic...
26
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   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   Eric Paris   SELinux: netif.c ...
34
  struct sel_netif {
1da177e4c   Linus Torvalds   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   Paul Moore   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   Linus Torvalds   Linux-2.6.12-rc2
54
  {
e8bfdb9d0   Paul Moore   SELinux: Convert ...
55
  	return (ifindex & (SEL_NETIF_HASH_SIZE - 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  }
e8bfdb9d0   Paul Moore   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   Linus Torvalds   Linux-2.6.12-rc2
65
   */
e8bfdb9d0   Paul Moore   SELinux: Convert ...
66
  static inline struct sel_netif *sel_netif_find(int ifindex)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  {
e8bfdb9d0   Paul Moore   SELinux: Convert ...
68
69
  	int idx = sel_netif_hashfn(ifindex);
  	struct sel_netif *netif;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

e8bfdb9d0   Paul Moore   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   Linus Torvalds   Linux-2.6.12-rc2
75
  			return netif;
e8bfdb9d0   Paul Moore   SELinux: Convert ...
76

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
  	return NULL;
  }
e8bfdb9d0   Paul Moore   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   Linus Torvalds   Linux-2.6.12-rc2
88
89
  static int sel_netif_insert(struct sel_netif *netif)
  {
e8bfdb9d0   Paul Moore   SELinux: Convert ...
90
  	int idx;
338366cbb   Eric Paris   SELinux: netif.c ...
91

e8bfdb9d0   Paul Moore   SELinux: Convert ...
92
93
  	if (sel_netif_total >= SEL_NETIF_HASH_MAX)
  		return -ENOSPC;
338366cbb   Eric Paris   SELinux: netif.c ...
94

e8bfdb9d0   Paul Moore   SELinux: Convert ...
95
  	idx = sel_netif_hashfn(netif->nsec.ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
  	list_add_rcu(&netif->list, &sel_netif_hash[idx]);
  	sel_netif_total++;
e8bfdb9d0   Paul Moore   SELinux: Convert ...
98
99
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  }
e8bfdb9d0   Paul Moore   SELinux: Convert ...
101
  /**
e8bfdb9d0   Paul Moore   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   Linus Torvalds   Linux-2.6.12-rc2
109
110
  static void sel_netif_destroy(struct sel_netif *netif)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
  	list_del_rcu(&netif->list);
  	sel_netif_total--;
690273fc7   Lai Jiangshan   security,rcu: con...
113
  	kfree_rcu(netif, rcu_head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  }
e8bfdb9d0   Paul Moore   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   Linus Torvalds   Linux-2.6.12-rc2
128
129
  {
  	int ret;
e8bfdb9d0   Paul Moore   SELinux: Convert ...
130
131
132
  	struct sel_netif *netif;
  	struct sel_netif *new = NULL;
  	struct net_device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133

e8bfdb9d0   Paul Moore   SELinux: Convert ...
134
135
  	/* NOTE: we always use init's network namespace since we don't
  	 * currently support containers */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136

e8bfdb9d0   Paul Moore   SELinux: Convert ...
137
  	dev = dev_get_by_index(&init_net, ifindex);
71f1cb05f   Paul Moore   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   Paul Moore   SELinux: Convert ...
143
  		return -ENOENT;
71f1cb05f   Paul Moore   SELinux: Add warn...
144
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	spin_lock_bh(&sel_netif_lock);
e8bfdb9d0   Paul Moore   SELinux: Convert ...
147
148
149
150
  	netif = sel_netif_find(ifindex);
  	if (netif != NULL) {
  		*sid = netif->nsec.sid;
  		ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
  		goto out;
  	}
e8bfdb9d0   Paul Moore   SELinux: Convert ...
153
154
155
  	new = kzalloc(sizeof(*new), GFP_ATOMIC);
  	if (new == NULL) {
  		ret = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
  		goto out;
  	}
e8bfdb9d0   Paul Moore   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   Linus Torvalds   Linux-2.6.12-rc2
166

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  out:
e8bfdb9d0   Paul Moore   SELinux: Convert ...
168
169
  	spin_unlock_bh(&sel_netif_lock);
  	dev_put(dev);
71f1cb05f   Paul Moore   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   Paul Moore   SELinux: Convert ...
176
  		kfree(new);
71f1cb05f   Paul Moore   SELinux: Add warn...
177
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
  	return ret;
  }
e8bfdb9d0   Paul Moore   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   Linus Torvalds   Linux-2.6.12-rc2
194
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
  	struct sel_netif *netif;
  
  	rcu_read_lock();
e8bfdb9d0   Paul Moore   SELinux: Convert ...
198
199
200
  	netif = sel_netif_find(ifindex);
  	if (likely(netif != NULL)) {
  		*sid = netif->nsec.sid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  		rcu_read_unlock();
e8bfdb9d0   Paul Moore   SELinux: Convert ...
202
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
  	rcu_read_unlock();
e8bfdb9d0   Paul Moore   SELinux: Convert ...
205
206
  
  	return sel_netif_sid_slow(ifindex, sid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  }
e8bfdb9d0   Paul Moore   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   Linus Torvalds   Linux-2.6.12-rc2
218
219
  {
  	struct sel_netif *netif;
618442509   Paul E. McKenney   SELinux fixups ne...
220
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  	spin_lock_bh(&sel_netif_lock);
e8bfdb9d0   Paul Moore   SELinux: Convert ...
222
  	netif = sel_netif_find(ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
  	if (netif)
  		sel_netif_destroy(netif);
  	spin_unlock_bh(&sel_netif_lock);
618442509   Paul E. McKenney   SELinux fixups ne...
226
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  }
e8bfdb9d0   Paul Moore   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   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
  static void sel_netif_flush(void)
  {
  	int idx;
e8bfdb9d0   Paul Moore   SELinux: Convert ...
238
  	struct sel_netif *netif;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
  
  	spin_lock_bh(&sel_netif_lock);
e8bfdb9d0   Paul Moore   SELinux: Convert ...
241
  	for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
  		list_for_each_entry(netif, &sel_netif_hash[idx], list)
  			sel_netif_destroy(netif);
1da177e4c   Linus Torvalds   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   Eric Paris   SELinux: netif.c ...
248
  				  u16 class, u32 perms, u32 *retained)
1da177e4c   Linus Torvalds   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   Eric Paris   SELinux: netif.c ...
258
  					     unsigned long event, void *ptr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
  {
  	struct net_device *dev = ptr;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
261
  	if (dev_net(dev) != &init_net)
e9dc86534   Eric W. Biederman   [NET]: Make devic...
262
  		return NOTIFY_DONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  	if (event == NETDEV_DOWN)
e8bfdb9d0   Paul Moore   SELinux: Convert ...
264
  		sel_netif_kill(dev->ifindex);
1da177e4c   Linus Torvalds   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   Paul Moore   SELinux: Convert ...
275
  	int i, err;
338366cbb   Eric Paris   SELinux: netif.c ...
276

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  	if (!selinux_enabled)
e8bfdb9d0   Paul Moore   SELinux: Convert ...
278
  		return 0;
1da177e4c   Linus Torvalds   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   Eric Paris   SELinux: netif.c ...
284

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET,
338366cbb   Eric Paris   SELinux: netif.c ...
286
  			       SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
  	if (err)
  		panic("avc_add_callback() failed, error %d
  ", err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
293
  	return err;
  }
  
  __initcall(sel_netif_init);