Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

SELinux: Convert the netif code to use ifindex values

The current SELinux netif code requires the caller have a valid net_device
struct pointer to lookup network interface information. However, we don't
always have a valid net_device pointer so convert the netif code to use
the ifindex values we always have as part of the sk_buff. This patch also
removes the default message SID from the network interface record, it is
not being used and therefore is "dead code".

Signed-off-by: Paul Moore <paul.moore@hp.com>
Signed-off-by: James Morris <jmorris@namei.org>

authored by

Paul Moore and committed by
James Morris
e8bfdb9d 75e22910

+155 -125
+2 -2
security/selinux/hooks.c
··· 3853 3853 if (!skb->dev) 3854 3854 goto out; 3855 3855 3856 - err = sel_netif_sids(skb->dev, &if_sid, NULL); 3856 + err = sel_netif_sid(skb->iif, &if_sid); 3857 3857 if (err) 3858 3858 goto out; 3859 3859 ··· 4178 4178 4179 4179 isec = inode->i_security; 4180 4180 4181 - err = sel_netif_sids(dev, &if_sid, NULL); 4181 + err = sel_netif_sid(dev->ifindex, &if_sid); 4182 4182 if (err) 4183 4183 goto out; 4184 4184
+3 -1
security/selinux/include/netif.h
··· 7 7 * Author: James Morris <jmorris@redhat.com> 8 8 * 9 9 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 10 + * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. 11 + * Paul Moore, <paul.moore@hp.com> 10 12 * 11 13 * This program is free software; you can redistribute it and/or modify 12 14 * it under the terms of the GNU General Public License version 2, ··· 17 15 #ifndef _SELINUX_NETIF_H_ 18 16 #define _SELINUX_NETIF_H_ 19 17 20 - int sel_netif_sids(struct net_device *dev, u32 *if_sid, u32 *msg_sid); 18 + int sel_netif_sid(int ifindex, u32 *sid); 21 19 22 20 #endif /* _SELINUX_NETIF_H_ */ 23 21
+2 -3
security/selinux/include/objsec.h
··· 96 96 }; 97 97 98 98 struct netif_security_struct { 99 - struct net_device *dev; /* back pointer */ 100 - u32 if_sid; /* SID for this interface */ 101 - u32 msg_sid; /* default SID for messages received on this interface */ 99 + int ifindex; /* device index */ 100 + u32 sid; /* SID for this interface */ 102 101 }; 103 102 104 103 struct sk_security_struct {
+1 -2
security/selinux/include/security.h
··· 77 77 int security_port_sid(u16 domain, u16 type, u8 protocol, u16 port, 78 78 u32 *out_sid); 79 79 80 - int security_netif_sid(char *name, u32 *if_sid, 81 - u32 *msg_sid); 80 + int security_netif_sid(char *name, u32 *if_sid); 82 81 83 82 int security_node_sid(u16 domain, void *addr, u32 addrlen, 84 83 u32 *out_sid);
+145 -109
security/selinux/netif.c
··· 7 7 * Author: James Morris <jmorris@redhat.com> 8 8 * 9 9 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 10 + * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. 11 + * Paul Moore <paul.moore@hp.com> 10 12 * 11 13 * This program is free software; you can redistribute it and/or modify 12 14 * it under the terms of the GNU General Public License version 2, ··· 31 29 #define SEL_NETIF_HASH_SIZE 64 32 30 #define SEL_NETIF_HASH_MAX 1024 33 31 34 - #undef DEBUG 35 - 36 - #ifdef DEBUG 37 - #define DEBUGP printk 38 - #else 39 - #define DEBUGP(format, args...) 40 - #endif 41 - 42 32 struct sel_netif 43 33 { 44 34 struct list_head list; ··· 43 49 static DEFINE_SPINLOCK(sel_netif_lock); 44 50 static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; 45 51 46 - static inline u32 sel_netif_hasfn(struct net_device *dev) 52 + /** 53 + * sel_netif_hashfn - Hashing function for the interface table 54 + * @ifindex: the network interface 55 + * 56 + * Description: 57 + * This is the hashing function for the network interface table, it returns the 58 + * bucket number for the given interface. 59 + * 60 + */ 61 + static inline u32 sel_netif_hashfn(int ifindex) 47 62 { 48 - return (dev->ifindex & (SEL_NETIF_HASH_SIZE - 1)); 63 + return (ifindex & (SEL_NETIF_HASH_SIZE - 1)); 49 64 } 50 65 51 - /* 52 - * All of the devices should normally fit in the hash, so we optimize 53 - * for that case. 66 + /** 67 + * sel_netif_find - Search for an interface record 68 + * @ifindex: the network interface 69 + * 70 + * Description: 71 + * Search the network interface table and return the record matching @ifindex. 72 + * If an entry can not be found in the table return NULL. 73 + * 54 74 */ 55 - static inline struct sel_netif *sel_netif_find(struct net_device *dev) 75 + static inline struct sel_netif *sel_netif_find(int ifindex) 56 76 { 57 - struct list_head *pos; 58 - int idx = sel_netif_hasfn(dev); 77 + int idx = sel_netif_hashfn(ifindex); 78 + struct sel_netif *netif; 59 79 60 - __list_for_each_rcu(pos, &sel_netif_hash[idx]) { 61 - struct sel_netif *netif = list_entry(pos, 62 - struct sel_netif, list); 63 - if (likely(netif->nsec.dev == dev)) 80 + list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list) 81 + /* all of the devices should normally fit in the hash, so we 82 + * optimize for that case */ 83 + if (likely(netif->nsec.ifindex == ifindex)) 64 84 return netif; 65 - } 85 + 66 86 return NULL; 67 87 } 68 88 89 + /** 90 + * sel_netif_insert - Insert a new interface into the table 91 + * @netif: the new interface record 92 + * 93 + * Description: 94 + * Add a new interface record to the network interface hash table. Returns 95 + * zero on success, negative values on failure. 96 + * 97 + */ 69 98 static int sel_netif_insert(struct sel_netif *netif) 70 99 { 71 - int idx, ret = 0; 100 + int idx; 72 101 73 - if (sel_netif_total >= SEL_NETIF_HASH_MAX) { 74 - ret = -ENOSPC; 75 - goto out; 76 - } 102 + if (sel_netif_total >= SEL_NETIF_HASH_MAX) 103 + return -ENOSPC; 77 104 78 - idx = sel_netif_hasfn(netif->nsec.dev); 105 + idx = sel_netif_hashfn(netif->nsec.ifindex); 79 106 list_add_rcu(&netif->list, &sel_netif_hash[idx]); 80 107 sel_netif_total++; 81 - out: 82 - return ret; 108 + 109 + return 0; 83 110 } 84 111 112 + /** 113 + * sel_netif_free - Frees an interface entry 114 + * @p: the entry's RCU field 115 + * 116 + * Description: 117 + * This function is designed to be used as a callback to the call_rcu() 118 + * function so that memory allocated to a hash table interface entry can be 119 + * released safely. 120 + * 121 + */ 85 122 static void sel_netif_free(struct rcu_head *p) 86 123 { 87 124 struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head); 88 - 89 - DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name); 90 125 kfree(netif); 91 126 } 92 127 128 + /** 129 + * sel_netif_destroy - Remove an interface record from the table 130 + * @netif: the existing interface record 131 + * 132 + * Description: 133 + * Remove an existing interface record from the network interface table. 134 + * 135 + */ 93 136 static void sel_netif_destroy(struct sel_netif *netif) 94 137 { 95 - DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name); 96 - 97 138 list_del_rcu(&netif->list); 98 139 sel_netif_total--; 99 140 call_rcu(&netif->rcu_head, sel_netif_free); 100 141 } 101 142 102 - static struct sel_netif *sel_netif_lookup(struct net_device *dev) 143 + /** 144 + * sel_netif_sid_slow - Lookup the SID of a network interface using the policy 145 + * @ifindex: the network interface 146 + * @sid: interface SID 147 + * 148 + * Description: 149 + * This function determines the SID of a network interface by quering the 150 + * security policy. The result is added to the network interface table to 151 + * speedup future queries. Returns zero on success, negative values on 152 + * failure. 153 + * 154 + */ 155 + static int sel_netif_sid_slow(int ifindex, u32 *sid) 103 156 { 104 157 int ret; 105 - struct sel_netif *netif, *new; 106 - struct netif_security_struct *nsec; 158 + struct sel_netif *netif; 159 + struct sel_netif *new = NULL; 160 + struct net_device *dev; 107 161 108 - netif = sel_netif_find(dev); 109 - if (likely(netif != NULL)) 110 - goto out; 111 - 112 - new = kzalloc(sizeof(*new), GFP_ATOMIC); 113 - if (!new) { 114 - netif = ERR_PTR(-ENOMEM); 115 - goto out; 116 - } 117 - 118 - nsec = &new->nsec; 162 + /* NOTE: we always use init's network namespace since we don't 163 + * currently support containers */ 119 164 120 - ret = security_netif_sid(dev->name, &nsec->if_sid, &nsec->msg_sid); 121 - if (ret < 0) { 122 - kfree(new); 123 - netif = ERR_PTR(ret); 124 - goto out; 125 - } 165 + dev = dev_get_by_index(&init_net, ifindex); 166 + if (dev == NULL) 167 + return -ENOENT; 126 168 127 - nsec->dev = dev; 128 - 129 169 spin_lock_bh(&sel_netif_lock); 130 - 131 - netif = sel_netif_find(dev); 132 - if (netif) { 133 - spin_unlock_bh(&sel_netif_lock); 134 - kfree(new); 170 + netif = sel_netif_find(ifindex); 171 + if (netif != NULL) { 172 + *sid = netif->nsec.sid; 173 + ret = 0; 135 174 goto out; 136 175 } 137 - 176 + new = kzalloc(sizeof(*new), GFP_ATOMIC); 177 + if (new == NULL) { 178 + ret = -ENOMEM; 179 + goto out; 180 + } 181 + ret = security_netif_sid(dev->name, &new->nsec.sid); 182 + if (ret != 0) 183 + goto out; 184 + new->nsec.ifindex = ifindex; 138 185 ret = sel_netif_insert(new); 139 - spin_unlock_bh(&sel_netif_lock); 140 - 141 - if (ret) { 142 - kfree(new); 143 - netif = ERR_PTR(ret); 186 + if (ret != 0) 144 187 goto out; 145 - } 188 + *sid = new->nsec.sid; 146 189 147 - netif = new; 148 - 149 - DEBUGP("new: ifindex=%u name=%s if_sid=%u msg_sid=%u\n", dev->ifindex, dev->name, 150 - nsec->if_sid, nsec->msg_sid); 151 190 out: 152 - return netif; 153 - } 154 - 155 - static void sel_netif_assign_sids(u32 if_sid_in, u32 msg_sid_in, u32 *if_sid_out, u32 *msg_sid_out) 156 - { 157 - if (if_sid_out) 158 - *if_sid_out = if_sid_in; 159 - if (msg_sid_out) 160 - *msg_sid_out = msg_sid_in; 161 - } 162 - 163 - static int sel_netif_sids_slow(struct net_device *dev, u32 *if_sid, u32 *msg_sid) 164 - { 165 - int ret = 0; 166 - u32 tmp_if_sid, tmp_msg_sid; 167 - 168 - ret = security_netif_sid(dev->name, &tmp_if_sid, &tmp_msg_sid); 169 - if (!ret) 170 - sel_netif_assign_sids(tmp_if_sid, tmp_msg_sid, if_sid, msg_sid); 191 + spin_unlock_bh(&sel_netif_lock); 192 + dev_put(dev); 193 + if (ret != 0) 194 + kfree(new); 171 195 return ret; 172 196 } 173 197 174 - int sel_netif_sids(struct net_device *dev, u32 *if_sid, u32 *msg_sid) 198 + /** 199 + * sel_netif_sid - Lookup the SID of a network interface 200 + * @ifindex: the network interface 201 + * @sid: interface SID 202 + * 203 + * Description: 204 + * This function determines the SID of a network interface using the fastest 205 + * method possible. First the interface table is queried, but if an entry 206 + * can't be found then the policy is queried and the result is added to the 207 + * table to speedup future queries. Returns zero on success, negative values 208 + * on failure. 209 + * 210 + */ 211 + int sel_netif_sid(int ifindex, u32 *sid) 175 212 { 176 - int ret = 0; 177 213 struct sel_netif *netif; 178 214 179 215 rcu_read_lock(); 180 - netif = sel_netif_lookup(dev); 181 - if (IS_ERR(netif)) { 216 + netif = sel_netif_find(ifindex); 217 + if (likely(netif != NULL)) { 218 + *sid = netif->nsec.sid; 182 219 rcu_read_unlock(); 183 - ret = sel_netif_sids_slow(dev, if_sid, msg_sid); 184 - goto out; 220 + return 0; 185 221 } 186 - sel_netif_assign_sids(netif->nsec.if_sid, netif->nsec.msg_sid, if_sid, msg_sid); 187 222 rcu_read_unlock(); 188 - out: 189 - return ret; 223 + 224 + return sel_netif_sid_slow(ifindex, sid); 190 225 } 191 226 192 - static void sel_netif_kill(struct net_device *dev) 227 + /** 228 + * sel_netif_kill - Remove an entry from the network interface table 229 + * @ifindex: the network interface 230 + * 231 + * Description: 232 + * This function removes the entry matching @ifindex from the network interface 233 + * table if it exists. 234 + * 235 + */ 236 + static void sel_netif_kill(int ifindex) 193 237 { 194 238 struct sel_netif *netif; 195 239 196 240 spin_lock_bh(&sel_netif_lock); 197 - netif = sel_netif_find(dev); 241 + netif = sel_netif_find(ifindex); 198 242 if (netif) 199 243 sel_netif_destroy(netif); 200 244 spin_unlock_bh(&sel_netif_lock); 201 245 } 202 246 247 + /** 248 + * sel_netif_flush - Flush the entire network interface table 249 + * 250 + * Description: 251 + * Remove all entries from the network interface table. 252 + * 253 + */ 203 254 static void sel_netif_flush(void) 204 255 { 205 256 int idx; 257 + struct sel_netif *netif; 206 258 207 259 spin_lock_bh(&sel_netif_lock); 208 - for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) { 209 - struct sel_netif *netif; 210 - 260 + for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) 211 261 list_for_each_entry(netif, &sel_netif_hash[idx], list) 212 262 sel_netif_destroy(netif); 213 - } 214 263 spin_unlock_bh(&sel_netif_lock); 215 264 } 216 265 ··· 276 239 return NOTIFY_DONE; 277 240 278 241 if (event == NETDEV_DOWN) 279 - sel_netif_kill(dev); 242 + sel_netif_kill(dev->ifindex); 280 243 281 244 return NOTIFY_DONE; 282 245 } ··· 287 250 288 251 static __init int sel_netif_init(void) 289 252 { 290 - int i, err = 0; 253 + int i, err; 291 254 292 255 if (!selinux_enabled) 293 - goto out; 256 + return 0; 294 257 295 258 for (i = 0; i < SEL_NETIF_HASH_SIZE; i++) 296 259 INIT_LIST_HEAD(&sel_netif_hash[i]); ··· 302 265 if (err) 303 266 panic("avc_add_callback() failed, error %d\n", err); 304 267 305 - out: 306 268 return err; 307 269 } 308 270
+2 -8
security/selinux/ss/services.c
··· 1478 1478 * security_netif_sid - Obtain the SID for a network interface. 1479 1479 * @name: interface name 1480 1480 * @if_sid: interface SID 1481 - * @msg_sid: default SID for received packets 1482 1481 */ 1483 - int security_netif_sid(char *name, 1484 - u32 *if_sid, 1485 - u32 *msg_sid) 1482 + int security_netif_sid(char *name, u32 *if_sid) 1486 1483 { 1487 1484 int rc = 0; 1488 1485 struct ocontext *c; ··· 1507 1510 goto out; 1508 1511 } 1509 1512 *if_sid = c->sid[0]; 1510 - *msg_sid = c->sid[1]; 1511 - } else { 1513 + } else 1512 1514 *if_sid = SECINITSID_NETIF; 1513 - *msg_sid = SECINITSID_NETMSG; 1514 - } 1515 1515 1516 1516 out: 1517 1517 POLICY_RDUNLOCK;