2 * Network interface table.
4 * Network interfaces (devices) do not have a security field, so we
5 * maintain a table associating each interface with a SID.
7 * Author: James Morris <jmorris@redhat.com>
9 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2,
13 * as published by the Free Software Foundation.
15 #include <linux/init.h>
16 #include <linux/types.h>
17 #include <linux/stddef.h>
18 #include <linux/kernel.h>
19 #include <linux/list.h>
20 #include <linux/notifier.h>
21 #include <linux/netdevice.h>
22 #include <linux/rcupdate.h>
28 #define SEL_NETIF_HASH_SIZE 64
29 #define SEL_NETIF_HASH_MAX 1024
36 #define DEBUGP(format, args...)
39 static u32 sel_netif_total
;
40 static LIST_HEAD(sel_netif_list
);
41 static spinlock_t sel_netif_lock
= SPIN_LOCK_UNLOCKED
;
42 static struct sel_netif sel_netif_hash
[SEL_NETIF_HASH_SIZE
];
44 static inline u32
sel_netif_hasfn(struct net_device
*dev
)
46 return (dev
->ifindex
& (SEL_NETIF_HASH_SIZE
- 1));
50 * All of the devices should normally fit in the hash, so we optimize
53 static struct sel_netif
*sel_netif_find(struct net_device
*dev
)
55 struct list_head
*pos
;
56 int idx
= sel_netif_hasfn(dev
);
58 __list_for_each_rcu(pos
, &sel_netif_hash
[idx
].list
) {
59 struct sel_netif
*netif
= list_entry(pos
,
60 struct sel_netif
, list
);
61 if (likely(netif
->nsec
.dev
== dev
))
67 static int sel_netif_insert(struct sel_netif
*netif
)
71 if (sel_netif_total
>= SEL_NETIF_HASH_MAX
) {
76 idx
= sel_netif_hasfn(netif
->nsec
.dev
);
77 list_add_rcu(&netif
->list
, &sel_netif_hash
[idx
].list
);
78 atomic_set(&netif
->users
, 1);
84 struct sel_netif
*sel_netif_lookup(struct net_device
*dev
)
87 struct sel_netif
*netif
, *new;
88 struct netif_security_struct
*nsec
;
91 netif
= sel_netif_find(dev
);
94 if (likely(netif
!= NULL
))
97 new = kmalloc(sizeof(*new), GFP_ATOMIC
);
99 netif
= ERR_PTR(-ENOMEM
);
103 memset(new, 0, sizeof(*new));
106 ret
= security_netif_sid(dev
->name
, &nsec
->if_sid
, &nsec
->msg_sid
);
109 netif
= ERR_PTR(ret
);
115 spin_lock_bh(&sel_netif_lock
);
117 netif
= sel_netif_find(dev
);
119 spin_unlock_bh(&sel_netif_lock
);
124 sel_netif_insert(new);
125 spin_unlock_bh(&sel_netif_lock
);
129 DEBUGP("new: ifindex=%u name=%s if_sid=%u msg_sid=%u\n", dev
->ifindex
, dev
->name
,
130 nsec
->if_sid
, nsec
->msg_sid
);
132 atomic_inc(&netif
->users
);
137 static void sel_netif_free(struct rcu_head
*p
)
139 struct sel_netif
*netif
= container_of(p
, struct sel_netif
, rcu_head
);
141 DEBUGP("%s: %s\n", __FUNCTION__
, netif
->nsec
.dev
->name
);
145 static void sel_netif_destroy(struct sel_netif
*netif
)
147 DEBUGP("%s: %s\n", __FUNCTION__
, netif
->nsec
.dev
->name
);
149 spin_lock_bh(&sel_netif_lock
);
150 list_del_rcu(&netif
->list
);
152 spin_unlock_bh(&sel_netif_lock
);
154 call_rcu(&netif
->rcu_head
, sel_netif_free
);
157 void sel_netif_put(struct sel_netif
*netif
)
159 if (atomic_dec_and_test(&netif
->users
))
160 sel_netif_destroy(netif
);
163 static void sel_netif_kill(struct net_device
*dev
)
165 struct sel_netif
*netif
;
168 netif
= sel_netif_find(dev
);
171 /* Drop internal reference */
173 sel_netif_put(netif
);
176 static void sel_netif_flush(void)
180 for (idx
= 0; idx
< SEL_NETIF_HASH_SIZE
; idx
++) {
181 struct list_head
*pos
;
183 list_for_each_rcu(pos
, &sel_netif_hash
[idx
].list
) {
184 struct sel_netif
*netif
;
186 netif
= list_entry(pos
, struct sel_netif
, list
);
188 sel_netif_put(netif
);
193 static int sel_netif_avc_callback(u32 event
, u32 ssid
, u32 tsid
,
194 u16
class, u32 perms
, u32
*retained
)
196 if (event
== AVC_CALLBACK_RESET
) {
203 static int sel_netif_netdev_notifier_handler(struct notifier_block
*this,
204 unsigned long event
, void *ptr
)
206 struct net_device
*dev
= ptr
;
208 if (event
== NETDEV_DOWN
)
214 static struct notifier_block sel_netif_netdev_notifier
= {
215 .notifier_call
= sel_netif_netdev_notifier_handler
,
218 static __init
int sel_netif_init(void)
222 if (!selinux_enabled
)
225 for (i
= 0; i
< SEL_NETIF_HASH_SIZE
; i
++)
226 INIT_LIST_HEAD(&sel_netif_hash
[i
].list
);
228 register_netdevice_notifier(&sel_netif_netdev_notifier
);
230 err
= avc_add_callback(sel_netif_avc_callback
, AVC_CALLBACK_RESET
,
231 SECSID_NULL
, SECSID_NULL
, SECCLASS_NULL
, 0);
233 panic("avc_add_callback() failed, error %d\n", err
);
239 __initcall(sel_netif_init
);