aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-01-30 17:32:24 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-01-30 17:32:24 -0500
commit44c3b59102e3ecc7a01e9811862633e670595e51 (patch)
tree5bf397b2b4bd8fc08c59ad5f9f9c83874259da48
parent3b470ac43fcd9848fa65e58e54875ad75be61cec (diff)
parentf71ea9ddf0ff110f3fcbb89a46686bfba264014c (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6: security: compile capabilities by default selinux: make selinux_set_mnt_opts() static SELinux: Add warning messages on network denial due to error SELinux: Add network ingress and egress control permission checks NetLabel: Add auditing to the static labeling mechanism NetLabel: Introduce static network labels for unlabeled connections SELinux: Allow NetLabel to directly cache SIDs SELinux: Enable dynamic enable/disable of the network access checks SELinux: Better integration between peer labeling subsystems SELinux: Add a new peer class and permissions to the Flask definitions SELinux: Add a capabilities bitmap to SELinux policy version 22 SELinux: Add a network node caching mechanism similar to the sel_netif_*() functions SELinux: Only store the network interface's ifindex SELinux: Convert the netif code to use ifindex values NetLabel: Add IP address family information to the netlbl_skbuff_getattr() function NetLabel: Add secid token support to the NetLabel secattr struct NetLabel: Consolidate the LSM domain mapping/hashing locks NetLabel: Cleanup the LSM domain hash functions NetLabel: Remove unneeded RCU read locks
-rw-r--r--include/linux/audit.h2
-rw-r--r--include/linux/selinux.h45
-rw-r--r--include/net/netlabel.h99
-rw-r--r--net/ipv4/cipso_ipv4.c59
-rw-r--r--net/netfilter/xt_SECMARK.c13
-rw-r--r--net/netlabel/netlabel_cipso_v4.c5
-rw-r--r--net/netlabel/netlabel_domainhash.c77
-rw-r--r--net/netlabel/netlabel_kapi.c21
-rw-r--r--net/netlabel/netlabel_mgmt.c63
-rw-r--r--net/netlabel/netlabel_mgmt.h7
-rw-r--r--net/netlabel/netlabel_unlabeled.c1565
-rw-r--r--net/netlabel/netlabel_unlabeled.h145
-rw-r--r--security/Kconfig1
-rw-r--r--security/selinux/Kconfig2
-rw-r--r--security/selinux/Makefile9
-rw-r--r--security/selinux/avc.c15
-rw-r--r--security/selinux/exports.c20
-rw-r--r--security/selinux/hooks.c667
-rw-r--r--security/selinux/include/av_perm_to_string.h9
-rw-r--r--security/selinux/include/av_permissions.h9
-rw-r--r--security/selinux/include/avc.h2
-rw-r--r--security/selinux/include/class_to_string.h7
-rw-r--r--security/selinux/include/flask.h1
-rw-r--r--security/selinux/include/netif.h4
-rw-r--r--security/selinux/include/netlabel.h11
-rw-r--r--security/selinux/include/netnode.h32
-rw-r--r--security/selinux/include/objsec.h16
-rw-r--r--security/selinux/include/security.h24
-rw-r--r--security/selinux/include/xfrm.h12
-rw-r--r--security/selinux/netif.c263
-rw-r--r--security/selinux/netlabel.c75
-rw-r--r--security/selinux/netnode.c354
-rw-r--r--security/selinux/selinuxfs.c89
-rw-r--r--security/selinux/ss/mls.c10
-rw-r--r--security/selinux/ss/policydb.c18
-rw-r--r--security/selinux/ss/policydb.h2
-rw-r--r--security/selinux/ss/services.c291
-rw-r--r--security/selinux/xfrm.c18
38 files changed, 3380 insertions, 682 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h
index c68781692838..bdd6f5de5fc4 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -115,6 +115,8 @@
115#define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Not used */ 115#define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Not used */
116#define AUDIT_MAC_IPSEC_DELSPD 1414 /* Not used */ 116#define AUDIT_MAC_IPSEC_DELSPD 1414 /* Not used */
117#define AUDIT_MAC_IPSEC_EVENT 1415 /* Audit an IPSec event */ 117#define AUDIT_MAC_IPSEC_EVENT 1415 /* Audit an IPSec event */
118#define AUDIT_MAC_UNLBL_STCADD 1416 /* NetLabel: add a static label */
119#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
118 120
119#define AUDIT_FIRST_KERN_ANOM_MSG 1700 121#define AUDIT_FIRST_KERN_ANOM_MSG 1700
120#define AUDIT_LAST_KERN_ANOM_MSG 1799 122#define AUDIT_LAST_KERN_ANOM_MSG 1799
diff --git a/include/linux/selinux.h b/include/linux/selinux.h
index 6080f73fc85f..8c2cc4c02526 100644
--- a/include/linux/selinux.h
+++ b/include/linux/selinux.h
@@ -120,16 +120,35 @@ void selinux_get_task_sid(struct task_struct *tsk, u32 *sid);
120int selinux_string_to_sid(char *str, u32 *sid); 120int selinux_string_to_sid(char *str, u32 *sid);
121 121
122/** 122/**
123 * selinux_relabel_packet_permission - check permission to relabel a packet 123 * selinux_secmark_relabel_packet_permission - secmark permission check
124 * @sid: ID value to be applied to network packet (via SECMARK, most likely) 124 * @sid: SECMARK ID value to be applied to network packet
125 * 125 *
126 * Returns 0 if the current task is allowed to label packets with the 126 * Returns 0 if the current task is allowed to set the SECMARK label of
127 * supplied security ID. Note that it is implicit that the packet is always 127 * packets with the supplied security ID. Note that it is implicit that
128 * being relabeled from the default unlabled value, and that the access 128 * the packet is always being relabeled from the default unlabeled value,
129 * control decision is made in the AVC. 129 * and that the access control decision is made in the AVC.
130 */ 130 */
131int selinux_relabel_packet_permission(u32 sid); 131int selinux_secmark_relabel_packet_permission(u32 sid);
132 132
133/**
134 * selinux_secmark_refcount_inc - increments the secmark use counter
135 *
136 * SELinux keeps track of the current SECMARK targets in use so it knows
137 * when to apply SECMARK label access checks to network packets. This
138 * function incements this reference count to indicate that a new SECMARK
139 * target has been configured.
140 */
141void selinux_secmark_refcount_inc(void);
142
143/**
144 * selinux_secmark_refcount_dec - decrements the secmark use counter
145 *
146 * SELinux keeps track of the current SECMARK targets in use so it knows
147 * when to apply SECMARK label access checks to network packets. This
148 * function decements this reference count to indicate that one of the
149 * existing SECMARK targets has been removed/flushed.
150 */
151void selinux_secmark_refcount_dec(void);
133#else 152#else
134 153
135static inline int selinux_audit_rule_init(u32 field, u32 op, 154static inline int selinux_audit_rule_init(u32 field, u32 op,
@@ -184,11 +203,21 @@ static inline int selinux_string_to_sid(const char *str, u32 *sid)
184 return 0; 203 return 0;
185} 204}
186 205
187static inline int selinux_relabel_packet_permission(u32 sid) 206static inline int selinux_secmark_relabel_packet_permission(u32 sid)
188{ 207{
189 return 0; 208 return 0;
190} 209}
191 210
211static inline void selinux_secmark_refcount_inc(void)
212{
213 return;
214}
215
216static inline void selinux_secmark_refcount_dec(void)
217{
218 return;
219}
220
192#endif /* CONFIG_SECURITY_SELINUX */ 221#endif /* CONFIG_SECURITY_SELINUX */
193 222
194#endif /* _LINUX_SELINUX_H */ 223#endif /* _LINUX_SELINUX_H */
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index 2e5b2f6f9fa0..b3213c7c5309 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -67,7 +67,11 @@
67 * NetLabel NETLINK protocol 67 * NetLabel NETLINK protocol
68 */ 68 */
69 69
70#define NETLBL_PROTO_VERSION 1 70/* NetLabel NETLINK protocol version
71 * 1: initial version
72 * 2: added static labels for unlabeled connections
73 */
74#define NETLBL_PROTO_VERSION 2
71 75
72/* NetLabel NETLINK types/families */ 76/* NetLabel NETLINK types/families */
73#define NETLBL_NLTYPE_NONE 0 77#define NETLBL_NLTYPE_NONE 0
@@ -105,17 +109,49 @@ struct netlbl_dom_map;
105/* Domain mapping operations */ 109/* Domain mapping operations */
106int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); 110int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
107 111
108/* LSM security attributes */ 112/*
113 * LSM security attributes
114 */
115
116/**
117 * struct netlbl_lsm_cache - NetLabel LSM security attribute cache
118 * @refcount: atomic reference counter
119 * @free: LSM supplied function to free the cache data
120 * @data: LSM supplied cache data
121 *
122 * Description:
123 * This structure is provided for LSMs which wish to make use of the NetLabel
124 * caching mechanism to store LSM specific data/attributes in the NetLabel
125 * cache. If the LSM has to perform a lot of translation from the NetLabel
126 * security attributes into it's own internal representation then the cache
127 * mechanism can provide a way to eliminate some or all of that translation
128 * overhead on a cache hit.
129 *
130 */
109struct netlbl_lsm_cache { 131struct netlbl_lsm_cache {
110 atomic_t refcount; 132 atomic_t refcount;
111 void (*free) (const void *data); 133 void (*free) (const void *data);
112 void *data; 134 void *data;
113}; 135};
114/* The catmap bitmap field MUST be a power of two in length and large 136
137/**
138 * struct netlbl_lsm_secattr_catmap - NetLabel LSM secattr category bitmap
139 * @startbit: the value of the lowest order bit in the bitmap
140 * @bitmap: the category bitmap
141 * @next: pointer to the next bitmap "node" or NULL
142 *
143 * Description:
144 * This structure is used to represent category bitmaps. Due to the large
145 * number of categories supported by most labeling protocols it is not
146 * practical to transfer a full bitmap internally so NetLabel adopts a sparse
147 * bitmap structure modeled after SELinux's ebitmap structure.
148 * The catmap bitmap field MUST be a power of two in length and large
115 * enough to hold at least 240 bits. Special care (i.e. check the code!) 149 * enough to hold at least 240 bits. Special care (i.e. check the code!)
116 * should be used when changing these values as the LSM implementation 150 * should be used when changing these values as the LSM implementation
117 * probably has functions which rely on the sizes of these types to speed 151 * probably has functions which rely on the sizes of these types to speed
118 * processing. */ 152 * processing.
153 *
154 */
119#define NETLBL_CATMAP_MAPTYPE u64 155#define NETLBL_CATMAP_MAPTYPE u64
120#define NETLBL_CATMAP_MAPCNT 4 156#define NETLBL_CATMAP_MAPCNT 4
121#define NETLBL_CATMAP_MAPSIZE (sizeof(NETLBL_CATMAP_MAPTYPE) * 8) 157#define NETLBL_CATMAP_MAPSIZE (sizeof(NETLBL_CATMAP_MAPTYPE) * 8)
@@ -127,22 +163,48 @@ struct netlbl_lsm_secattr_catmap {
127 NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT]; 163 NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT];
128 struct netlbl_lsm_secattr_catmap *next; 164 struct netlbl_lsm_secattr_catmap *next;
129}; 165};
166
167/**
168 * struct netlbl_lsm_secattr - NetLabel LSM security attributes
169 * @flags: indicate which attributes are contained in this structure
170 * @type: indicate the NLTYPE of the attributes
171 * @domain: the NetLabel LSM domain
172 * @cache: NetLabel LSM specific cache
173 * @attr.mls: MLS sensitivity label
174 * @attr.mls.cat: MLS category bitmap
175 * @attr.mls.lvl: MLS sensitivity level
176 * @attr.secid: LSM specific secid token
177 *
178 * Description:
179 * This structure is used to pass security attributes between NetLabel and the
180 * LSM modules. The flags field is used to specify which fields within the
181 * struct are valid and valid values can be created by bitwise OR'ing the
182 * NETLBL_SECATTR_* defines. The domain field is typically set by the LSM to
183 * specify domain specific configuration settings and is not usually used by
184 * NetLabel itself when returning security attributes to the LSM.
185 *
186 */
130#define NETLBL_SECATTR_NONE 0x00000000 187#define NETLBL_SECATTR_NONE 0x00000000
131#define NETLBL_SECATTR_DOMAIN 0x00000001 188#define NETLBL_SECATTR_DOMAIN 0x00000001
132#define NETLBL_SECATTR_CACHE 0x00000002 189#define NETLBL_SECATTR_CACHE 0x00000002
133#define NETLBL_SECATTR_MLS_LVL 0x00000004 190#define NETLBL_SECATTR_MLS_LVL 0x00000004
134#define NETLBL_SECATTR_MLS_CAT 0x00000008 191#define NETLBL_SECATTR_MLS_CAT 0x00000008
192#define NETLBL_SECATTR_SECID 0x00000010
135#define NETLBL_SECATTR_CACHEABLE (NETLBL_SECATTR_MLS_LVL | \ 193#define NETLBL_SECATTR_CACHEABLE (NETLBL_SECATTR_MLS_LVL | \
136 NETLBL_SECATTR_MLS_CAT) 194 NETLBL_SECATTR_MLS_CAT | \
195 NETLBL_SECATTR_SECID)
137struct netlbl_lsm_secattr { 196struct netlbl_lsm_secattr {
138 u32 flags; 197 u32 flags;
139 198 u32 type;
140 char *domain; 199 char *domain;
141
142 u32 mls_lvl;
143 struct netlbl_lsm_secattr_catmap *mls_cat;
144
145 struct netlbl_lsm_cache *cache; 200 struct netlbl_lsm_cache *cache;
201 union {
202 struct {
203 struct netlbl_lsm_secattr_catmap *cat;
204 u32 lvl;
205 } mls;
206 u32 secid;
207 } attr;
146}; 208};
147 209
148/* 210/*
@@ -231,10 +293,7 @@ static inline void netlbl_secattr_catmap_free(
231 */ 293 */
232static inline void netlbl_secattr_init(struct netlbl_lsm_secattr *secattr) 294static inline void netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
233{ 295{
234 secattr->flags = 0; 296 memset(secattr, 0, sizeof(*secattr));
235 secattr->domain = NULL;
236 secattr->mls_cat = NULL;
237 secattr->cache = NULL;
238} 297}
239 298
240/** 299/**
@@ -248,11 +307,11 @@ static inline void netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
248 */ 307 */
249static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr) 308static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
250{ 309{
251 if (secattr->cache)
252 netlbl_secattr_cache_free(secattr->cache);
253 kfree(secattr->domain); 310 kfree(secattr->domain);
254 if (secattr->mls_cat) 311 if (secattr->flags & NETLBL_SECATTR_CACHE)
255 netlbl_secattr_catmap_free(secattr->mls_cat); 312 netlbl_secattr_cache_free(secattr->cache);
313 if (secattr->flags & NETLBL_SECATTR_MLS_CAT)
314 netlbl_secattr_catmap_free(secattr->attr.mls.cat);
256} 315}
257 316
258/** 317/**
@@ -300,7 +359,7 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
300 gfp_t flags); 359 gfp_t flags);
301 360
302/* 361/*
303 * LSM protocol operations 362 * LSM protocol operations (NetLabel LSM/kernel API)
304 */ 363 */
305int netlbl_enabled(void); 364int netlbl_enabled(void);
306int netlbl_sock_setattr(struct sock *sk, 365int netlbl_sock_setattr(struct sock *sk,
@@ -308,6 +367,7 @@ int netlbl_sock_setattr(struct sock *sk,
308int netlbl_sock_getattr(struct sock *sk, 367int netlbl_sock_getattr(struct sock *sk,
309 struct netlbl_lsm_secattr *secattr); 368 struct netlbl_lsm_secattr *secattr);
310int netlbl_skbuff_getattr(const struct sk_buff *skb, 369int netlbl_skbuff_getattr(const struct sk_buff *skb,
370 u16 family,
311 struct netlbl_lsm_secattr *secattr); 371 struct netlbl_lsm_secattr *secattr);
312void netlbl_skbuff_err(struct sk_buff *skb, int error); 372void netlbl_skbuff_err(struct sk_buff *skb, int error);
313 373
@@ -360,6 +420,7 @@ static inline int netlbl_sock_getattr(struct sock *sk,
360 return -ENOSYS; 420 return -ENOSYS;
361} 421}
362static inline int netlbl_skbuff_getattr(const struct sk_buff *skb, 422static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
423 u16 family,
363 struct netlbl_lsm_secattr *secattr) 424 struct netlbl_lsm_secattr *secattr)
364{ 425{
365 return -ENOSYS; 426 return -ENOSYS;
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index d4dc4eb48d95..a2241060113b 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -348,6 +348,7 @@ static int cipso_v4_cache_check(const unsigned char *key,
348 atomic_inc(&entry->lsm_data->refcount); 348 atomic_inc(&entry->lsm_data->refcount);
349 secattr->cache = entry->lsm_data; 349 secattr->cache = entry->lsm_data;
350 secattr->flags |= NETLBL_SECATTR_CACHE; 350 secattr->flags |= NETLBL_SECATTR_CACHE;
351 secattr->type = NETLBL_NLTYPE_CIPSOV4;
351 if (prev_entry == NULL) { 352 if (prev_entry == NULL) {
352 spin_unlock_bh(&cipso_v4_cache[bkt].lock); 353 spin_unlock_bh(&cipso_v4_cache[bkt].lock);
353 return 0; 354 return 0;
@@ -865,7 +866,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
865 } 866 }
866 867
867 for (;;) { 868 for (;;) {
868 host_spot = netlbl_secattr_catmap_walk(secattr->mls_cat, 869 host_spot = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
869 host_spot + 1); 870 host_spot + 1);
870 if (host_spot < 0) 871 if (host_spot < 0)
871 break; 872 break;
@@ -948,7 +949,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
948 return -EPERM; 949 return -EPERM;
949 break; 950 break;
950 } 951 }
951 ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, 952 ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
952 host_spot, 953 host_spot,
953 GFP_ATOMIC); 954 GFP_ATOMIC);
954 if (ret_val != 0) 955 if (ret_val != 0)
@@ -1014,7 +1015,8 @@ static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def,
1014 u32 cat_iter = 0; 1015 u32 cat_iter = 0;
1015 1016
1016 for (;;) { 1017 for (;;) {
1017 cat = netlbl_secattr_catmap_walk(secattr->mls_cat, cat + 1); 1018 cat = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
1019 cat + 1);
1018 if (cat < 0) 1020 if (cat < 0)
1019 break; 1021 break;
1020 if ((cat_iter + 2) > net_cat_len) 1022 if ((cat_iter + 2) > net_cat_len)
@@ -1049,7 +1051,7 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def,
1049 u32 iter; 1051 u32 iter;
1050 1052
1051 for (iter = 0; iter < net_cat_len; iter += 2) { 1053 for (iter = 0; iter < net_cat_len; iter += 2) {
1052 ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, 1054 ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
1053 ntohs(get_unaligned((__be16 *)&net_cat[iter])), 1055 ntohs(get_unaligned((__be16 *)&net_cat[iter])),
1054 GFP_ATOMIC); 1056 GFP_ATOMIC);
1055 if (ret_val != 0) 1057 if (ret_val != 0)
@@ -1130,7 +1132,8 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def,
1130 return -ENOSPC; 1132 return -ENOSPC;
1131 1133
1132 for (;;) { 1134 for (;;) {
1133 iter = netlbl_secattr_catmap_walk(secattr->mls_cat, iter + 1); 1135 iter = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
1136 iter + 1);
1134 if (iter < 0) 1137 if (iter < 0)
1135 break; 1138 break;
1136 cat_size += (iter == 0 ? 0 : sizeof(u16)); 1139 cat_size += (iter == 0 ? 0 : sizeof(u16));
@@ -1138,7 +1141,8 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def,
1138 return -ENOSPC; 1141 return -ENOSPC;
1139 array[array_cnt++] = iter; 1142 array[array_cnt++] = iter;
1140 1143
1141 iter = netlbl_secattr_catmap_walk_rng(secattr->mls_cat, iter); 1144 iter = netlbl_secattr_catmap_walk_rng(secattr->attr.mls.cat,
1145 iter);
1142 if (iter < 0) 1146 if (iter < 0)
1143 return -EFAULT; 1147 return -EFAULT;
1144 cat_size += sizeof(u16); 1148 cat_size += sizeof(u16);
@@ -1191,7 +1195,7 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def,
1191 else 1195 else
1192 cat_low = 0; 1196 cat_low = 0;
1193 1197
1194 ret_val = netlbl_secattr_catmap_setrng(secattr->mls_cat, 1198 ret_val = netlbl_secattr_catmap_setrng(secattr->attr.mls.cat,
1195 cat_low, 1199 cat_low,
1196 cat_high, 1200 cat_high,
1197 GFP_ATOMIC); 1201 GFP_ATOMIC);
@@ -1251,7 +1255,9 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
1251 if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0) 1255 if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0)
1252 return -EPERM; 1256 return -EPERM;
1253 1257
1254 ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); 1258 ret_val = cipso_v4_map_lvl_hton(doi_def,
1259 secattr->attr.mls.lvl,
1260 &level);
1255 if (ret_val != 0) 1261 if (ret_val != 0)
1256 return ret_val; 1262 return ret_val;
1257 1263
@@ -1303,12 +1309,13 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
1303 ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); 1309 ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
1304 if (ret_val != 0) 1310 if (ret_val != 0)
1305 return ret_val; 1311 return ret_val;
1306 secattr->mls_lvl = level; 1312 secattr->attr.mls.lvl = level;
1307 secattr->flags |= NETLBL_SECATTR_MLS_LVL; 1313 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1308 1314
1309 if (tag_len > 4) { 1315 if (tag_len > 4) {
1310 secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); 1316 secattr->attr.mls.cat =
1311 if (secattr->mls_cat == NULL) 1317 netlbl_secattr_catmap_alloc(GFP_ATOMIC);
1318 if (secattr->attr.mls.cat == NULL)
1312 return -ENOMEM; 1319 return -ENOMEM;
1313 1320
1314 ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, 1321 ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
@@ -1316,7 +1323,7 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
1316 tag_len - 4, 1323 tag_len - 4,
1317 secattr); 1324 secattr);
1318 if (ret_val != 0) { 1325 if (ret_val != 0) {
1319 netlbl_secattr_catmap_free(secattr->mls_cat); 1326 netlbl_secattr_catmap_free(secattr->attr.mls.cat);
1320 return ret_val; 1327 return ret_val;
1321 } 1328 }
1322 1329
@@ -1350,7 +1357,9 @@ static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def,
1350 if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) 1357 if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL))
1351 return -EPERM; 1358 return -EPERM;
1352 1359
1353 ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); 1360 ret_val = cipso_v4_map_lvl_hton(doi_def,
1361 secattr->attr.mls.lvl,
1362 &level);
1354 if (ret_val != 0) 1363 if (ret_val != 0)
1355 return ret_val; 1364 return ret_val;
1356 1365
@@ -1396,12 +1405,13 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def,
1396 ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); 1405 ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
1397 if (ret_val != 0) 1406 if (ret_val != 0)
1398 return ret_val; 1407 return ret_val;
1399 secattr->mls_lvl = level; 1408 secattr->attr.mls.lvl = level;
1400 secattr->flags |= NETLBL_SECATTR_MLS_LVL; 1409 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1401 1410
1402 if (tag_len > 4) { 1411 if (tag_len > 4) {
1403 secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); 1412 secattr->attr.mls.cat =
1404 if (secattr->mls_cat == NULL) 1413 netlbl_secattr_catmap_alloc(GFP_ATOMIC);
1414 if (secattr->attr.mls.cat == NULL)
1405 return -ENOMEM; 1415 return -ENOMEM;
1406 1416
1407 ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, 1417 ret_val = cipso_v4_map_cat_enum_ntoh(doi_def,
@@ -1409,7 +1419,7 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def,
1409 tag_len - 4, 1419 tag_len - 4,
1410 secattr); 1420 secattr);
1411 if (ret_val != 0) { 1421 if (ret_val != 0) {
1412 netlbl_secattr_catmap_free(secattr->mls_cat); 1422 netlbl_secattr_catmap_free(secattr->attr.mls.cat);
1413 return ret_val; 1423 return ret_val;
1414 } 1424 }
1415 1425
@@ -1443,7 +1453,9 @@ static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def,
1443 if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) 1453 if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL))
1444 return -EPERM; 1454 return -EPERM;
1445 1455
1446 ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); 1456 ret_val = cipso_v4_map_lvl_hton(doi_def,
1457 secattr->attr.mls.lvl,
1458 &level);
1447 if (ret_val != 0) 1459 if (ret_val != 0)
1448 return ret_val; 1460 return ret_val;
1449 1461
@@ -1488,12 +1500,13 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
1488 ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); 1500 ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
1489 if (ret_val != 0) 1501 if (ret_val != 0)
1490 return ret_val; 1502 return ret_val;
1491 secattr->mls_lvl = level; 1503 secattr->attr.mls.lvl = level;
1492 secattr->flags |= NETLBL_SECATTR_MLS_LVL; 1504 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1493 1505
1494 if (tag_len > 4) { 1506 if (tag_len > 4) {
1495 secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); 1507 secattr->attr.mls.cat =
1496 if (secattr->mls_cat == NULL) 1508 netlbl_secattr_catmap_alloc(GFP_ATOMIC);
1509 if (secattr->attr.mls.cat == NULL)
1497 return -ENOMEM; 1510 return -ENOMEM;
1498 1511
1499 ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, 1512 ret_val = cipso_v4_map_cat_rng_ntoh(doi_def,
@@ -1501,7 +1514,7 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
1501 tag_len - 4, 1514 tag_len - 4,
1502 secattr); 1515 secattr);
1503 if (ret_val != 0) { 1516 if (ret_val != 0) {
1504 netlbl_secattr_catmap_free(secattr->mls_cat); 1517 netlbl_secattr_catmap_free(secattr->attr.mls.cat);
1505 return ret_val; 1518 return ret_val;
1506 } 1519 }
1507 1520
@@ -1850,6 +1863,8 @@ static int cipso_v4_getattr(const unsigned char *cipso,
1850 ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr); 1863 ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);
1851 break; 1864 break;
1852 } 1865 }
1866 if (ret_val == 0)
1867 secattr->type = NETLBL_NLTYPE_CIPSOV4;
1853 1868
1854getattr_return: 1869getattr_return:
1855 rcu_read_unlock(); 1870 rcu_read_unlock();
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index b11b3ecbb39d..7708e2084ce2 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -72,12 +72,13 @@ static bool checkentry_selinux(struct xt_secmark_target_info *info)
72 return false; 72 return false;
73 } 73 }
74 74
75 err = selinux_relabel_packet_permission(sel->selsid); 75 err = selinux_secmark_relabel_packet_permission(sel->selsid);
76 if (err) { 76 if (err) {
77 printk(KERN_INFO PFX "unable to obtain relabeling permission\n"); 77 printk(KERN_INFO PFX "unable to obtain relabeling permission\n");
78 return false; 78 return false;
79 } 79 }
80 80
81 selinux_secmark_refcount_inc();
81 return true; 82 return true;
82} 83}
83 84
@@ -110,11 +111,20 @@ secmark_tg_check(const char *tablename, const void *entry,
110 return true; 111 return true;
111} 112}
112 113
114void secmark_tg_destroy(const struct xt_target *target, void *targinfo)
115{
116 switch (mode) {
117 case SECMARK_MODE_SEL:
118 selinux_secmark_refcount_dec();
119 }
120}
121
113static struct xt_target secmark_tg_reg[] __read_mostly = { 122static struct xt_target secmark_tg_reg[] __read_mostly = {
114 { 123 {
115 .name = "SECMARK", 124 .name = "SECMARK",
116 .family = AF_INET, 125 .family = AF_INET,
117 .checkentry = secmark_tg_check, 126 .checkentry = secmark_tg_check,
127 .destroy = secmark_tg_destroy,
118 .target = secmark_tg, 128 .target = secmark_tg,
119 .targetsize = sizeof(struct xt_secmark_target_info), 129 .targetsize = sizeof(struct xt_secmark_target_info),
120 .table = "mangle", 130 .table = "mangle",
@@ -124,6 +134,7 @@ static struct xt_target secmark_tg_reg[] __read_mostly = {
124 .name = "SECMARK", 134 .name = "SECMARK",
125 .family = AF_INET6, 135 .family = AF_INET6,
126 .checkentry = secmark_tg_check, 136 .checkentry = secmark_tg_check,
137 .destroy = secmark_tg_destroy,
127 .target = secmark_tg, 138 .target = secmark_tg,
128 .targetsize = sizeof(struct xt_secmark_target_info), 139 .targetsize = sizeof(struct xt_secmark_target_info),
129 .table = "mangle", 140 .table = "mangle",
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index ba0ca8d3f77d..becf91a952ae 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -38,6 +38,7 @@
38#include <net/genetlink.h> 38#include <net/genetlink.h>
39#include <net/netlabel.h> 39#include <net/netlabel.h>
40#include <net/cipso_ipv4.h> 40#include <net/cipso_ipv4.h>
41#include <asm/atomic.h>
41 42
42#include "netlabel_user.h" 43#include "netlabel_user.h"
43#include "netlabel_cipso_v4.h" 44#include "netlabel_cipso_v4.h"
@@ -421,7 +422,7 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
421 break; 422 break;
422 } 423 }
423 if (ret_val == 0) 424 if (ret_val == 0)
424 netlbl_mgmt_protocount_inc(); 425 atomic_inc(&netlabel_mgmt_protocount);
425 426
426 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, 427 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
427 &audit_info); 428 &audit_info);
@@ -698,7 +699,7 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
698 &audit_info, 699 &audit_info,
699 netlbl_cipsov4_doi_free); 700 netlbl_cipsov4_doi_free);
700 if (ret_val == 0) 701 if (ret_val == 0)
701 netlbl_mgmt_protocount_dec(); 702 atomic_dec(&netlabel_mgmt_protocount);
702 703
703 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, 704 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
704 &audit_info); 705 &audit_info);
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index b3675bd7db33..9a8ea0195c4f 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -54,9 +54,6 @@ struct netlbl_domhsh_tbl {
54 * hash table should be okay */ 54 * hash table should be okay */
55static DEFINE_SPINLOCK(netlbl_domhsh_lock); 55static DEFINE_SPINLOCK(netlbl_domhsh_lock);
56static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL; 56static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
57
58/* Default domain mapping */
59static DEFINE_SPINLOCK(netlbl_domhsh_def_lock);
60static struct netlbl_dom_map *netlbl_domhsh_def = NULL; 57static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
61 58
62/* 59/*
@@ -109,17 +106,14 @@ static u32 netlbl_domhsh_hash(const char *key)
109/** 106/**
110 * netlbl_domhsh_search - Search for a domain entry 107 * netlbl_domhsh_search - Search for a domain entry
111 * @domain: the domain 108 * @domain: the domain
112 * @def: return default if no match is found
113 * 109 *
114 * Description: 110 * Description:
115 * Searches the domain hash table and returns a pointer to the hash table 111 * Searches the domain hash table and returns a pointer to the hash table
116 * entry if found, otherwise NULL is returned. If @def is non-zero and a 112 * entry if found, otherwise NULL is returned. The caller is responsibile for
117 * match is not found in the domain hash table the default mapping is returned 113 * the rcu hash table locks (i.e. the caller much call rcu_read_[un]lock()).
118 * if it exists. The caller is responsibile for the rcu hash table locks
119 * (i.e. the caller much call rcu_read_[un]lock()).
120 * 114 *
121 */ 115 */
122static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, u32 def) 116static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
123{ 117{
124 u32 bkt; 118 u32 bkt;
125 struct netlbl_dom_map *iter; 119 struct netlbl_dom_map *iter;
@@ -133,10 +127,31 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, u32 def)
133 return iter; 127 return iter;
134 } 128 }
135 129
136 if (def != 0) { 130 return NULL;
137 iter = rcu_dereference(netlbl_domhsh_def); 131}
138 if (iter != NULL && iter->valid) 132
139 return iter; 133/**
134 * netlbl_domhsh_search_def - Search for a domain entry
135 * @domain: the domain
136 * @def: return default if no match is found
137 *
138 * Description:
139 * Searches the domain hash table and returns a pointer to the hash table
140 * entry if an exact match is found, if an exact match is not present in the
141 * hash table then the default entry is returned if valid otherwise NULL is
142 * returned. The caller is responsibile for the rcu hash table locks
143 * (i.e. the caller much call rcu_read_[un]lock()).
144 *
145 */
146static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
147{
148 struct netlbl_dom_map *entry;
149
150 entry = netlbl_domhsh_search(domain);
151 if (entry == NULL) {
152 entry = rcu_dereference(netlbl_domhsh_def);
153 if (entry != NULL && entry->valid)
154 return entry;
140 } 155 }
141 156
142 return NULL; 157 return NULL;
@@ -221,24 +236,22 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
221 INIT_RCU_HEAD(&entry->rcu); 236 INIT_RCU_HEAD(&entry->rcu);
222 237
223 rcu_read_lock(); 238 rcu_read_lock();
239 spin_lock(&netlbl_domhsh_lock);
224 if (entry->domain != NULL) { 240 if (entry->domain != NULL) {
225 bkt = netlbl_domhsh_hash(entry->domain); 241 bkt = netlbl_domhsh_hash(entry->domain);
226 spin_lock(&netlbl_domhsh_lock); 242 if (netlbl_domhsh_search(entry->domain) == NULL)
227 if (netlbl_domhsh_search(entry->domain, 0) == NULL)
228 list_add_tail_rcu(&entry->list, 243 list_add_tail_rcu(&entry->list,
229 &rcu_dereference(netlbl_domhsh)->tbl[bkt]); 244 &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
230 else 245 else
231 ret_val = -EEXIST; 246 ret_val = -EEXIST;
232 spin_unlock(&netlbl_domhsh_lock);
233 } else { 247 } else {
234 INIT_LIST_HEAD(&entry->list); 248 INIT_LIST_HEAD(&entry->list);
235 spin_lock(&netlbl_domhsh_def_lock);
236 if (rcu_dereference(netlbl_domhsh_def) == NULL) 249 if (rcu_dereference(netlbl_domhsh_def) == NULL)
237 rcu_assign_pointer(netlbl_domhsh_def, entry); 250 rcu_assign_pointer(netlbl_domhsh_def, entry);
238 else 251 else
239 ret_val = -EEXIST; 252 ret_val = -EEXIST;
240 spin_unlock(&netlbl_domhsh_def_lock);
241 } 253 }
254 spin_unlock(&netlbl_domhsh_lock);
242 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); 255 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
243 if (audit_buf != NULL) { 256 if (audit_buf != NULL) {
244 audit_log_format(audit_buf, 257 audit_log_format(audit_buf,
@@ -307,7 +320,10 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
307 struct audit_buffer *audit_buf; 320 struct audit_buffer *audit_buf;
308 321
309 rcu_read_lock(); 322 rcu_read_lock();
310 entry = netlbl_domhsh_search(domain, (domain != NULL ? 0 : 1)); 323 if (domain)
324 entry = netlbl_domhsh_search(domain);
325 else
326 entry = netlbl_domhsh_search_def(domain);
311 if (entry == NULL) 327 if (entry == NULL)
312 goto remove_return; 328 goto remove_return;
313 switch (entry->type) { 329 switch (entry->type) {
@@ -316,23 +332,16 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
316 entry->domain); 332 entry->domain);
317 break; 333 break;
318 } 334 }
319 if (entry != rcu_dereference(netlbl_domhsh_def)) { 335 spin_lock(&netlbl_domhsh_lock);
320 spin_lock(&netlbl_domhsh_lock); 336 if (entry->valid) {
321 if (entry->valid) { 337 entry->valid = 0;
322 entry->valid = 0; 338 if (entry != rcu_dereference(netlbl_domhsh_def))
323 list_del_rcu(&entry->list); 339 list_del_rcu(&entry->list);
324 ret_val = 0; 340 else
325 }
326 spin_unlock(&netlbl_domhsh_lock);
327 } else {
328 spin_lock(&netlbl_domhsh_def_lock);
329 if (entry->valid) {
330 entry->valid = 0;
331 rcu_assign_pointer(netlbl_domhsh_def, NULL); 341 rcu_assign_pointer(netlbl_domhsh_def, NULL);
332 ret_val = 0; 342 ret_val = 0;
333 }
334 spin_unlock(&netlbl_domhsh_def_lock);
335 } 343 }
344 spin_unlock(&netlbl_domhsh_lock);
336 345
337 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); 346 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
338 if (audit_buf != NULL) { 347 if (audit_buf != NULL) {
@@ -377,7 +386,7 @@ int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
377 */ 386 */
378struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain) 387struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
379{ 388{
380 return netlbl_domhsh_search(domain, 1); 389 return netlbl_domhsh_search_def(domain);
381} 390}
382 391
383/** 392/**
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 4f50949722a9..c69e3e1f05c3 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -34,6 +34,7 @@
34#include <net/netlabel.h> 34#include <net/netlabel.h>
35#include <net/cipso_ipv4.h> 35#include <net/cipso_ipv4.h>
36#include <asm/bug.h> 36#include <asm/bug.h>
37#include <asm/atomic.h>
37 38
38#include "netlabel_domainhash.h" 39#include "netlabel_domainhash.h"
39#include "netlabel_unlabeled.h" 40#include "netlabel_unlabeled.h"
@@ -262,7 +263,7 @@ int netlbl_enabled(void)
262 /* At some point we probably want to expose this mechanism to the user 263 /* At some point we probably want to expose this mechanism to the user
263 * as well so that admins can toggle NetLabel regardless of the 264 * as well so that admins can toggle NetLabel regardless of the
264 * configuration */ 265 * configuration */
265 return (netlbl_mgmt_protocount_value() > 0 ? 1 : 0); 266 return (atomic_read(&netlabel_mgmt_protocount) > 0);
266} 267}
267 268
268/** 269/**
@@ -311,7 +312,7 @@ socket_setattr_return:
311 * @secattr: the security attributes 312 * @secattr: the security attributes
312 * 313 *
313 * Description: 314 * Description:
314 * Examines the given sock to see any NetLabel style labeling has been 315 * Examines the given sock to see if any NetLabel style labeling has been
315 * applied to the sock, if so it parses the socket label and returns the 316 * applied to the sock, if so it parses the socket label and returns the
316 * security attributes in @secattr. Returns zero on success, negative values 317 * security attributes in @secattr. Returns zero on success, negative values
317 * on failure. 318 * on failure.
@@ -319,18 +320,13 @@ socket_setattr_return:
319 */ 320 */
320int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) 321int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
321{ 322{
322 int ret_val; 323 return cipso_v4_sock_getattr(sk, secattr);
323
324 ret_val = cipso_v4_sock_getattr(sk, secattr);
325 if (ret_val == 0)
326 return 0;
327
328 return netlbl_unlabel_getattr(secattr);
329} 324}
330 325
331/** 326/**
332 * netlbl_skbuff_getattr - Determine the security attributes of a packet 327 * netlbl_skbuff_getattr - Determine the security attributes of a packet
333 * @skb: the packet 328 * @skb: the packet
329 * @family: protocol family
334 * @secattr: the security attributes 330 * @secattr: the security attributes
335 * 331 *
336 * Description: 332 * Description:
@@ -341,13 +337,14 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
341 * 337 *
342 */ 338 */
343int netlbl_skbuff_getattr(const struct sk_buff *skb, 339int netlbl_skbuff_getattr(const struct sk_buff *skb,
340 u16 family,
344 struct netlbl_lsm_secattr *secattr) 341 struct netlbl_lsm_secattr *secattr)
345{ 342{
346 if (CIPSO_V4_OPTEXIST(skb) && 343 if (CIPSO_V4_OPTEXIST(skb) &&
347 cipso_v4_skbuff_getattr(skb, secattr) == 0) 344 cipso_v4_skbuff_getattr(skb, secattr) == 0)
348 return 0; 345 return 0;
349 346
350 return netlbl_unlabel_getattr(secattr); 347 return netlbl_unlabel_getattr(skb, family, secattr);
351} 348}
352 349
353/** 350/**
@@ -431,6 +428,10 @@ static int __init netlbl_init(void)
431 if (ret_val != 0) 428 if (ret_val != 0)
432 goto init_failure; 429 goto init_failure;
433 430
431 ret_val = netlbl_unlabel_init(NETLBL_UNLHSH_BITSIZE);
432 if (ret_val != 0)
433 goto init_failure;
434
434 ret_val = netlbl_netlink_init(); 435 ret_val = netlbl_netlink_init();
435 if (ret_val != 0) 436 if (ret_val != 0)
436 goto init_failure; 437 goto init_failure;
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 9c41464d58d1..e2258dc3c845 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -37,14 +37,14 @@
37#include <net/genetlink.h> 37#include <net/genetlink.h>
38#include <net/netlabel.h> 38#include <net/netlabel.h>
39#include <net/cipso_ipv4.h> 39#include <net/cipso_ipv4.h>
40#include <asm/atomic.h>
40 41
41#include "netlabel_domainhash.h" 42#include "netlabel_domainhash.h"
42#include "netlabel_user.h" 43#include "netlabel_user.h"
43#include "netlabel_mgmt.h" 44#include "netlabel_mgmt.h"
44 45
45/* NetLabel configured protocol count */ 46/* NetLabel configured protocol counter */
46static DEFINE_SPINLOCK(netlabel_mgmt_protocount_lock); 47atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
47static u32 netlabel_mgmt_protocount = 0;
48 48
49/* Argument struct for netlbl_domhsh_walk() */ 49/* Argument struct for netlbl_domhsh_walk() */
50struct netlbl_domhsh_walk_arg { 50struct netlbl_domhsh_walk_arg {
@@ -71,63 +71,6 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
71}; 71};
72 72
73/* 73/*
74 * NetLabel Misc Management Functions
75 */
76
77/**
78 * netlbl_mgmt_protocount_inc - Increment the configured labeled protocol count
79 *
80 * Description:
81 * Increment the number of labeled protocol configurations in the current
82 * NetLabel configuration. Keep track of this for use in determining if
83 * NetLabel label enforcement should be active/enabled or not in the LSM.
84 *
85 */
86void netlbl_mgmt_protocount_inc(void)
87{
88 spin_lock(&netlabel_mgmt_protocount_lock);
89 netlabel_mgmt_protocount++;
90 spin_unlock(&netlabel_mgmt_protocount_lock);
91}
92
93/**
94 * netlbl_mgmt_protocount_dec - Decrement the configured labeled protocol count
95 *
96 * Description:
97 * Decrement the number of labeled protocol configurations in the current
98 * NetLabel configuration. Keep track of this for use in determining if
99 * NetLabel label enforcement should be active/enabled or not in the LSM.
100 *
101 */
102void netlbl_mgmt_protocount_dec(void)
103{
104 spin_lock(&netlabel_mgmt_protocount_lock);
105 if (netlabel_mgmt_protocount > 0)
106 netlabel_mgmt_protocount--;
107 spin_unlock(&netlabel_mgmt_protocount_lock);
108}
109
110/**
111 * netlbl_mgmt_protocount_value - Return the number of configured protocols
112 *
113 * Description:
114 * Return the number of labeled protocols in the current NetLabel
115 * configuration. This value is useful in determining if NetLabel label
116 * enforcement should be active/enabled or not in the LSM.
117 *
118 */
119u32 netlbl_mgmt_protocount_value(void)
120{
121 u32 val;
122
123 rcu_read_lock();
124 val = netlabel_mgmt_protocount;
125 rcu_read_unlock();
126
127 return val;
128}
129
130/*
131 * NetLabel Command Handlers 74 * NetLabel Command Handlers
132 */ 75 */
133 76
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h
index ccb2b3923591..a43bff169d6b 100644
--- a/net/netlabel/netlabel_mgmt.h
+++ b/net/netlabel/netlabel_mgmt.h
@@ -32,6 +32,7 @@
32#define _NETLABEL_MGMT_H 32#define _NETLABEL_MGMT_H
33 33
34#include <net/netlabel.h> 34#include <net/netlabel.h>
35#include <asm/atomic.h>
35 36
36/* 37/*
37 * The following NetLabel payloads are supported by the management interface. 38 * The following NetLabel payloads are supported by the management interface.
@@ -168,9 +169,7 @@ enum {
168/* NetLabel protocol functions */ 169/* NetLabel protocol functions */
169int netlbl_mgmt_genl_init(void); 170int netlbl_mgmt_genl_init(void);
170 171
171/* NetLabel misc management functions */ 172/* NetLabel configured protocol reference counter */
172void netlbl_mgmt_protocount_inc(void); 173extern atomic_t netlabel_mgmt_protocount;
173void netlbl_mgmt_protocount_dec(void);
174u32 netlbl_mgmt_protocount_value(void);
175 174
176#endif 175#endif
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 348292450deb..42e81fd8cc49 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12/* 12/*
13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2007
14 * 14 *
15 * This program is free software; you can redistribute it and/or modify 15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
@@ -36,22 +36,92 @@
36#include <linux/string.h> 36#include <linux/string.h>
37#include <linux/skbuff.h> 37#include <linux/skbuff.h>
38#include <linux/audit.h> 38#include <linux/audit.h>
39#include <linux/in.h>
40#include <linux/in6.h>
41#include <linux/ip.h>
42#include <linux/ipv6.h>
43#include <linux/notifier.h>
44#include <linux/netdevice.h>
45#include <linux/security.h>
39#include <net/sock.h> 46#include <net/sock.h>
40#include <net/netlink.h> 47#include <net/netlink.h>
41#include <net/genetlink.h> 48#include <net/genetlink.h>
42 49#include <net/ip.h>
50#include <net/ipv6.h>
51#include <net/net_namespace.h>
43#include <net/netlabel.h> 52#include <net/netlabel.h>
44#include <asm/bug.h> 53#include <asm/bug.h>
54#include <asm/atomic.h>
45 55
46#include "netlabel_user.h" 56#include "netlabel_user.h"
47#include "netlabel_domainhash.h" 57#include "netlabel_domainhash.h"
48#include "netlabel_unlabeled.h" 58#include "netlabel_unlabeled.h"
59#include "netlabel_mgmt.h"
60
61/* NOTE: at present we always use init's network namespace since we don't
62 * presently support different namespaces even though the majority of
63 * the functions in this file are "namespace safe" */
64
65/* The unlabeled connection hash table which we use to map network interfaces
66 * and addresses of unlabeled packets to a user specified secid value for the
67 * LSM. The hash table is used to lookup the network interface entry
68 * (struct netlbl_unlhsh_iface) and then the interface entry is used to
69 * lookup an IP address match from an ordered list. If a network interface
70 * match can not be found in the hash table then the default entry
71 * (netlbl_unlhsh_def) is used. The IP address entry list
72 * (struct netlbl_unlhsh_addr) is ordered such that the entries with a
73 * larger netmask come first.
74 */
75struct netlbl_unlhsh_tbl {
76 struct list_head *tbl;
77 u32 size;
78};
79struct netlbl_unlhsh_addr4 {
80 __be32 addr;
81 __be32 mask;
82 u32 secid;
83
84 u32 valid;
85 struct list_head list;
86 struct rcu_head rcu;
87};
88struct netlbl_unlhsh_addr6 {
89 struct in6_addr addr;
90 struct in6_addr mask;
91 u32 secid;
92
93 u32 valid;
94 struct list_head list;
95 struct rcu_head rcu;
96};
97struct netlbl_unlhsh_iface {
98 int ifindex;
99 struct list_head addr4_list;
100 struct list_head addr6_list;
101
102 u32 valid;
103 struct list_head list;
104 struct rcu_head rcu;
105};
106
107/* Argument struct for netlbl_unlhsh_walk() */
108struct netlbl_unlhsh_walk_arg {
109 struct netlink_callback *nl_cb;
110 struct sk_buff *skb;
111 u32 seq;
112};
113
114/* Unlabeled connection hash table */
115/* updates should be so rare that having one spinlock for the entire
116 * hash table should be okay */
117static DEFINE_SPINLOCK(netlbl_unlhsh_lock);
118static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL;
119static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL;
49 120
50/* Accept unlabeled packets flag */ 121/* Accept unlabeled packets flag */
51static DEFINE_SPINLOCK(netlabel_unlabel_acceptflg_lock);
52static u8 netlabel_unlabel_acceptflg = 0; 122static u8 netlabel_unlabel_acceptflg = 0;
53 123
54/* NetLabel Generic NETLINK CIPSOv4 family */ 124/* NetLabel Generic NETLINK unlabeled family */
55static struct genl_family netlbl_unlabel_gnl_family = { 125static struct genl_family netlbl_unlabel_gnl_family = {
56 .id = GENL_ID_GENERATE, 126 .id = GENL_ID_GENERATE,
57 .hdrsize = 0, 127 .hdrsize = 0,
@@ -63,11 +133,841 @@ static struct genl_family netlbl_unlabel_gnl_family = {
63/* NetLabel Netlink attribute policy */ 133/* NetLabel Netlink attribute policy */
64static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { 134static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
65 [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, 135 [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 },
136 [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY,
137 .len = sizeof(struct in6_addr) },
138 [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY,
139 .len = sizeof(struct in6_addr) },
140 [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY,
141 .len = sizeof(struct in_addr) },
142 [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY,
143 .len = sizeof(struct in_addr) },
144 [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING,
145 .len = IFNAMSIZ - 1 },
146 [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY }
66}; 147};
67 148
68/* 149/*
69 * Helper Functions 150 * Audit Helper Functions
151 */
152
153/**
154 * netlbl_unlabel_audit_addr4 - Audit an IPv4 address
155 * @audit_buf: audit buffer
156 * @dev: network interface
157 * @addr: IP address
158 * @mask: IP address mask
159 *
160 * Description:
161 * Write the IPv4 address and address mask, if necessary, to @audit_buf.
162 *
163 */
164static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf,
165 const char *dev,
166 __be32 addr, __be32 mask)
167{
168 u32 mask_val = ntohl(mask);
169
170 if (dev != NULL)
171 audit_log_format(audit_buf, " netif=%s", dev);
172 audit_log_format(audit_buf, " src=" NIPQUAD_FMT, NIPQUAD(addr));
173 if (mask_val != 0xffffffff) {
174 u32 mask_len = 0;
175 while (mask_val > 0) {
176 mask_val <<= 1;
177 mask_len++;
178 }
179 audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
180 }
181}
182
183/**
184 * netlbl_unlabel_audit_addr6 - Audit an IPv6 address
185 * @audit_buf: audit buffer
186 * @dev: network interface
187 * @addr: IP address
188 * @mask: IP address mask
189 *
190 * Description:
191 * Write the IPv6 address and address mask, if necessary, to @audit_buf.
192 *
193 */
194static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf,
195 const char *dev,
196 const struct in6_addr *addr,
197 const struct in6_addr *mask)
198{
199 if (dev != NULL)
200 audit_log_format(audit_buf, " netif=%s", dev);
201 audit_log_format(audit_buf, " src=" NIP6_FMT, NIP6(*addr));
202 if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
203 u32 mask_len = 0;
204 u32 mask_val;
205 int iter = -1;
206 while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
207 mask_len += 32;
208 mask_val = ntohl(mask->s6_addr32[iter]);
209 while (mask_val > 0) {
210 mask_val <<= 1;
211 mask_len++;
212 }
213 audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
214 }
215}
216
217/*
218 * Unlabeled Connection Hash Table Functions
219 */
220
221/**
222 * netlbl_unlhsh_free_addr4 - Frees an IPv4 address entry from the hash table
223 * @entry: the entry's RCU field
224 *
225 * Description:
226 * This function is designed to be used as a callback to the call_rcu()
227 * function so that memory allocated to a hash table address entry can be
228 * released safely.
229 *
230 */
231static void netlbl_unlhsh_free_addr4(struct rcu_head *entry)
232{
233 struct netlbl_unlhsh_addr4 *ptr;
234
235 ptr = container_of(entry, struct netlbl_unlhsh_addr4, rcu);
236 kfree(ptr);
237}
238
239#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
240/**
241 * netlbl_unlhsh_free_addr6 - Frees an IPv6 address entry from the hash table
242 * @entry: the entry's RCU field
243 *
244 * Description:
245 * This function is designed to be used as a callback to the call_rcu()
246 * function so that memory allocated to a hash table address entry can be
247 * released safely.
248 *
249 */
250static void netlbl_unlhsh_free_addr6(struct rcu_head *entry)
251{
252 struct netlbl_unlhsh_addr6 *ptr;
253
254 ptr = container_of(entry, struct netlbl_unlhsh_addr6, rcu);
255 kfree(ptr);
256}
257#endif /* IPv6 */
258
259/**
260 * netlbl_unlhsh_free_iface - Frees an interface entry from the hash table
261 * @entry: the entry's RCU field
262 *
263 * Description:
264 * This function is designed to be used as a callback to the call_rcu()
265 * function so that memory allocated to a hash table interface entry can be
266 * released safely. It is important to note that this function does not free
267 * the IPv4 and IPv6 address lists contained as part of an interface entry. It
268 * is up to the rest of the code to make sure an interface entry is only freed
269 * once it's address lists are empty.
270 *
271 */
272static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
273{
274 struct netlbl_unlhsh_iface *iface;
275 struct netlbl_unlhsh_addr4 *iter4;
276 struct netlbl_unlhsh_addr4 *tmp4;
277 struct netlbl_unlhsh_addr6 *iter6;
278 struct netlbl_unlhsh_addr6 *tmp6;
279
280 iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
281
282 /* no need for locks here since we are the only one with access to this
283 * structure */
284
285 list_for_each_entry_safe(iter4, tmp4, &iface->addr4_list, list)
286 if (iter4->valid) {
287 list_del_rcu(&iter4->list);
288 kfree(iter4);
289 }
290 list_for_each_entry_safe(iter6, tmp6, &iface->addr6_list, list)
291 if (iter6->valid) {
292 list_del_rcu(&iter6->list);
293 kfree(iter6);
294 }
295 kfree(iface);
296}
297
298/**
299 * netlbl_unlhsh_hash - Hashing function for the hash table
300 * @ifindex: the network interface/device to hash
301 *
302 * Description:
303 * This is the hashing function for the unlabeled hash table, it returns the
304 * bucket number for the given device/interface. The caller is responsible for
305 * calling the rcu_read_[un]lock() functions.
306 *
70 */ 307 */
308static u32 netlbl_unlhsh_hash(int ifindex)
309{
310 /* this is taken _almost_ directly from
311 * security/selinux/netif.c:sel_netif_hasfn() as they do pretty much
312 * the same thing */
313 return ifindex & (rcu_dereference(netlbl_unlhsh)->size - 1);
314}
315
316/**
317 * netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry
318 * @addr: IPv4 address
319 * @iface: the network interface entry
320 *
321 * Description:
322 * Searches the IPv4 address list of the network interface specified by @iface.
323 * If a matching address entry is found it is returned, otherwise NULL is
324 * returned. The caller is responsible for calling the rcu_read_[un]lock()
325 * functions.
326 *
327 */
328static struct netlbl_unlhsh_addr4 *netlbl_unlhsh_search_addr4(
329 __be32 addr,
330 const struct netlbl_unlhsh_iface *iface)
331{
332 struct netlbl_unlhsh_addr4 *iter;
333
334 list_for_each_entry_rcu(iter, &iface->addr4_list, list)
335 if (iter->valid && (addr & iter->mask) == iter->addr)
336 return iter;
337
338 return NULL;
339}
340
341#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
342/**
343 * netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry
344 * @addr: IPv6 address
345 * @iface: the network interface entry
346 *
347 * Description:
348 * Searches the IPv6 address list of the network interface specified by @iface.
349 * If a matching address entry is found it is returned, otherwise NULL is
350 * returned. The caller is responsible for calling the rcu_read_[un]lock()
351 * functions.
352 *
353 */
354static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
355 const struct in6_addr *addr,
356 const struct netlbl_unlhsh_iface *iface)
357{
358 struct netlbl_unlhsh_addr6 *iter;
359
360 list_for_each_entry_rcu(iter, &iface->addr6_list, list)
361 if (iter->valid &&
362 ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
363 return iter;
364
365 return NULL;
366}
367#endif /* IPv6 */
368
369/**
370 * netlbl_unlhsh_search_iface - Search for a matching interface entry
371 * @ifindex: the network interface
372 *
373 * Description:
374 * Searches the unlabeled connection hash table and returns a pointer to the
375 * interface entry which matches @ifindex, otherwise NULL is returned. The
376 * caller is responsible for calling the rcu_read_[un]lock() functions.
377 *
378 */
379static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
380{
381 u32 bkt;
382 struct netlbl_unlhsh_iface *iter;
383
384 bkt = netlbl_unlhsh_hash(ifindex);
385 list_for_each_entry_rcu(iter,
386 &rcu_dereference(netlbl_unlhsh)->tbl[bkt],
387 list)
388 if (iter->valid && iter->ifindex == ifindex)
389 return iter;
390
391 return NULL;
392}
393
394/**
395 * netlbl_unlhsh_search_iface_def - Search for a matching interface entry
396 * @ifindex: the network interface
397 *
398 * Description:
399 * Searches the unlabeled connection hash table and returns a pointer to the
400 * interface entry which matches @ifindex. If an exact match can not be found
401 * and there is a valid default entry, the default entry is returned, otherwise
402 * NULL is returned. The caller is responsible for calling the
403 * rcu_read_[un]lock() functions.
404 *
405 */
406static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface_def(int ifindex)
407{
408 struct netlbl_unlhsh_iface *entry;
409
410 entry = netlbl_unlhsh_search_iface(ifindex);
411 if (entry != NULL)
412 return entry;
413
414 entry = rcu_dereference(netlbl_unlhsh_def);
415 if (entry != NULL && entry->valid)
416 return entry;
417
418 return NULL;
419}
420
421/**
422 * netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table
423 * @iface: the associated interface entry
424 * @addr: IPv4 address in network byte order
425 * @mask: IPv4 address mask in network byte order
426 * @secid: LSM secid value for entry
427 *
428 * Description:
429 * Add a new address entry into the unlabeled connection hash table using the
430 * interface entry specified by @iface. On success zero is returned, otherwise
431 * a negative value is returned. The caller is responsible for calling the
432 * rcu_read_[un]lock() functions.
433 *
434 */
435static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
436 const struct in_addr *addr,
437 const struct in_addr *mask,
438 u32 secid)
439{
440 struct netlbl_unlhsh_addr4 *entry;
441 struct netlbl_unlhsh_addr4 *iter;
442
443 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
444 if (entry == NULL)
445 return -ENOMEM;
446
447 entry->addr = addr->s_addr & mask->s_addr;
448 entry->mask = mask->s_addr;
449 entry->secid = secid;
450 entry->valid = 1;
451 INIT_RCU_HEAD(&entry->rcu);
452
453 spin_lock(&netlbl_unlhsh_lock);
454 iter = netlbl_unlhsh_search_addr4(entry->addr, iface);
455 if (iter != NULL &&
456 iter->addr == addr->s_addr && iter->mask == mask->s_addr) {
457 spin_unlock(&netlbl_unlhsh_lock);
458 kfree(entry);
459 return -EEXIST;
460 }
461 /* in order to speed up address searches through the list (the common
462 * case) we need to keep the list in order based on the size of the
463 * address mask such that the entry with the widest mask (smallest
464 * numerical value) appears first in the list */
465 list_for_each_entry_rcu(iter, &iface->addr4_list, list)
466 if (iter->valid &&
467 ntohl(entry->mask) > ntohl(iter->mask)) {
468 __list_add_rcu(&entry->list,
469 iter->list.prev,
470 &iter->list);
471 spin_unlock(&netlbl_unlhsh_lock);
472 return 0;
473 }
474 list_add_tail_rcu(&entry->list, &iface->addr4_list);
475 spin_unlock(&netlbl_unlhsh_lock);
476 return 0;
477}
478
479#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
480/**
481 * netlbl_unlhsh_add_addr6 - Add a new IPv6 address entry to the hash table
482 * @iface: the associated interface entry
483 * @addr: IPv6 address in network byte order
484 * @mask: IPv6 address mask in network byte order
485 * @secid: LSM secid value for entry
486 *
487 * Description:
488 * Add a new address entry into the unlabeled connection hash table using the
489 * interface entry specified by @iface. On success zero is returned, otherwise
490 * a negative value is returned. The caller is responsible for calling the
491 * rcu_read_[un]lock() functions.
492 *
493 */
494static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
495 const struct in6_addr *addr,
496 const struct in6_addr *mask,
497 u32 secid)
498{
499 struct netlbl_unlhsh_addr6 *entry;
500 struct netlbl_unlhsh_addr6 *iter;
501
502 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
503 if (entry == NULL)
504 return -ENOMEM;
505
506 ipv6_addr_copy(&entry->addr, addr);
507 entry->addr.s6_addr32[0] &= mask->s6_addr32[0];
508 entry->addr.s6_addr32[1] &= mask->s6_addr32[1];
509 entry->addr.s6_addr32[2] &= mask->s6_addr32[2];
510 entry->addr.s6_addr32[3] &= mask->s6_addr32[3];
511 ipv6_addr_copy(&entry->mask, mask);
512 entry->secid = secid;
513 entry->valid = 1;
514 INIT_RCU_HEAD(&entry->rcu);
515
516 spin_lock(&netlbl_unlhsh_lock);
517 iter = netlbl_unlhsh_search_addr6(&entry->addr, iface);
518 if (iter != NULL &&
519 (ipv6_addr_equal(&iter->addr, addr) &&
520 ipv6_addr_equal(&iter->mask, mask))) {
521 spin_unlock(&netlbl_unlhsh_lock);
522 kfree(entry);
523 return -EEXIST;
524 }
525 /* in order to speed up address searches through the list (the common
526 * case) we need to keep the list in order based on the size of the
527 * address mask such that the entry with the widest mask (smallest
528 * numerical value) appears first in the list */
529 list_for_each_entry_rcu(iter, &iface->addr6_list, list)
530 if (iter->valid &&
531 ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
532 __list_add_rcu(&entry->list,
533 iter->list.prev,
534 &iter->list);
535 spin_unlock(&netlbl_unlhsh_lock);
536 return 0;
537 }
538 list_add_tail_rcu(&entry->list, &iface->addr6_list);
539 spin_unlock(&netlbl_unlhsh_lock);
540 return 0;
541}
542#endif /* IPv6 */
543
544/**
545 * netlbl_unlhsh_add_iface - Adds a new interface entry to the hash table
546 * @ifindex: network interface
547 *
548 * Description:
549 * Add a new, empty, interface entry into the unlabeled connection hash table.
550 * On success a pointer to the new interface entry is returned, on failure NULL
551 * is returned. The caller is responsible for calling the rcu_read_[un]lock()
552 * functions.
553 *
554 */
555static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex)
556{
557 u32 bkt;
558 struct netlbl_unlhsh_iface *iface;
559
560 iface = kzalloc(sizeof(*iface), GFP_ATOMIC);
561 if (iface == NULL)
562 return NULL;
563
564 iface->ifindex = ifindex;
565 INIT_LIST_HEAD(&iface->addr4_list);
566 INIT_LIST_HEAD(&iface->addr6_list);
567 iface->valid = 1;
568 INIT_RCU_HEAD(&iface->rcu);
569
570 spin_lock(&netlbl_unlhsh_lock);
571 if (ifindex > 0) {
572 bkt = netlbl_unlhsh_hash(ifindex);
573 if (netlbl_unlhsh_search_iface(ifindex) != NULL)
574 goto add_iface_failure;
575 list_add_tail_rcu(&iface->list,
576 &rcu_dereference(netlbl_unlhsh)->tbl[bkt]);
577 } else {
578 INIT_LIST_HEAD(&iface->list);
579 if (rcu_dereference(netlbl_unlhsh_def) != NULL)
580 goto add_iface_failure;
581 rcu_assign_pointer(netlbl_unlhsh_def, iface);
582 }
583 spin_unlock(&netlbl_unlhsh_lock);
584
585 return iface;
586
587add_iface_failure:
588 spin_unlock(&netlbl_unlhsh_lock);
589 kfree(iface);
590 return NULL;
591}
592
593/**
594 * netlbl_unlhsh_add - Adds a new entry to the unlabeled connection hash table
595 * @net: network namespace
596 * @dev_name: interface name
597 * @addr: IP address in network byte order
598 * @mask: address mask in network byte order
599 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
600 * @secid: LSM secid value for the entry
601 * @audit_info: NetLabel audit information
602 *
603 * Description:
604 * Adds a new entry to the unlabeled connection hash table. Returns zero on
605 * success, negative values on failure.
606 *
607 */
608static int netlbl_unlhsh_add(struct net *net,
609 const char *dev_name,
610 const void *addr,
611 const void *mask,
612 u32 addr_len,
613 u32 secid,
614 struct netlbl_audit *audit_info)
615{
616 int ret_val;
617 int ifindex;
618 struct net_device *dev;
619 struct netlbl_unlhsh_iface *iface;
620 struct in_addr *addr4, *mask4;
621 struct in6_addr *addr6, *mask6;
622 struct audit_buffer *audit_buf = NULL;
623 char *secctx = NULL;
624 u32 secctx_len;
625
626 if (addr_len != sizeof(struct in_addr) &&
627 addr_len != sizeof(struct in6_addr))
628 return -EINVAL;
629
630 rcu_read_lock();
631 if (dev_name != NULL) {
632 dev = dev_get_by_name(net, dev_name);
633 if (dev == NULL) {
634 ret_val = -ENODEV;
635 goto unlhsh_add_return;
636 }
637 ifindex = dev->ifindex;
638 dev_put(dev);
639 iface = netlbl_unlhsh_search_iface(ifindex);
640 } else {
641 ifindex = 0;
642 iface = rcu_dereference(netlbl_unlhsh_def);
643 }
644 if (iface == NULL) {
645 iface = netlbl_unlhsh_add_iface(ifindex);
646 if (iface == NULL) {
647 ret_val = -ENOMEM;
648 goto unlhsh_add_return;
649 }
650 }
651 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCADD,
652 audit_info);
653 switch (addr_len) {
654 case sizeof(struct in_addr):
655 addr4 = (struct in_addr *)addr;
656 mask4 = (struct in_addr *)mask;
657 ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
658 if (audit_buf != NULL)
659 netlbl_unlabel_audit_addr4(audit_buf,
660 dev_name,
661 addr4->s_addr,
662 mask4->s_addr);
663 break;
664#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
665 case sizeof(struct in6_addr):
666 addr6 = (struct in6_addr *)addr;
667 mask6 = (struct in6_addr *)mask;
668 ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
669 if (audit_buf != NULL)
670 netlbl_unlabel_audit_addr6(audit_buf,
671 dev_name,
672 addr6, mask6);
673 break;
674#endif /* IPv6 */
675 default:
676 ret_val = -EINVAL;
677 }
678 if (ret_val == 0)
679 atomic_inc(&netlabel_mgmt_protocount);
680
681unlhsh_add_return:
682 rcu_read_unlock();
683 if (audit_buf != NULL) {
684 if (security_secid_to_secctx(secid,
685 &secctx,
686 &secctx_len) == 0) {
687 audit_log_format(audit_buf, " sec_obj=%s", secctx);
688 security_release_secctx(secctx, secctx_len);
689 }
690 audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
691 audit_log_end(audit_buf);
692 }
693 return ret_val;
694}
695
696/**
697 * netlbl_unlhsh_remove_addr4 - Remove an IPv4 address entry
698 * @net: network namespace
699 * @iface: interface entry
700 * @addr: IP address
701 * @mask: IP address mask
702 * @audit_info: NetLabel audit information
703 *
704 * Description:
705 * Remove an IP address entry from the unlabeled connection hash table.
706 * Returns zero on success, negative values on failure. The caller is
707 * responsible for calling the rcu_read_[un]lock() functions.
708 *
709 */
710static int netlbl_unlhsh_remove_addr4(struct net *net,
711 struct netlbl_unlhsh_iface *iface,
712 const struct in_addr *addr,
713 const struct in_addr *mask,
714 struct netlbl_audit *audit_info)
715{
716 int ret_val = -ENOENT;
717 struct netlbl_unlhsh_addr4 *entry;
718 struct audit_buffer *audit_buf = NULL;
719 struct net_device *dev;
720 char *secctx = NULL;
721 u32 secctx_len;
722
723 spin_lock(&netlbl_unlhsh_lock);
724 entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface);
725 if (entry != NULL &&
726 entry->addr == addr->s_addr && entry->mask == mask->s_addr) {
727 entry->valid = 0;
728 list_del_rcu(&entry->list);
729 ret_val = 0;
730 }
731 spin_unlock(&netlbl_unlhsh_lock);
732
733 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
734 audit_info);
735 if (audit_buf != NULL) {
736 dev = dev_get_by_index(net, iface->ifindex);
737 netlbl_unlabel_audit_addr4(audit_buf,
738 (dev != NULL ? dev->name : NULL),
739 entry->addr, entry->mask);
740 if (dev != NULL)
741 dev_put(dev);
742 if (security_secid_to_secctx(entry->secid,
743 &secctx,
744 &secctx_len) == 0) {
745 audit_log_format(audit_buf, " sec_obj=%s", secctx);
746 security_release_secctx(secctx, secctx_len);
747 }
748 audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
749 audit_log_end(audit_buf);
750 }
751
752 if (ret_val == 0)
753 call_rcu(&entry->rcu, netlbl_unlhsh_free_addr4);
754 return ret_val;
755}
756
757#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
758/**
759 * netlbl_unlhsh_remove_addr6 - Remove an IPv6 address entry
760 * @net: network namespace
761 * @iface: interface entry
762 * @addr: IP address
763 * @mask: IP address mask
764 * @audit_info: NetLabel audit information
765 *
766 * Description:
767 * Remove an IP address entry from the unlabeled connection hash table.
768 * Returns zero on success, negative values on failure. The caller is
769 * responsible for calling the rcu_read_[un]lock() functions.
770 *
771 */
772static int netlbl_unlhsh_remove_addr6(struct net *net,
773 struct netlbl_unlhsh_iface *iface,
774 const struct in6_addr *addr,
775 const struct in6_addr *mask,
776 struct netlbl_audit *audit_info)
777{
778 int ret_val = -ENOENT;
779 struct netlbl_unlhsh_addr6 *entry;
780 struct audit_buffer *audit_buf = NULL;
781 struct net_device *dev;
782 char *secctx = NULL;
783 u32 secctx_len;
784
785 spin_lock(&netlbl_unlhsh_lock);
786 entry = netlbl_unlhsh_search_addr6(addr, iface);
787 if (entry != NULL &&
788 (ipv6_addr_equal(&entry->addr, addr) &&
789 ipv6_addr_equal(&entry->mask, mask))) {
790 entry->valid = 0;
791 list_del_rcu(&entry->list);
792 ret_val = 0;
793 }
794 spin_unlock(&netlbl_unlhsh_lock);
795
796 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
797 audit_info);
798 if (audit_buf != NULL) {
799 dev = dev_get_by_index(net, iface->ifindex);
800 netlbl_unlabel_audit_addr6(audit_buf,
801 (dev != NULL ? dev->name : NULL),
802 addr, mask);
803 if (dev != NULL)
804 dev_put(dev);
805 if (security_secid_to_secctx(entry->secid,
806 &secctx,
807 &secctx_len) == 0) {
808 audit_log_format(audit_buf, " sec_obj=%s", secctx);
809 security_release_secctx(secctx, secctx_len);
810 }
811 audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
812 audit_log_end(audit_buf);
813 }
814
815 if (ret_val == 0)
816 call_rcu(&entry->rcu, netlbl_unlhsh_free_addr6);
817 return ret_val;
818}
819#endif /* IPv6 */
820
821/**
822 * netlbl_unlhsh_condremove_iface - Remove an interface entry
823 * @iface: the interface entry
824 *
825 * Description:
826 * Remove an interface entry from the unlabeled connection hash table if it is
827 * empty. An interface entry is considered to be empty if there are no
828 * address entries assigned to it.
829 *
830 */
831static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
832{
833 struct netlbl_unlhsh_addr4 *iter4;
834 struct netlbl_unlhsh_addr6 *iter6;
835
836 spin_lock(&netlbl_unlhsh_lock);
837 list_for_each_entry_rcu(iter4, &iface->addr4_list, list)
838 if (iter4->valid)
839 goto unlhsh_condremove_failure;
840 list_for_each_entry_rcu(iter6, &iface->addr6_list, list)
841 if (iter6->valid)
842 goto unlhsh_condremove_failure;
843 iface->valid = 0;
844 if (iface->ifindex > 0)
845 list_del_rcu(&iface->list);
846 else
847 rcu_assign_pointer(netlbl_unlhsh_def, NULL);
848 spin_unlock(&netlbl_unlhsh_lock);
849
850 call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
851 return;
852
853unlhsh_condremove_failure:
854 spin_unlock(&netlbl_unlhsh_lock);
855 return;
856}
857
858/**
859 * netlbl_unlhsh_remove - Remove an entry from the unlabeled hash table
860 * @net: network namespace
861 * @dev_name: interface name
862 * @addr: IP address in network byte order
863 * @mask: address mask in network byte order
864 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
865 * @audit_info: NetLabel audit information
866 *
867 * Description:
868 * Removes and existing entry from the unlabeled connection hash table.
869 * Returns zero on success, negative values on failure.
870 *
871 */
872static int netlbl_unlhsh_remove(struct net *net,
873 const char *dev_name,
874 const void *addr,
875 const void *mask,
876 u32 addr_len,
877 struct netlbl_audit *audit_info)
878{
879 int ret_val;
880 struct net_device *dev;
881 struct netlbl_unlhsh_iface *iface;
882
883 if (addr_len != sizeof(struct in_addr) &&
884 addr_len != sizeof(struct in6_addr))
885 return -EINVAL;
886
887 rcu_read_lock();
888 if (dev_name != NULL) {
889 dev = dev_get_by_name(net, dev_name);
890 if (dev == NULL) {
891 ret_val = -ENODEV;
892 goto unlhsh_remove_return;
893 }
894 iface = netlbl_unlhsh_search_iface(dev->ifindex);
895 dev_put(dev);
896 } else
897 iface = rcu_dereference(netlbl_unlhsh_def);
898 if (iface == NULL) {
899 ret_val = -ENOENT;
900 goto unlhsh_remove_return;
901 }
902 switch (addr_len) {
903 case sizeof(struct in_addr):
904 ret_val = netlbl_unlhsh_remove_addr4(net,
905 iface, addr, mask,
906 audit_info);
907 break;
908#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
909 case sizeof(struct in6_addr):
910 ret_val = netlbl_unlhsh_remove_addr6(net,
911 iface, addr, mask,
912 audit_info);
913 break;
914#endif /* IPv6 */
915 default:
916 ret_val = -EINVAL;
917 }
918 if (ret_val == 0) {
919 netlbl_unlhsh_condremove_iface(iface);
920 atomic_dec(&netlabel_mgmt_protocount);
921 }
922
923unlhsh_remove_return:
924 rcu_read_unlock();
925 return ret_val;
926}
927
928/*
929 * General Helper Functions
930 */
931
932/**
933 * netlbl_unlhsh_netdev_handler - Network device notification handler
934 * @this: notifier block
935 * @event: the event
936 * @ptr: the network device (cast to void)
937 *
938 * Description:
939 * Handle network device events, although at present all we care about is a
940 * network device going away. In the case of a device going away we clear any
941 * related entries from the unlabeled connection hash table.
942 *
943 */
944static int netlbl_unlhsh_netdev_handler(struct notifier_block *this,
945 unsigned long event,
946 void *ptr)
947{
948 struct net_device *dev = ptr;
949 struct netlbl_unlhsh_iface *iface = NULL;
950
951 if (dev->nd_net != &init_net)
952 return NOTIFY_DONE;
953
954 /* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */
955 if (event == NETDEV_DOWN) {
956 spin_lock(&netlbl_unlhsh_lock);
957 iface = netlbl_unlhsh_search_iface(dev->ifindex);
958 if (iface != NULL && iface->valid) {
959 iface->valid = 0;
960 list_del_rcu(&iface->list);
961 } else
962 iface = NULL;
963 spin_unlock(&netlbl_unlhsh_lock);
964 }
965
966 if (iface != NULL)
967 call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
968
969 return NOTIFY_DONE;
970}
71 971
72/** 972/**
73 * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag 973 * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag
@@ -84,11 +984,8 @@ static void netlbl_unlabel_acceptflg_set(u8 value,
84 struct audit_buffer *audit_buf; 984 struct audit_buffer *audit_buf;
85 u8 old_val; 985 u8 old_val;
86 986
87 spin_lock(&netlabel_unlabel_acceptflg_lock);
88 old_val = netlabel_unlabel_acceptflg; 987 old_val = netlabel_unlabel_acceptflg;
89 netlabel_unlabel_acceptflg = value; 988 netlabel_unlabel_acceptflg = value;
90 spin_unlock(&netlabel_unlabel_acceptflg_lock);
91
92 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW, 989 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW,
93 audit_info); 990 audit_info);
94 if (audit_buf != NULL) { 991 if (audit_buf != NULL) {
@@ -98,6 +995,48 @@ static void netlbl_unlabel_acceptflg_set(u8 value,
98 } 995 }
99} 996}
100 997
998/**
999 * netlbl_unlabel_addrinfo_get - Get the IPv4/6 address information
1000 * @info: the Generic NETLINK info block
1001 * @addr: the IP address
1002 * @mask: the IP address mask
1003 * @len: the address length
1004 *
1005 * Description:
1006 * Examine the Generic NETLINK message and extract the IP address information.
1007 * Returns zero on success, negative values on failure.
1008 *
1009 */
1010static int netlbl_unlabel_addrinfo_get(struct genl_info *info,
1011 void **addr,
1012 void **mask,
1013 u32 *len)
1014{
1015 u32 addr_len;
1016
1017 if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR]) {
1018 addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
1019 if (addr_len != sizeof(struct in_addr) &&
1020 addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK]))
1021 return -EINVAL;
1022 *len = addr_len;
1023 *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
1024 *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]);
1025 return 0;
1026 } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) {
1027 addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
1028 if (addr_len != sizeof(struct in6_addr) &&
1029 addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK]))
1030 return -EINVAL;
1031 *len = addr_len;
1032 *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
1033 *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]);
1034 return 0;
1035 }
1036
1037 return -EINVAL;
1038}
1039
101/* 1040/*
102 * NetLabel Command Handlers 1041 * NetLabel Command Handlers
103 */ 1042 */
@@ -155,11 +1094,9 @@ static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
155 goto list_failure; 1094 goto list_failure;
156 } 1095 }
157 1096
158 rcu_read_lock();
159 ret_val = nla_put_u8(ans_skb, 1097 ret_val = nla_put_u8(ans_skb,
160 NLBL_UNLABEL_A_ACPTFLG, 1098 NLBL_UNLABEL_A_ACPTFLG,
161 netlabel_unlabel_acceptflg); 1099 netlabel_unlabel_acceptflg);
162 rcu_read_unlock();
163 if (ret_val != 0) 1100 if (ret_val != 0)
164 goto list_failure; 1101 goto list_failure;
165 1102
@@ -175,11 +1112,489 @@ list_failure:
175 return ret_val; 1112 return ret_val;
176} 1113}
177 1114
1115/**
1116 * netlbl_unlabel_staticadd - Handle a STATICADD message
1117 * @skb: the NETLINK buffer
1118 * @info: the Generic NETLINK info block
1119 *
1120 * Description:
1121 * Process a user generated STATICADD message and add a new unlabeled
1122 * connection entry to the hash table. Returns zero on success, negative
1123 * values on failure.
1124 *
1125 */
1126static int netlbl_unlabel_staticadd(struct sk_buff *skb,
1127 struct genl_info *info)
1128{
1129 int ret_val;
1130 char *dev_name;
1131 void *addr;
1132 void *mask;
1133 u32 addr_len;
1134 u32 secid;
1135 struct netlbl_audit audit_info;
1136
1137 /* Don't allow users to add both IPv4 and IPv6 addresses for a
1138 * single entry. However, allow users to create two entries, one each
1139 * for IPv4 and IPv4, with the same LSM security context which should
1140 * achieve the same result. */
1141 if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
1142 !info->attrs[NLBL_UNLABEL_A_IFACE] ||
1143 !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1144 !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1145 (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1146 !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1147 return -EINVAL;
1148
1149 netlbl_netlink_auditinfo(skb, &audit_info);
1150
1151 ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1152 if (ret_val != 0)
1153 return ret_val;
1154 dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
1155 ret_val = security_secctx_to_secid(
1156 nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
1157 nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
1158 &secid);
1159 if (ret_val != 0)
1160 return ret_val;
1161
1162 return netlbl_unlhsh_add(&init_net,
1163 dev_name, addr, mask, addr_len, secid,
1164 &audit_info);
1165}
1166
1167/**
1168 * netlbl_unlabel_staticadddef - Handle a STATICADDDEF message
1169 * @skb: the NETLINK buffer
1170 * @info: the Generic NETLINK info block
1171 *
1172 * Description:
1173 * Process a user generated STATICADDDEF message and add a new default
1174 * unlabeled connection entry. Returns zero on success, negative values on
1175 * failure.
1176 *
1177 */
1178static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
1179 struct genl_info *info)
1180{
1181 int ret_val;
1182 void *addr;
1183 void *mask;
1184 u32 addr_len;
1185 u32 secid;
1186 struct netlbl_audit audit_info;
1187
1188 /* Don't allow users to add both IPv4 and IPv6 addresses for a
1189 * single entry. However, allow users to create two entries, one each
1190 * for IPv4 and IPv6, with the same LSM security context which should
1191 * achieve the same result. */
1192 if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
1193 !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1194 !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1195 (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1196 !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1197 return -EINVAL;
1198
1199 netlbl_netlink_auditinfo(skb, &audit_info);
1200
1201 ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1202 if (ret_val != 0)
1203 return ret_val;
1204 ret_val = security_secctx_to_secid(
1205 nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
1206 nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
1207 &secid);
1208 if (ret_val != 0)
1209 return ret_val;
1210
1211 return netlbl_unlhsh_add(&init_net,
1212 NULL, addr, mask, addr_len, secid,
1213 &audit_info);
1214}
1215
1216/**
1217 * netlbl_unlabel_staticremove - Handle a STATICREMOVE message
1218 * @skb: the NETLINK buffer
1219 * @info: the Generic NETLINK info block
1220 *
1221 * Description:
1222 * Process a user generated STATICREMOVE message and remove the specified
1223 * unlabeled connection entry. Returns zero on success, negative values on
1224 * failure.
1225 *
1226 */
1227static int netlbl_unlabel_staticremove(struct sk_buff *skb,
1228 struct genl_info *info)
1229{
1230 int ret_val;
1231 char *dev_name;
1232 void *addr;
1233 void *mask;
1234 u32 addr_len;
1235 struct netlbl_audit audit_info;
1236
1237 /* See the note in netlbl_unlabel_staticadd() about not allowing both
1238 * IPv4 and IPv6 in the same entry. */
1239 if (!info->attrs[NLBL_UNLABEL_A_IFACE] ||
1240 !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1241 !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1242 (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1243 !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1244 return -EINVAL;
1245
1246 netlbl_netlink_auditinfo(skb, &audit_info);
1247
1248 ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1249 if (ret_val != 0)
1250 return ret_val;
1251 dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
1252
1253 return netlbl_unlhsh_remove(&init_net,
1254 dev_name, addr, mask, addr_len,
1255 &audit_info);
1256}
1257
1258/**
1259 * netlbl_unlabel_staticremovedef - Handle a STATICREMOVEDEF message
1260 * @skb: the NETLINK buffer
1261 * @info: the Generic NETLINK info block
1262 *
1263 * Description:
1264 * Process a user generated STATICREMOVEDEF message and remove the default
1265 * unlabeled connection entry. Returns zero on success, negative values on
1266 * failure.
1267 *
1268 */
1269static int netlbl_unlabel_staticremovedef(struct sk_buff *skb,
1270 struct genl_info *info)
1271{
1272 int ret_val;
1273 void *addr;
1274 void *mask;
1275 u32 addr_len;
1276 struct netlbl_audit audit_info;
1277
1278 /* See the note in netlbl_unlabel_staticadd() about not allowing both
1279 * IPv4 and IPv6 in the same entry. */
1280 if (!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1281 !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1282 (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1283 !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1284 return -EINVAL;
1285
1286 netlbl_netlink_auditinfo(skb, &audit_info);
1287
1288 ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1289 if (ret_val != 0)
1290 return ret_val;
1291
1292 return netlbl_unlhsh_remove(&init_net,
1293 NULL, addr, mask, addr_len,
1294 &audit_info);
1295}
1296
1297
1298/**
1299 * netlbl_unlabel_staticlist_gen - Generate messages for STATICLIST[DEF]
1300 * @cmd: command/message
1301 * @iface: the interface entry
1302 * @addr4: the IPv4 address entry
1303 * @addr6: the IPv6 address entry
1304 * @arg: the netlbl_unlhsh_walk_arg structure
1305 *
1306 * Description:
1307 * This function is designed to be used to generate a response for a
1308 * STATICLIST or STATICLISTDEF message. When called either @addr4 or @addr6
1309 * can be specified, not both, the other unspecified entry should be set to
1310 * NULL by the caller. Returns the size of the message on success, negative
1311 * values on failure.
1312 *
1313 */
1314static int netlbl_unlabel_staticlist_gen(u32 cmd,
1315 const struct netlbl_unlhsh_iface *iface,
1316 const struct netlbl_unlhsh_addr4 *addr4,
1317 const struct netlbl_unlhsh_addr6 *addr6,
1318 void *arg)
1319{
1320 int ret_val = -ENOMEM;
1321 struct netlbl_unlhsh_walk_arg *cb_arg = arg;
1322 struct net_device *dev;
1323 void *data;
1324 u32 secid;
1325 char *secctx;
1326 u32 secctx_len;
1327
1328 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
1329 cb_arg->seq, &netlbl_unlabel_gnl_family,
1330 NLM_F_MULTI, cmd);
1331 if (data == NULL)
1332 goto list_cb_failure;
1333
1334 if (iface->ifindex > 0) {
1335 dev = dev_get_by_index(&init_net, iface->ifindex);
1336 ret_val = nla_put_string(cb_arg->skb,
1337 NLBL_UNLABEL_A_IFACE, dev->name);
1338 dev_put(dev);
1339 if (ret_val != 0)
1340 goto list_cb_failure;
1341 }
1342
1343 if (addr4) {
1344 struct in_addr addr_struct;
1345
1346 addr_struct.s_addr = addr4->addr;
1347 ret_val = nla_put(cb_arg->skb,
1348 NLBL_UNLABEL_A_IPV4ADDR,
1349 sizeof(struct in_addr),
1350 &addr_struct);
1351 if (ret_val != 0)
1352 goto list_cb_failure;
1353
1354 addr_struct.s_addr = addr4->mask;
1355 ret_val = nla_put(cb_arg->skb,
1356 NLBL_UNLABEL_A_IPV4MASK,
1357 sizeof(struct in_addr),
1358 &addr_struct);
1359 if (ret_val != 0)
1360 goto list_cb_failure;
1361
1362 secid = addr4->secid;
1363 } else {
1364 ret_val = nla_put(cb_arg->skb,
1365 NLBL_UNLABEL_A_IPV6ADDR,
1366 sizeof(struct in6_addr),
1367 &addr6->addr);
1368 if (ret_val != 0)
1369 goto list_cb_failure;
1370
1371 ret_val = nla_put(cb_arg->skb,
1372 NLBL_UNLABEL_A_IPV6MASK,
1373 sizeof(struct in6_addr),
1374 &addr6->mask);
1375 if (ret_val != 0)
1376 goto list_cb_failure;
1377
1378 secid = addr6->secid;
1379 }
1380
1381 ret_val = security_secid_to_secctx(secid, &secctx, &secctx_len);
1382 if (ret_val != 0)
1383 goto list_cb_failure;
1384 ret_val = nla_put(cb_arg->skb,
1385 NLBL_UNLABEL_A_SECCTX,
1386 secctx_len,
1387 secctx);
1388 security_release_secctx(secctx, secctx_len);
1389 if (ret_val != 0)
1390 goto list_cb_failure;
1391
1392 cb_arg->seq++;
1393 return genlmsg_end(cb_arg->skb, data);
1394
1395list_cb_failure:
1396 genlmsg_cancel(cb_arg->skb, data);
1397 return ret_val;
1398}
1399
1400/**
1401 * netlbl_unlabel_staticlist - Handle a STATICLIST message
1402 * @skb: the NETLINK buffer
1403 * @cb: the NETLINK callback
1404 *
1405 * Description:
1406 * Process a user generated STATICLIST message and dump the unlabeled
1407 * connection hash table in a form suitable for use in a kernel generated
1408 * STATICLIST message. Returns the length of @skb.
1409 *
1410 */
1411static int netlbl_unlabel_staticlist(struct sk_buff *skb,
1412 struct netlink_callback *cb)
1413{
1414 struct netlbl_unlhsh_walk_arg cb_arg;
1415 u32 skip_bkt = cb->args[0];
1416 u32 skip_chain = cb->args[1];
1417 u32 skip_addr4 = cb->args[2];
1418 u32 skip_addr6 = cb->args[3];
1419 u32 iter_bkt;
1420 u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
1421 struct netlbl_unlhsh_iface *iface;
1422 struct netlbl_unlhsh_addr4 *addr4;
1423 struct netlbl_unlhsh_addr6 *addr6;
1424
1425 cb_arg.nl_cb = cb;
1426 cb_arg.skb = skb;
1427 cb_arg.seq = cb->nlh->nlmsg_seq;
1428
1429 rcu_read_lock();
1430 for (iter_bkt = skip_bkt;
1431 iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
1432 iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) {
1433 list_for_each_entry_rcu(iface,
1434 &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt],
1435 list) {
1436 if (!iface->valid ||
1437 iter_chain++ < skip_chain)
1438 continue;
1439 list_for_each_entry_rcu(addr4,
1440 &iface->addr4_list,
1441 list) {
1442 if (!addr4->valid || iter_addr4++ < skip_addr4)
1443 continue;
1444 if (netlbl_unlabel_staticlist_gen(
1445 NLBL_UNLABEL_C_STATICLIST,
1446 iface,
1447 addr4,
1448 NULL,
1449 &cb_arg) < 0) {
1450 iter_addr4--;
1451 iter_chain--;
1452 goto unlabel_staticlist_return;
1453 }
1454 }
1455 list_for_each_entry_rcu(addr6,
1456 &iface->addr6_list,
1457 list) {
1458 if (!addr6->valid || iter_addr6++ < skip_addr6)
1459 continue;
1460 if (netlbl_unlabel_staticlist_gen(
1461 NLBL_UNLABEL_C_STATICLIST,
1462 iface,
1463 NULL,
1464 addr6,
1465 &cb_arg) < 0) {
1466 iter_addr6--;
1467 iter_chain--;
1468 goto unlabel_staticlist_return;
1469 }
1470 }
1471 }
1472 }
1473
1474unlabel_staticlist_return:
1475 rcu_read_unlock();
1476 cb->args[0] = skip_bkt;
1477 cb->args[1] = skip_chain;
1478 cb->args[2] = skip_addr4;
1479 cb->args[3] = skip_addr6;
1480 return skb->len;
1481}
1482
1483/**
1484 * netlbl_unlabel_staticlistdef - Handle a STATICLISTDEF message
1485 * @skb: the NETLINK buffer
1486 * @cb: the NETLINK callback
1487 *
1488 * Description:
1489 * Process a user generated STATICLISTDEF message and dump the default
1490 * unlabeled connection entry in a form suitable for use in a kernel generated
1491 * STATICLISTDEF message. Returns the length of @skb.
1492 *
1493 */
1494static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
1495 struct netlink_callback *cb)
1496{
1497 struct netlbl_unlhsh_walk_arg cb_arg;
1498 struct netlbl_unlhsh_iface *iface;
1499 u32 skip_addr4 = cb->args[0];
1500 u32 skip_addr6 = cb->args[1];
1501 u32 iter_addr4 = 0, iter_addr6 = 0;
1502 struct netlbl_unlhsh_addr4 *addr4;
1503 struct netlbl_unlhsh_addr6 *addr6;
1504
1505 cb_arg.nl_cb = cb;
1506 cb_arg.skb = skb;
1507 cb_arg.seq = cb->nlh->nlmsg_seq;
1508
1509 rcu_read_lock();
1510 iface = rcu_dereference(netlbl_unlhsh_def);
1511 if (iface == NULL || !iface->valid)
1512 goto unlabel_staticlistdef_return;
1513
1514 list_for_each_entry_rcu(addr4, &iface->addr4_list, list) {
1515 if (!addr4->valid || iter_addr4++ < skip_addr4)
1516 continue;
1517 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1518 iface,
1519 addr4,
1520 NULL,
1521 &cb_arg) < 0) {
1522 iter_addr4--;
1523 goto unlabel_staticlistdef_return;
1524 }
1525 }
1526 list_for_each_entry_rcu(addr6, &iface->addr6_list, list) {
1527 if (addr6->valid || iter_addr6++ < skip_addr6)
1528 continue;
1529 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1530 iface,
1531 NULL,
1532 addr6,
1533 &cb_arg) < 0) {
1534 iter_addr6--;
1535 goto unlabel_staticlistdef_return;
1536 }
1537 }
1538
1539unlabel_staticlistdef_return:
1540 rcu_read_unlock();
1541 cb->args[0] = skip_addr4;
1542 cb->args[1] = skip_addr6;
1543 return skb->len;
1544}
178 1545
179/* 1546/*
180 * NetLabel Generic NETLINK Command Definitions 1547 * NetLabel Generic NETLINK Command Definitions
181 */ 1548 */
182 1549
1550static struct genl_ops netlbl_unlabel_genl_c_staticadd = {
1551 .cmd = NLBL_UNLABEL_C_STATICADD,
1552 .flags = GENL_ADMIN_PERM,
1553 .policy = netlbl_unlabel_genl_policy,
1554 .doit = netlbl_unlabel_staticadd,
1555 .dumpit = NULL,
1556};
1557
1558static struct genl_ops netlbl_unlabel_genl_c_staticremove = {
1559 .cmd = NLBL_UNLABEL_C_STATICREMOVE,
1560 .flags = GENL_ADMIN_PERM,
1561 .policy = netlbl_unlabel_genl_policy,
1562 .doit = netlbl_unlabel_staticremove,
1563 .dumpit = NULL,
1564};
1565
1566static struct genl_ops netlbl_unlabel_genl_c_staticlist = {
1567 .cmd = NLBL_UNLABEL_C_STATICLIST,
1568 .flags = 0,
1569 .policy = netlbl_unlabel_genl_policy,
1570 .doit = NULL,
1571 .dumpit = netlbl_unlabel_staticlist,
1572};
1573
1574static struct genl_ops netlbl_unlabel_genl_c_staticadddef = {
1575 .cmd = NLBL_UNLABEL_C_STATICADDDEF,
1576 .flags = GENL_ADMIN_PERM,
1577 .policy = netlbl_unlabel_genl_policy,
1578 .doit = netlbl_unlabel_staticadddef,
1579 .dumpit = NULL,
1580};
1581
1582static struct genl_ops netlbl_unlabel_genl_c_staticremovedef = {
1583 .cmd = NLBL_UNLABEL_C_STATICREMOVEDEF,
1584 .flags = GENL_ADMIN_PERM,
1585 .policy = netlbl_unlabel_genl_policy,
1586 .doit = netlbl_unlabel_staticremovedef,
1587 .dumpit = NULL,
1588};
1589
1590static struct genl_ops netlbl_unlabel_genl_c_staticlistdef = {
1591 .cmd = NLBL_UNLABEL_C_STATICLISTDEF,
1592 .flags = 0,
1593 .policy = netlbl_unlabel_genl_policy,
1594 .doit = NULL,
1595 .dumpit = netlbl_unlabel_staticlistdef,
1596};
1597
183static struct genl_ops netlbl_unlabel_genl_c_accept = { 1598static struct genl_ops netlbl_unlabel_genl_c_accept = {
184 .cmd = NLBL_UNLABEL_C_ACCEPT, 1599 .cmd = NLBL_UNLABEL_C_ACCEPT,
185 .flags = GENL_ADMIN_PERM, 1600 .flags = GENL_ADMIN_PERM,
@@ -196,7 +1611,6 @@ static struct genl_ops netlbl_unlabel_genl_c_list = {
196 .dumpit = NULL, 1611 .dumpit = NULL,
197}; 1612};
198 1613
199
200/* 1614/*
201 * NetLabel Generic NETLINK Protocol Functions 1615 * NetLabel Generic NETLINK Protocol Functions
202 */ 1616 */
@@ -218,6 +1632,36 @@ int netlbl_unlabel_genl_init(void)
218 return ret_val; 1632 return ret_val;
219 1633
220 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, 1634 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1635 &netlbl_unlabel_genl_c_staticadd);
1636 if (ret_val != 0)
1637 return ret_val;
1638
1639 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1640 &netlbl_unlabel_genl_c_staticremove);
1641 if (ret_val != 0)
1642 return ret_val;
1643
1644 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1645 &netlbl_unlabel_genl_c_staticlist);
1646 if (ret_val != 0)
1647 return ret_val;
1648
1649 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1650 &netlbl_unlabel_genl_c_staticadddef);
1651 if (ret_val != 0)
1652 return ret_val;
1653
1654 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1655 &netlbl_unlabel_genl_c_staticremovedef);
1656 if (ret_val != 0)
1657 return ret_val;
1658
1659 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1660 &netlbl_unlabel_genl_c_staticlistdef);
1661 if (ret_val != 0)
1662 return ret_val;
1663
1664 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
221 &netlbl_unlabel_genl_c_accept); 1665 &netlbl_unlabel_genl_c_accept);
222 if (ret_val != 0) 1666 if (ret_val != 0)
223 return ret_val; 1667 return ret_val;
@@ -234,8 +1678,58 @@ int netlbl_unlabel_genl_init(void)
234 * NetLabel KAPI Hooks 1678 * NetLabel KAPI Hooks
235 */ 1679 */
236 1680
1681static struct notifier_block netlbl_unlhsh_netdev_notifier = {
1682 .notifier_call = netlbl_unlhsh_netdev_handler,
1683};
1684
1685/**
1686 * netlbl_unlabel_init - Initialize the unlabeled connection hash table
1687 * @size: the number of bits to use for the hash buckets
1688 *
1689 * Description:
1690 * Initializes the unlabeled connection hash table and registers a network
1691 * device notification handler. This function should only be called by the
1692 * NetLabel subsystem itself during initialization. Returns zero on success,
1693 * non-zero values on error.
1694 *
1695 */
1696int netlbl_unlabel_init(u32 size)
1697{
1698 u32 iter;
1699 struct netlbl_unlhsh_tbl *hsh_tbl;
1700
1701 if (size == 0)
1702 return -EINVAL;
1703
1704 hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
1705 if (hsh_tbl == NULL)
1706 return -ENOMEM;
1707 hsh_tbl->size = 1 << size;
1708 hsh_tbl->tbl = kcalloc(hsh_tbl->size,
1709 sizeof(struct list_head),
1710 GFP_KERNEL);
1711 if (hsh_tbl->tbl == NULL) {
1712 kfree(hsh_tbl);
1713 return -ENOMEM;
1714 }
1715 for (iter = 0; iter < hsh_tbl->size; iter++)
1716 INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
1717
1718 rcu_read_lock();
1719 spin_lock(&netlbl_unlhsh_lock);
1720 rcu_assign_pointer(netlbl_unlhsh, hsh_tbl);
1721 spin_unlock(&netlbl_unlhsh_lock);
1722 rcu_read_unlock();
1723
1724 register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier);
1725
1726 return 0;
1727}
1728
237/** 1729/**
238 * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet 1730 * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
1731 * @skb: the packet
1732 * @family: protocol family
239 * @secattr: the security attributes 1733 * @secattr: the security attributes
240 * 1734 *
241 * Description: 1735 * Description:
@@ -243,19 +1737,52 @@ int netlbl_unlabel_genl_init(void)
243 * them in @secattr. Returns zero on success and negative values on failure. 1737 * them in @secattr. Returns zero on success and negative values on failure.
244 * 1738 *
245 */ 1739 */
246int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr) 1740int netlbl_unlabel_getattr(const struct sk_buff *skb,
1741 u16 family,
1742 struct netlbl_lsm_secattr *secattr)
247{ 1743{
248 int ret_val; 1744 struct iphdr *hdr4;
1745 struct ipv6hdr *hdr6;
1746 struct netlbl_unlhsh_addr4 *addr4;
1747 struct netlbl_unlhsh_addr6 *addr6;
1748 struct netlbl_unlhsh_iface *iface;
249 1749
250 rcu_read_lock(); 1750 rcu_read_lock();
251 if (netlabel_unlabel_acceptflg == 1) { 1751 iface = netlbl_unlhsh_search_iface_def(skb->iif);
252 netlbl_secattr_init(secattr); 1752 if (iface == NULL)
253 ret_val = 0; 1753 goto unlabel_getattr_nolabel;
254 } else 1754 switch (family) {
255 ret_val = -ENOMSG; 1755 case PF_INET:
1756 hdr4 = ip_hdr(skb);
1757 addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface);
1758 if (addr4 == NULL)
1759 goto unlabel_getattr_nolabel;
1760 secattr->attr.secid = addr4->secid;
1761 break;
1762#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1763 case PF_INET6:
1764 hdr6 = ipv6_hdr(skb);
1765 addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface);
1766 if (addr6 == NULL)
1767 goto unlabel_getattr_nolabel;
1768 secattr->attr.secid = addr6->secid;
1769 break;
1770#endif /* IPv6 */
1771 default:
1772 goto unlabel_getattr_nolabel;
1773 }
256 rcu_read_unlock(); 1774 rcu_read_unlock();
257 1775
258 return ret_val; 1776 secattr->flags |= NETLBL_SECATTR_SECID;
1777 secattr->type = NETLBL_NLTYPE_UNLABELED;
1778 return 0;
1779
1780unlabel_getattr_nolabel:
1781 rcu_read_unlock();
1782 if (netlabel_unlabel_acceptflg == 0)
1783 return -ENOMSG;
1784 secattr->type = NETLBL_NLTYPE_UNLABELED;
1785 return 0;
259} 1786}
260 1787
261/** 1788/**
diff --git a/net/netlabel/netlabel_unlabeled.h b/net/netlabel/netlabel_unlabeled.h
index c2917fbb42cf..06b1301ac072 100644
--- a/net/netlabel/netlabel_unlabeled.h
+++ b/net/netlabel/netlabel_unlabeled.h
@@ -36,6 +36,116 @@
36/* 36/*
37 * The following NetLabel payloads are supported by the Unlabeled subsystem. 37 * The following NetLabel payloads are supported by the Unlabeled subsystem.
38 * 38 *
39 * o STATICADD
40 * This message is sent from an application to add a new static label for
41 * incoming unlabeled connections.
42 *
43 * Required attributes:
44 *
45 * NLBL_UNLABEL_A_IFACE
46 * NLBL_UNLABEL_A_SECCTX
47 *
48 * If IPv4 is specified the following attributes are required:
49 *
50 * NLBL_UNLABEL_A_IPV4ADDR
51 * NLBL_UNLABEL_A_IPV4MASK
52 *
53 * If IPv6 is specified the following attributes are required:
54 *
55 * NLBL_UNLABEL_A_IPV6ADDR
56 * NLBL_UNLABEL_A_IPV6MASK
57 *
58 * o STATICREMOVE
59 * This message is sent from an application to remove an existing static
60 * label for incoming unlabeled connections.
61 *
62 * Required attributes:
63 *
64 * NLBL_UNLABEL_A_IFACE
65 *
66 * If IPv4 is specified the following attributes are required:
67 *
68 * NLBL_UNLABEL_A_IPV4ADDR
69 * NLBL_UNLABEL_A_IPV4MASK
70 *
71 * If IPv6 is specified the following attributes are required:
72 *
73 * NLBL_UNLABEL_A_IPV6ADDR
74 * NLBL_UNLABEL_A_IPV6MASK
75 *
76 * o STATICLIST
77 * This message can be sent either from an application or by the kernel in
78 * response to an application generated STATICLIST message. When sent by an
79 * application there is no payload and the NLM_F_DUMP flag should be set.
80 * The kernel should response with a series of the following messages.
81 *
82 * Required attributes:
83 *
84 * NLBL_UNLABEL_A_IFACE
85 * NLBL_UNLABEL_A_SECCTX
86 *
87 * If IPv4 is specified the following attributes are required:
88 *
89 * NLBL_UNLABEL_A_IPV4ADDR
90 * NLBL_UNLABEL_A_IPV4MASK
91 *
92 * If IPv6 is specified the following attributes are required:
93 *
94 * NLBL_UNLABEL_A_IPV6ADDR
95 * NLBL_UNLABEL_A_IPV6MASK
96 *
97 * o STATICADDDEF
98 * This message is sent from an application to set the default static
99 * label for incoming unlabeled connections.
100 *
101 * Required attribute:
102 *
103 * NLBL_UNLABEL_A_SECCTX
104 *
105 * If IPv4 is specified the following attributes are required:
106 *
107 * NLBL_UNLABEL_A_IPV4ADDR
108 * NLBL_UNLABEL_A_IPV4MASK
109 *
110 * If IPv6 is specified the following attributes are required:
111 *
112 * NLBL_UNLABEL_A_IPV6ADDR
113 * NLBL_UNLABEL_A_IPV6MASK
114 *
115 * o STATICREMOVEDEF
116 * This message is sent from an application to remove the existing default
117 * static label for incoming unlabeled connections.
118 *
119 * If IPv4 is specified the following attributes are required:
120 *
121 * NLBL_UNLABEL_A_IPV4ADDR
122 * NLBL_UNLABEL_A_IPV4MASK
123 *
124 * If IPv6 is specified the following attributes are required:
125 *
126 * NLBL_UNLABEL_A_IPV6ADDR
127 * NLBL_UNLABEL_A_IPV6MASK
128 *
129 * o STATICLISTDEF
130 * This message can be sent either from an application or by the kernel in
131 * response to an application generated STATICLISTDEF message. When sent by
132 * an application there is no payload and the NLM_F_DUMP flag should be set.
133 * The kernel should response with the following message.
134 *
135 * Required attribute:
136 *
137 * NLBL_UNLABEL_A_SECCTX
138 *
139 * If IPv4 is specified the following attributes are required:
140 *
141 * NLBL_UNLABEL_A_IPV4ADDR
142 * NLBL_UNLABEL_A_IPV4MASK
143 *
144 * If IPv6 is specified the following attributes are required:
145 *
146 * NLBL_UNLABEL_A_IPV6ADDR
147 * NLBL_UNLABEL_A_IPV6MASK
148 *
39 * o ACCEPT 149 * o ACCEPT
40 * This message is sent from an application to specify if the kernel should 150 * This message is sent from an application to specify if the kernel should
41 * allow unlabled packets to pass if they do not match any of the static 151 * allow unlabled packets to pass if they do not match any of the static
@@ -62,6 +172,12 @@ enum {
62 NLBL_UNLABEL_C_UNSPEC, 172 NLBL_UNLABEL_C_UNSPEC,
63 NLBL_UNLABEL_C_ACCEPT, 173 NLBL_UNLABEL_C_ACCEPT,
64 NLBL_UNLABEL_C_LIST, 174 NLBL_UNLABEL_C_LIST,
175 NLBL_UNLABEL_C_STATICADD,
176 NLBL_UNLABEL_C_STATICREMOVE,
177 NLBL_UNLABEL_C_STATICLIST,
178 NLBL_UNLABEL_C_STATICADDDEF,
179 NLBL_UNLABEL_C_STATICREMOVEDEF,
180 NLBL_UNLABEL_C_STATICLISTDEF,
65 __NLBL_UNLABEL_C_MAX, 181 __NLBL_UNLABEL_C_MAX,
66}; 182};
67#define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1) 183#define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1)
@@ -73,6 +189,24 @@ enum {
73 /* (NLA_U8) 189 /* (NLA_U8)
74 * if true then unlabeled packets are allowed to pass, else unlabeled 190 * if true then unlabeled packets are allowed to pass, else unlabeled
75 * packets are rejected */ 191 * packets are rejected */
192 NLBL_UNLABEL_A_IPV6ADDR,
193 /* (NLA_BINARY, struct in6_addr)
194 * an IPv6 address */
195 NLBL_UNLABEL_A_IPV6MASK,
196 /* (NLA_BINARY, struct in6_addr)
197 * an IPv6 address mask */
198 NLBL_UNLABEL_A_IPV4ADDR,
199 /* (NLA_BINARY, struct in_addr)
200 * an IPv4 address */
201 NLBL_UNLABEL_A_IPV4MASK,
202 /* (NLA_BINARY, struct in_addr)
203 * and IPv4 address mask */
204 NLBL_UNLABEL_A_IFACE,
205 /* (NLA_NULL_STRING)
206 * network interface */
207 NLBL_UNLABEL_A_SECCTX,
208 /* (NLA_BINARY)
209 * a LSM specific security context */
76 __NLBL_UNLABEL_A_MAX, 210 __NLBL_UNLABEL_A_MAX,
77}; 211};
78#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1) 212#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1)
@@ -80,8 +214,17 @@ enum {
80/* NetLabel protocol functions */ 214/* NetLabel protocol functions */
81int netlbl_unlabel_genl_init(void); 215int netlbl_unlabel_genl_init(void);
82 216
217/* Unlabeled connection hash table size */
218/* XXX - currently this number is an uneducated guess */
219#define NETLBL_UNLHSH_BITSIZE 7
220
221/* General Unlabeled init function */
222int netlbl_unlabel_init(u32 size);
223
83/* Process Unlabeled incoming network packets */ 224/* Process Unlabeled incoming network packets */
84int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr); 225int netlbl_unlabel_getattr(const struct sk_buff *skb,
226 u16 family,
227 struct netlbl_lsm_secattr *secattr);
85 228
86/* Set the default configuration to allow Unlabeled packets */ 229/* Set the default configuration to allow Unlabeled packets */
87int netlbl_unlabel_defconf(void); 230int netlbl_unlabel_defconf(void);
diff --git a/security/Kconfig b/security/Kconfig
index 8086e61058e3..389e151e3b68 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -76,6 +76,7 @@ config SECURITY_NETWORK_XFRM
76config SECURITY_CAPABILITIES 76config SECURITY_CAPABILITIES
77 bool "Default Linux Capabilities" 77 bool "Default Linux Capabilities"
78 depends on SECURITY 78 depends on SECURITY
79 default y
79 help 80 help
80 This enables the "default" Linux capabilities functionality. 81 This enables the "default" Linux capabilities functionality.
81 If you are unsure how to answer this question, answer Y. 82 If you are unsure how to answer this question, answer Y.
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index b32a459c0683..2b517d618672 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -145,7 +145,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX
145config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE 145config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
146 int "NSA SELinux maximum supported policy format version value" 146 int "NSA SELinux maximum supported policy format version value"
147 depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX 147 depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX
148 range 15 21 148 range 15 22
149 default 19 149 default 19
150 help 150 help
151 This option sets the value for the maximum policy format version 151 This option sets the value for the maximum policy format version
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index dc3502e30b19..00afd85f1edb 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -4,7 +4,14 @@
4 4
5obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/ 5obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/
6 6
7selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o exports.o 7selinux-y := avc.o \
8 hooks.o \
9 selinuxfs.o \
10 netlink.o \
11 nlmsgtab.o \
12 netif.o \
13 netnode.o \
14 exports.o
8 15
9selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o 16selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
10 17
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 81b3dff3cbf0..e8529e2f51e5 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -661,9 +661,18 @@ void avc_audit(u32 ssid, u32 tsid,
661 "daddr", "dest"); 661 "daddr", "dest");
662 break; 662 break;
663 } 663 }
664 if (a->u.net.netif) 664 if (a->u.net.netif > 0) {
665 audit_log_format(ab, " netif=%s", 665 struct net_device *dev;
666 a->u.net.netif); 666
667 /* NOTE: we always use init's namespace */
668 dev = dev_get_by_index(&init_net,
669 a->u.net.netif);
670 if (dev) {
671 audit_log_format(ab, " netif=%s",
672 dev->name);
673 dev_put(dev);
674 }
675 }
667 break; 676 break;
668 } 677 }
669 } 678 }
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index b6f96943be1f..87d2bb3ea355 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -17,10 +17,14 @@
17#include <linux/selinux.h> 17#include <linux/selinux.h>
18#include <linux/fs.h> 18#include <linux/fs.h>
19#include <linux/ipc.h> 19#include <linux/ipc.h>
20#include <asm/atomic.h>
20 21
21#include "security.h" 22#include "security.h"
22#include "objsec.h" 23#include "objsec.h"
23 24
25/* SECMARK reference count */
26extern atomic_t selinux_secmark_refcount;
27
24int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen) 28int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
25{ 29{
26 if (selinux_enabled) 30 if (selinux_enabled)
@@ -74,7 +78,7 @@ int selinux_string_to_sid(char *str, u32 *sid)
74} 78}
75EXPORT_SYMBOL_GPL(selinux_string_to_sid); 79EXPORT_SYMBOL_GPL(selinux_string_to_sid);
76 80
77int selinux_relabel_packet_permission(u32 sid) 81int selinux_secmark_relabel_packet_permission(u32 sid)
78{ 82{
79 if (selinux_enabled) { 83 if (selinux_enabled) {
80 struct task_security_struct *tsec = current->security; 84 struct task_security_struct *tsec = current->security;
@@ -84,4 +88,16 @@ int selinux_relabel_packet_permission(u32 sid)
84 } 88 }
85 return 0; 89 return 0;
86} 90}
87EXPORT_SYMBOL_GPL(selinux_relabel_packet_permission); 91EXPORT_SYMBOL_GPL(selinux_secmark_relabel_packet_permission);
92
93void selinux_secmark_refcount_inc(void)
94{
95 atomic_inc(&selinux_secmark_refcount);
96}
97EXPORT_SYMBOL_GPL(selinux_secmark_refcount_inc);
98
99void selinux_secmark_refcount_dec(void)
100{
101 atomic_dec(&selinux_secmark_refcount);
102}
103EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 64d414efb404..be6de0b8734f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -12,8 +12,8 @@
12 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 12 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
13 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. 13 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
14 * <dgoeddel@trustedcs.com> 14 * <dgoeddel@trustedcs.com>
15 * Copyright (C) 2006 Hewlett-Packard Development Company, L.P. 15 * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
16 * Paul Moore, <paul.moore@hp.com> 16 * Paul Moore <paul.moore@hp.com>
17 * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. 17 * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
18 * Yuichi Nakamura <ynakam@hitachisoft.jp> 18 * Yuichi Nakamura <ynakam@hitachisoft.jp>
19 * 19 *
@@ -50,8 +50,11 @@
50#include <net/icmp.h> 50#include <net/icmp.h>
51#include <net/ip.h> /* for local_port_range[] */ 51#include <net/ip.h> /* for local_port_range[] */
52#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ 52#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
53#include <net/net_namespace.h>
54#include <net/netlabel.h>
53#include <asm/uaccess.h> 55#include <asm/uaccess.h>
54#include <asm/ioctls.h> 56#include <asm/ioctls.h>
57#include <asm/atomic.h>
55#include <linux/bitops.h> 58#include <linux/bitops.h>
56#include <linux/interrupt.h> 59#include <linux/interrupt.h>
57#include <linux/netdevice.h> /* for network interface checks */ 60#include <linux/netdevice.h> /* for network interface checks */
@@ -76,6 +79,7 @@
76#include "avc.h" 79#include "avc.h"
77#include "objsec.h" 80#include "objsec.h"
78#include "netif.h" 81#include "netif.h"
82#include "netnode.h"
79#include "xfrm.h" 83#include "xfrm.h"
80#include "netlabel.h" 84#include "netlabel.h"
81 85
@@ -89,6 +93,9 @@ extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
89extern int selinux_compat_net; 93extern int selinux_compat_net;
90extern struct security_operations *security_ops; 94extern struct security_operations *security_ops;
91 95
96/* SECMARK reference count */
97atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
98
92#ifdef CONFIG_SECURITY_SELINUX_DEVELOP 99#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
93int selinux_enforcing = 0; 100int selinux_enforcing = 0;
94 101
@@ -155,6 +162,21 @@ getsecurity_exit:
155 return len; 162 return len;
156} 163}
157 164
165/**
166 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
167 *
168 * Description:
169 * This function checks the SECMARK reference counter to see if any SECMARK
170 * targets are currently configured, if the reference counter is greater than
171 * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
172 * enabled, false (0) if SECMARK is disabled.
173 *
174 */
175static int selinux_secmark_enabled(void)
176{
177 return (atomic_read(&selinux_secmark_refcount) > 0);
178}
179
158/* Allocate and free functions for each kind of security blob. */ 180/* Allocate and free functions for each kind of security blob. */
159 181
160static int task_alloc_security(struct task_struct *task) 182static int task_alloc_security(struct task_struct *task)
@@ -561,8 +583,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
561 * Allow filesystems with binary mount data to explicitly set mount point 583 * Allow filesystems with binary mount data to explicitly set mount point
562 * labeling information. 584 * labeling information.
563 */ 585 */
564int selinux_set_mnt_opts(struct super_block *sb, char **mount_options, 586static int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
565 int *flags, int num_opts) 587 int *flags, int num_opts)
566{ 588{
567 int rc = 0, i; 589 int rc = 0, i;
568 struct task_security_struct *tsec = current->security; 590 struct task_security_struct *tsec = current->security;
@@ -3395,7 +3417,7 @@ out:
3395#endif /* IPV6 */ 3417#endif /* IPV6 */
3396 3418
3397static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, 3419static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
3398 char **addrp, int *len, int src, u8 *proto) 3420 char **addrp, int src, u8 *proto)
3399{ 3421{
3400 int ret = 0; 3422 int ret = 0;
3401 3423
@@ -3404,7 +3426,6 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
3404 ret = selinux_parse_skb_ipv4(skb, ad, proto); 3426 ret = selinux_parse_skb_ipv4(skb, ad, proto);
3405 if (ret || !addrp) 3427 if (ret || !addrp)
3406 break; 3428 break;
3407 *len = 4;
3408 *addrp = (char *)(src ? &ad->u.net.v4info.saddr : 3429 *addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3409 &ad->u.net.v4info.daddr); 3430 &ad->u.net.v4info.daddr);
3410 break; 3431 break;
@@ -3414,7 +3435,6 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
3414 ret = selinux_parse_skb_ipv6(skb, ad, proto); 3435 ret = selinux_parse_skb_ipv6(skb, ad, proto);
3415 if (ret || !addrp) 3436 if (ret || !addrp)
3416 break; 3437 break;
3417 *len = 16;
3418 *addrp = (char *)(src ? &ad->u.net.v6info.saddr : 3438 *addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3419 &ad->u.net.v6info.daddr); 3439 &ad->u.net.v6info.daddr);
3420 break; 3440 break;
@@ -3423,36 +3443,48 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
3423 break; 3443 break;
3424 } 3444 }
3425 3445
3446 if (unlikely(ret))
3447 printk(KERN_WARNING
3448 "SELinux: failure in selinux_parse_skb(),"
3449 " unable to parse packet\n");
3450
3426 return ret; 3451 return ret;
3427} 3452}
3428 3453
3429/** 3454/**
3430 * selinux_skb_extlbl_sid - Determine the external label of a packet 3455 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
3431 * @skb: the packet 3456 * @skb: the packet
3432 * @sid: the packet's SID 3457 * @family: protocol family
3458 * @sid: the packet's peer label SID
3433 * 3459 *
3434 * Description: 3460 * Description:
3435 * Check the various different forms of external packet labeling and determine 3461 * Check the various different forms of network peer labeling and determine
3436 * the external SID for the packet. If only one form of external labeling is 3462 * the peer label/SID for the packet; most of the magic actually occurs in
3437 * present then it is used, if both labeled IPsec and NetLabel labels are 3463 * the security server function security_net_peersid_cmp(). The function
3438 * present then the SELinux type information is taken from the labeled IPsec 3464 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3439 * SA and the MLS sensitivity label information is taken from the NetLabel 3465 * or -EACCES if @sid is invalid due to inconsistencies with the different
3440 * security attributes. This bit of "magic" is done in the call to 3466 * peer labels.
3441 * selinux_netlbl_skbuff_getsid().
3442 * 3467 *
3443 */ 3468 */
3444static void selinux_skb_extlbl_sid(struct sk_buff *skb, u32 *sid) 3469static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
3445{ 3470{
3471 int err;
3446 u32 xfrm_sid; 3472 u32 xfrm_sid;
3447 u32 nlbl_sid; 3473 u32 nlbl_sid;
3474 u32 nlbl_type;
3448 3475
3449 selinux_skb_xfrm_sid(skb, &xfrm_sid); 3476 selinux_skb_xfrm_sid(skb, &xfrm_sid);
3450 if (selinux_netlbl_skbuff_getsid(skb, 3477 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
3451 (xfrm_sid == SECSID_NULL ? 3478
3452 SECINITSID_NETMSG : xfrm_sid), 3479 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3453 &nlbl_sid) != 0) 3480 if (unlikely(err)) {
3454 nlbl_sid = SECSID_NULL; 3481 printk(KERN_WARNING
3455 *sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid); 3482 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3483 " unable to determine packet's peer label\n");
3484 return -EACCES;
3485 }
3486
3487 return 0;
3456} 3488}
3457 3489
3458/* socket security operations */ 3490/* socket security operations */
@@ -3518,6 +3550,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
3518 if (sock->sk) { 3550 if (sock->sk) {
3519 sksec = sock->sk->sk_security; 3551 sksec = sock->sk->sk_security;
3520 sksec->sid = isec->sid; 3552 sksec->sid = isec->sid;
3553 sksec->sclass = isec->sclass;
3521 err = selinux_netlbl_socket_post_create(sock); 3554 err = selinux_netlbl_socket_post_create(sock);
3522 } 3555 }
3523 3556
@@ -3610,7 +3643,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
3610 break; 3643 break;
3611 } 3644 }
3612 3645
3613 err = security_node_sid(family, addrp, addrlen, &sid); 3646 err = sel_netnode_sid(addrp, family, &sid);
3614 if (err) 3647 if (err)
3615 goto out; 3648 goto out;
3616 3649
@@ -3821,131 +3854,182 @@ static int selinux_socket_unix_may_send(struct socket *sock,
3821 return 0; 3854 return 0;
3822} 3855}
3823 3856
3824static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, 3857static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
3825 struct avc_audit_data *ad, u16 family, char *addrp, int len) 3858 u32 peer_sid,
3859 struct avc_audit_data *ad)
3826{ 3860{
3827 int err = 0; 3861 int err;
3828 u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; 3862 u32 if_sid;
3829 struct socket *sock; 3863 u32 node_sid;
3830 u16 sock_class = 0;
3831 u32 sock_sid = 0;
3832
3833 read_lock_bh(&sk->sk_callback_lock);
3834 sock = sk->sk_socket;
3835 if (sock) {
3836 struct inode *inode;
3837 inode = SOCK_INODE(sock);
3838 if (inode) {
3839 struct inode_security_struct *isec;
3840 isec = inode->i_security;
3841 sock_sid = isec->sid;
3842 sock_class = isec->sclass;
3843 }
3844 }
3845 read_unlock_bh(&sk->sk_callback_lock);
3846 if (!sock_sid)
3847 goto out;
3848 3864
3849 if (!skb->dev) 3865 err = sel_netif_sid(ifindex, &if_sid);
3850 goto out; 3866 if (err)
3867 return err;
3868 err = avc_has_perm(peer_sid, if_sid,
3869 SECCLASS_NETIF, NETIF__INGRESS, ad);
3870 if (err)
3871 return err;
3851 3872
3852 err = sel_netif_sids(skb->dev, &if_sid, NULL); 3873 err = sel_netnode_sid(addrp, family, &node_sid);
3853 if (err) 3874 if (err)
3854 goto out; 3875 return err;
3876 return avc_has_perm(peer_sid, node_sid,
3877 SECCLASS_NODE, NODE__RECVFROM, ad);
3878}
3879
3880static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
3881 struct sk_buff *skb,
3882 struct avc_audit_data *ad,
3883 u16 family,
3884 char *addrp)
3885{
3886 int err;
3887 struct sk_security_struct *sksec = sk->sk_security;
3888 u16 sk_class;
3889 u32 netif_perm, node_perm, recv_perm;
3890 u32 port_sid, node_sid, if_sid, sk_sid;
3855 3891
3856 switch (sock_class) { 3892 sk_sid = sksec->sid;
3893 sk_class = sksec->sclass;
3894
3895 switch (sk_class) {
3857 case SECCLASS_UDP_SOCKET: 3896 case SECCLASS_UDP_SOCKET:
3858 netif_perm = NETIF__UDP_RECV; 3897 netif_perm = NETIF__UDP_RECV;
3859 node_perm = NODE__UDP_RECV; 3898 node_perm = NODE__UDP_RECV;
3860 recv_perm = UDP_SOCKET__RECV_MSG; 3899 recv_perm = UDP_SOCKET__RECV_MSG;
3861 break; 3900 break;
3862
3863 case SECCLASS_TCP_SOCKET: 3901 case SECCLASS_TCP_SOCKET:
3864 netif_perm = NETIF__TCP_RECV; 3902 netif_perm = NETIF__TCP_RECV;
3865 node_perm = NODE__TCP_RECV; 3903 node_perm = NODE__TCP_RECV;
3866 recv_perm = TCP_SOCKET__RECV_MSG; 3904 recv_perm = TCP_SOCKET__RECV_MSG;
3867 break; 3905 break;
3868
3869 case SECCLASS_DCCP_SOCKET: 3906 case SECCLASS_DCCP_SOCKET:
3870 netif_perm = NETIF__DCCP_RECV; 3907 netif_perm = NETIF__DCCP_RECV;
3871 node_perm = NODE__DCCP_RECV; 3908 node_perm = NODE__DCCP_RECV;
3872 recv_perm = DCCP_SOCKET__RECV_MSG; 3909 recv_perm = DCCP_SOCKET__RECV_MSG;
3873 break; 3910 break;
3874
3875 default: 3911 default:
3876 netif_perm = NETIF__RAWIP_RECV; 3912 netif_perm = NETIF__RAWIP_RECV;
3877 node_perm = NODE__RAWIP_RECV; 3913 node_perm = NODE__RAWIP_RECV;
3914 recv_perm = 0;
3878 break; 3915 break;
3879 } 3916 }
3880 3917
3881 err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); 3918 err = sel_netif_sid(skb->iif, &if_sid);
3882 if (err) 3919 if (err)
3883 goto out; 3920 return err;
3884 3921 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
3885 err = security_node_sid(family, addrp, len, &node_sid);
3886 if (err) 3922 if (err)
3887 goto out; 3923 return err;
3888 3924
3889 err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad); 3925 err = sel_netnode_sid(addrp, family, &node_sid);
3890 if (err) 3926 if (err)
3891 goto out; 3927 return err;
3928 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
3929 if (err)
3930 return err;
3892 3931
3893 if (recv_perm) { 3932 if (!recv_perm)
3894 u32 port_sid; 3933 return 0;
3934 err = security_port_sid(sk->sk_family, sk->sk_type,
3935 sk->sk_protocol, ntohs(ad->u.net.sport),
3936 &port_sid);
3937 if (unlikely(err)) {
3938 printk(KERN_WARNING
3939 "SELinux: failure in"
3940 " selinux_sock_rcv_skb_iptables_compat(),"
3941 " network port label not found\n");
3942 return err;
3943 }
3944 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
3945}
3895 3946
3896 err = security_port_sid(sk->sk_family, sk->sk_type, 3947static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
3897 sk->sk_protocol, ntohs(ad->u.net.sport), 3948 struct avc_audit_data *ad,
3898 &port_sid); 3949 u16 family, char *addrp)
3899 if (err) 3950{
3900 goto out; 3951 int err;
3952 struct sk_security_struct *sksec = sk->sk_security;
3953 u32 peer_sid;
3954 u32 sk_sid = sksec->sid;
3901 3955
3902 err = avc_has_perm(sock_sid, port_sid, 3956 if (selinux_compat_net)
3903 sock_class, recv_perm, ad); 3957 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad,
3958 family, addrp);
3959 else
3960 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
3961 PACKET__RECV, ad);
3962 if (err)
3963 return err;
3964
3965 if (selinux_policycap_netpeer) {
3966 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
3967 if (err)
3968 return err;
3969 err = avc_has_perm(sk_sid, peer_sid,
3970 SECCLASS_PEER, PEER__RECV, ad);
3971 } else {
3972 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad);
3973 if (err)
3974 return err;
3975 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad);
3904 } 3976 }
3905 3977
3906out:
3907 return err; 3978 return err;
3908} 3979}
3909 3980
3910static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 3981static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
3911{ 3982{
3912 u16 family; 3983 int err;
3913 char *addrp;
3914 int len, err = 0;
3915 struct avc_audit_data ad;
3916 struct sk_security_struct *sksec = sk->sk_security; 3984 struct sk_security_struct *sksec = sk->sk_security;
3985 u16 family = sk->sk_family;
3986 u32 sk_sid = sksec->sid;
3987 struct avc_audit_data ad;
3988 char *addrp;
3917 3989
3918 family = sk->sk_family;
3919 if (family != PF_INET && family != PF_INET6) 3990 if (family != PF_INET && family != PF_INET6)
3920 goto out; 3991 return 0;
3921 3992
3922 /* Handle mapped IPv4 packets arriving via IPv6 sockets */ 3993 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
3923 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 3994 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
3924 family = PF_INET; 3995 family = PF_INET;
3925 3996
3926 AVC_AUDIT_DATA_INIT(&ad, NET); 3997 AVC_AUDIT_DATA_INIT(&ad, NET);
3927 ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; 3998 ad.u.net.netif = skb->iif;
3928 ad.u.net.family = family; 3999 ad.u.net.family = family;
3929 4000 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
3930 err = selinux_parse_skb(skb, &ad, &addrp, &len, 1, NULL);
3931 if (err) 4001 if (err)
3932 goto out; 4002 return err;
3933 4003
3934 if (selinux_compat_net) 4004 /* If any sort of compatibility mode is enabled then handoff processing
3935 err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family, 4005 * to the selinux_sock_rcv_skb_compat() function to deal with the
3936 addrp, len); 4006 * special handling. We do this in an attempt to keep this function
3937 else 4007 * as fast and as clean as possible. */
3938 err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, 4008 if (selinux_compat_net || !selinux_policycap_netpeer)
3939 PACKET__RECV, &ad); 4009 return selinux_sock_rcv_skb_compat(sk, skb, &ad,
3940 if (err) 4010 family, addrp);
3941 goto out;
3942 4011
3943 err = selinux_netlbl_sock_rcv_skb(sksec, skb, &ad); 4012 if (netlbl_enabled() || selinux_xfrm_enabled()) {
3944 if (err) 4013 u32 peer_sid;
3945 goto out; 4014
4015 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4016 if (err)
4017 return err;
4018 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4019 peer_sid, &ad);
4020 if (err)
4021 return err;
4022 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4023 PEER__RECV, &ad);
4024 }
4025
4026 if (selinux_secmark_enabled()) {
4027 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4028 PACKET__RECV, &ad);
4029 if (err)
4030 return err;
4031 }
3946 4032
3947 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
3948out:
3949 return err; 4033 return err;
3950} 4034}
3951 4035
@@ -3996,18 +4080,25 @@ out:
3996static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) 4080static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
3997{ 4081{
3998 u32 peer_secid = SECSID_NULL; 4082 u32 peer_secid = SECSID_NULL;
3999 int err = 0; 4083 u16 family;
4084
4085 if (sock)
4086 family = sock->sk->sk_family;
4087 else if (skb && skb->sk)
4088 family = skb->sk->sk_family;
4089 else
4090 goto out;
4000 4091
4001 if (sock && sock->sk->sk_family == PF_UNIX) 4092 if (sock && family == PF_UNIX)
4002 selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); 4093 selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
4003 else if (skb) 4094 else if (skb)
4004 selinux_skb_extlbl_sid(skb, &peer_secid); 4095 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
4005 4096
4006 if (peer_secid == SECSID_NULL) 4097out:
4007 err = -EINVAL;
4008 *secid = peer_secid; 4098 *secid = peer_secid;
4009 4099 if (peer_secid == SECSID_NULL)
4010 return err; 4100 return -EINVAL;
4101 return 0;
4011} 4102}
4012 4103
4013static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) 4104static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
@@ -4027,6 +4118,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4027 4118
4028 newssec->sid = ssec->sid; 4119 newssec->sid = ssec->sid;
4029 newssec->peer_sid = ssec->peer_sid; 4120 newssec->peer_sid = ssec->peer_sid;
4121 newssec->sclass = ssec->sclass;
4030 4122
4031 selinux_netlbl_sk_security_clone(ssec, newssec); 4123 selinux_netlbl_sk_security_clone(ssec, newssec);
4032} 4124}
@@ -4050,6 +4142,7 @@ static void selinux_sock_graft(struct sock* sk, struct socket *parent)
4050 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || 4142 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4051 sk->sk_family == PF_UNIX) 4143 sk->sk_family == PF_UNIX)
4052 isec->sid = sksec->sid; 4144 isec->sid = sksec->sid;
4145 sksec->sclass = isec->sclass;
4053 4146
4054 selinux_netlbl_sock_graft(sk, parent); 4147 selinux_netlbl_sock_graft(sk, parent);
4055} 4148}
@@ -4062,7 +4155,9 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4062 u32 newsid; 4155 u32 newsid;
4063 u32 peersid; 4156 u32 peersid;
4064 4157
4065 selinux_skb_extlbl_sid(skb, &peersid); 4158 err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid);
4159 if (err)
4160 return err;
4066 if (peersid == SECSID_NULL) { 4161 if (peersid == SECSID_NULL) {
4067 req->secid = sksec->sid; 4162 req->secid = sksec->sid;
4068 req->peer_secid = SECSID_NULL; 4163 req->peer_secid = SECSID_NULL;
@@ -4100,7 +4195,7 @@ static void selinux_inet_conn_established(struct sock *sk,
4100{ 4195{
4101 struct sk_security_struct *sksec = sk->sk_security; 4196 struct sk_security_struct *sksec = sk->sk_security;
4102 4197
4103 selinux_skb_extlbl_sid(skb, &sksec->peer_sid); 4198 selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid);
4104} 4199}
4105 4200
4106static void selinux_req_classify_flow(const struct request_sock *req, 4201static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4147,149 +4242,260 @@ out:
4147 4242
4148#ifdef CONFIG_NETFILTER 4243#ifdef CONFIG_NETFILTER
4149 4244
4150static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, 4245static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4151 struct avc_audit_data *ad, 4246 u16 family)
4152 u16 family, char *addrp, int len)
4153{ 4247{
4154 int err = 0; 4248 char *addrp;
4155 u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; 4249 u32 peer_sid;
4156 struct socket *sock; 4250 struct avc_audit_data ad;
4157 struct inode *inode; 4251 u8 secmark_active;
4158 struct inode_security_struct *isec; 4252 u8 peerlbl_active;
4159 4253
4160 sock = sk->sk_socket; 4254 if (!selinux_policycap_netpeer)
4161 if (!sock) 4255 return NF_ACCEPT;
4162 goto out;
4163 4256
4164 inode = SOCK_INODE(sock); 4257 secmark_active = selinux_secmark_enabled();
4165 if (!inode) 4258 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4166 goto out; 4259 if (!secmark_active && !peerlbl_active)
4260 return NF_ACCEPT;
4167 4261
4168 isec = inode->i_security; 4262 AVC_AUDIT_DATA_INIT(&ad, NET);
4169 4263 ad.u.net.netif = ifindex;
4170 err = sel_netif_sids(dev, &if_sid, NULL); 4264 ad.u.net.family = family;
4171 if (err) 4265 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4172 goto out; 4266 return NF_DROP;
4267
4268 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4269 return NF_DROP;
4270
4271 if (peerlbl_active)
4272 if (selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4273 peer_sid, &ad) != 0)
4274 return NF_DROP;
4275
4276 if (secmark_active)
4277 if (avc_has_perm(peer_sid, skb->secmark,
4278 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4279 return NF_DROP;
4280
4281 return NF_ACCEPT;
4282}
4283
4284static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4285 struct sk_buff *skb,
4286 const struct net_device *in,
4287 const struct net_device *out,
4288 int (*okfn)(struct sk_buff *))
4289{
4290 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4291}
4173 4292
4174 switch (isec->sclass) { 4293#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4294static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4295 struct sk_buff *skb,
4296 const struct net_device *in,
4297 const struct net_device *out,
4298 int (*okfn)(struct sk_buff *))
4299{
4300 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4301}
4302#endif /* IPV6 */
4303
4304static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4305 int ifindex,
4306 struct avc_audit_data *ad,
4307 u16 family, char *addrp)
4308{
4309 int err;
4310 struct sk_security_struct *sksec = sk->sk_security;
4311 u16 sk_class;
4312 u32 netif_perm, node_perm, send_perm;
4313 u32 port_sid, node_sid, if_sid, sk_sid;
4314
4315 sk_sid = sksec->sid;
4316 sk_class = sksec->sclass;
4317
4318 switch (sk_class) {
4175 case SECCLASS_UDP_SOCKET: 4319 case SECCLASS_UDP_SOCKET:
4176 netif_perm = NETIF__UDP_SEND; 4320 netif_perm = NETIF__UDP_SEND;
4177 node_perm = NODE__UDP_SEND; 4321 node_perm = NODE__UDP_SEND;
4178 send_perm = UDP_SOCKET__SEND_MSG; 4322 send_perm = UDP_SOCKET__SEND_MSG;
4179 break; 4323 break;
4180
4181 case SECCLASS_TCP_SOCKET: 4324 case SECCLASS_TCP_SOCKET:
4182 netif_perm = NETIF__TCP_SEND; 4325 netif_perm = NETIF__TCP_SEND;
4183 node_perm = NODE__TCP_SEND; 4326 node_perm = NODE__TCP_SEND;
4184 send_perm = TCP_SOCKET__SEND_MSG; 4327 send_perm = TCP_SOCKET__SEND_MSG;
4185 break; 4328 break;
4186
4187 case SECCLASS_DCCP_SOCKET: 4329 case SECCLASS_DCCP_SOCKET:
4188 netif_perm = NETIF__DCCP_SEND; 4330 netif_perm = NETIF__DCCP_SEND;
4189 node_perm = NODE__DCCP_SEND; 4331 node_perm = NODE__DCCP_SEND;
4190 send_perm = DCCP_SOCKET__SEND_MSG; 4332 send_perm = DCCP_SOCKET__SEND_MSG;
4191 break; 4333 break;
4192
4193 default: 4334 default:
4194 netif_perm = NETIF__RAWIP_SEND; 4335 netif_perm = NETIF__RAWIP_SEND;
4195 node_perm = NODE__RAWIP_SEND; 4336 node_perm = NODE__RAWIP_SEND;
4337 send_perm = 0;
4196 break; 4338 break;
4197 } 4339 }
4198 4340
4199 err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad); 4341 err = sel_netif_sid(ifindex, &if_sid);
4200 if (err) 4342 if (err)
4201 goto out; 4343 return err;
4344 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4345 return err;
4202 4346
4203 err = security_node_sid(family, addrp, len, &node_sid); 4347 err = sel_netnode_sid(addrp, family, &node_sid);
4204 if (err) 4348 if (err)
4205 goto out; 4349 return err;
4206 4350 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
4207 err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad);
4208 if (err) 4351 if (err)
4209 goto out; 4352 return err;
4210 4353
4211 if (send_perm) { 4354 if (send_perm != 0)
4212 u32 port_sid; 4355 return 0;
4213
4214 err = security_port_sid(sk->sk_family,
4215 sk->sk_type,
4216 sk->sk_protocol,
4217 ntohs(ad->u.net.dport),
4218 &port_sid);
4219 if (err)
4220 goto out;
4221 4356
4222 err = avc_has_perm(isec->sid, port_sid, isec->sclass, 4357 err = security_port_sid(sk->sk_family, sk->sk_type,
4223 send_perm, ad); 4358 sk->sk_protocol, ntohs(ad->u.net.dport),
4359 &port_sid);
4360 if (unlikely(err)) {
4361 printk(KERN_WARNING
4362 "SELinux: failure in"
4363 " selinux_ip_postroute_iptables_compat(),"
4364 " network port label not found\n");
4365 return err;
4224 } 4366 }
4225out: 4367 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
4226 return err;
4227} 4368}
4228 4369
4229static unsigned int selinux_ip_postroute_last(unsigned int hooknum, 4370static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4230 struct sk_buff *skb, 4371 int ifindex,
4231 const struct net_device *in, 4372 struct avc_audit_data *ad,
4232 const struct net_device *out, 4373 u16 family,
4233 int (*okfn)(struct sk_buff *), 4374 char *addrp,
4234 u16 family) 4375 u8 proto)
4235{ 4376{
4236 char *addrp; 4377 struct sock *sk = skb->sk;
4237 int len, err = 0;
4238 struct sock *sk;
4239 struct avc_audit_data ad;
4240 struct net_device *dev = (struct net_device *)out;
4241 struct sk_security_struct *sksec; 4378 struct sk_security_struct *sksec;
4242 u8 proto;
4243
4244 sk = skb->sk;
4245 if (!sk)
4246 goto out;
4247 4379
4380 if (sk == NULL)
4381 return NF_ACCEPT;
4248 sksec = sk->sk_security; 4382 sksec = sk->sk_security;
4249 4383
4250 AVC_AUDIT_DATA_INIT(&ad, NET); 4384 if (selinux_compat_net) {
4251 ad.u.net.netif = dev->name; 4385 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
4252 ad.u.net.family = family; 4386 ad, family, addrp))
4387 return NF_DROP;
4388 } else {
4389 if (avc_has_perm(sksec->sid, skb->secmark,
4390 SECCLASS_PACKET, PACKET__SEND, ad))
4391 return NF_DROP;
4392 }
4253 4393
4254 err = selinux_parse_skb(skb, &ad, &addrp, &len, 0, &proto); 4394 if (selinux_policycap_netpeer)
4255 if (err) 4395 if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto))
4256 goto out; 4396 return NF_DROP;
4257 4397
4258 if (selinux_compat_net) 4398 return NF_ACCEPT;
4259 err = selinux_ip_postroute_last_compat(sk, dev, &ad, 4399}
4260 family, addrp, len);
4261 else
4262 err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET,
4263 PACKET__SEND, &ad);
4264 4400
4265 if (err) 4401static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4266 goto out; 4402 u16 family)
4403{
4404 u32 secmark_perm;
4405 u32 peer_sid;
4406 struct sock *sk;
4407 struct avc_audit_data ad;
4408 char *addrp;
4409 u8 proto;
4410 u8 secmark_active;
4411 u8 peerlbl_active;
4267 4412
4268 err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto); 4413 AVC_AUDIT_DATA_INIT(&ad, NET);
4269out: 4414 ad.u.net.netif = ifindex;
4270 return err ? NF_DROP : NF_ACCEPT; 4415 ad.u.net.family = family;
4416 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4417 return NF_DROP;
4418
4419 /* If any sort of compatibility mode is enabled then handoff processing
4420 * to the selinux_ip_postroute_compat() function to deal with the
4421 * special handling. We do this in an attempt to keep this function
4422 * as fast and as clean as possible. */
4423 if (selinux_compat_net || !selinux_policycap_netpeer)
4424 return selinux_ip_postroute_compat(skb, ifindex, &ad,
4425 family, addrp, proto);
4426
4427 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4428 * packet transformation so allow the packet to pass without any checks
4429 * since we'll have another chance to perform access control checks
4430 * when the packet is on it's final way out.
4431 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4432 * is NULL, in this case go ahead and apply access control. */
4433 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4434 return NF_ACCEPT;
4435
4436 secmark_active = selinux_secmark_enabled();
4437 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4438 if (!secmark_active && !peerlbl_active)
4439 return NF_ACCEPT;
4440
4441 /* if the packet is locally generated (skb->sk != NULL) then use the
4442 * socket's label as the peer label, otherwise the packet is being
4443 * forwarded through this system and we need to fetch the peer label
4444 * directly from the packet */
4445 sk = skb->sk;
4446 if (sk) {
4447 struct sk_security_struct *sksec = sk->sk_security;
4448 peer_sid = sksec->sid;
4449 secmark_perm = PACKET__SEND;
4450 } else {
4451 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4452 return NF_DROP;
4453 secmark_perm = PACKET__FORWARD_OUT;
4454 }
4455
4456 if (secmark_active)
4457 if (avc_has_perm(peer_sid, skb->secmark,
4458 SECCLASS_PACKET, secmark_perm, &ad))
4459 return NF_DROP;
4460
4461 if (peerlbl_active) {
4462 u32 if_sid;
4463 u32 node_sid;
4464
4465 if (sel_netif_sid(ifindex, &if_sid))
4466 return NF_DROP;
4467 if (avc_has_perm(peer_sid, if_sid,
4468 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4469 return NF_DROP;
4470
4471 if (sel_netnode_sid(addrp, family, &node_sid))
4472 return NF_DROP;
4473 if (avc_has_perm(peer_sid, node_sid,
4474 SECCLASS_NODE, NODE__SENDTO, &ad))
4475 return NF_DROP;
4476 }
4477
4478 return NF_ACCEPT;
4271} 4479}
4272 4480
4273static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum, 4481static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4274 struct sk_buff *skb, 4482 struct sk_buff *skb,
4275 const struct net_device *in, 4483 const struct net_device *in,
4276 const struct net_device *out, 4484 const struct net_device *out,
4277 int (*okfn)(struct sk_buff *)) 4485 int (*okfn)(struct sk_buff *))
4278{ 4486{
4279 return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET); 4487 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
4280} 4488}
4281 4489
4282#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 4490#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4283 4491static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4284static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum, 4492 struct sk_buff *skb,
4285 struct sk_buff *skb, 4493 const struct net_device *in,
4286 const struct net_device *in, 4494 const struct net_device *out,
4287 const struct net_device *out, 4495 int (*okfn)(struct sk_buff *))
4288 int (*okfn)(struct sk_buff *))
4289{ 4496{
4290 return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET6); 4497 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
4291} 4498}
4292
4293#endif /* IPV6 */ 4499#endif /* IPV6 */
4294 4500
4295#endif /* CONFIG_NETFILTER */ 4501#endif /* CONFIG_NETFILTER */
@@ -5277,22 +5483,40 @@ security_initcall(selinux_init);
5277 5483
5278#if defined(CONFIG_NETFILTER) 5484#if defined(CONFIG_NETFILTER)
5279 5485
5280static struct nf_hook_ops selinux_ipv4_op = { 5486static struct nf_hook_ops selinux_ipv4_ops[] = {
5281 .hook = selinux_ipv4_postroute_last, 5487 {
5282 .owner = THIS_MODULE, 5488 .hook = selinux_ipv4_postroute,
5283 .pf = PF_INET, 5489 .owner = THIS_MODULE,
5284 .hooknum = NF_INET_POST_ROUTING, 5490 .pf = PF_INET,
5285 .priority = NF_IP_PRI_SELINUX_LAST, 5491 .hooknum = NF_INET_POST_ROUTING,
5492 .priority = NF_IP_PRI_SELINUX_LAST,
5493 },
5494 {
5495 .hook = selinux_ipv4_forward,
5496 .owner = THIS_MODULE,
5497 .pf = PF_INET,
5498 .hooknum = NF_INET_FORWARD,
5499 .priority = NF_IP_PRI_SELINUX_FIRST,
5500 }
5286}; 5501};
5287 5502
5288#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 5503#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5289 5504
5290static struct nf_hook_ops selinux_ipv6_op = { 5505static struct nf_hook_ops selinux_ipv6_ops[] = {
5291 .hook = selinux_ipv6_postroute_last, 5506 {
5292 .owner = THIS_MODULE, 5507 .hook = selinux_ipv6_postroute,
5293 .pf = PF_INET6, 5508 .owner = THIS_MODULE,
5294 .hooknum = NF_INET_POST_ROUTING, 5509 .pf = PF_INET6,
5295 .priority = NF_IP6_PRI_SELINUX_LAST, 5510 .hooknum = NF_INET_POST_ROUTING,
5511 .priority = NF_IP6_PRI_SELINUX_LAST,
5512 },
5513 {
5514 .hook = selinux_ipv6_forward,
5515 .owner = THIS_MODULE,
5516 .pf = PF_INET6,
5517 .hooknum = NF_INET_FORWARD,
5518 .priority = NF_IP6_PRI_SELINUX_FIRST,
5519 }
5296}; 5520};
5297 5521
5298#endif /* IPV6 */ 5522#endif /* IPV6 */
@@ -5300,22 +5524,27 @@ static struct nf_hook_ops selinux_ipv6_op = {
5300static int __init selinux_nf_ip_init(void) 5524static int __init selinux_nf_ip_init(void)
5301{ 5525{
5302 int err = 0; 5526 int err = 0;
5527 u32 iter;
5303 5528
5304 if (!selinux_enabled) 5529 if (!selinux_enabled)
5305 goto out; 5530 goto out;
5306 5531
5307 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); 5532 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5308 5533
5309 err = nf_register_hook(&selinux_ipv4_op); 5534 for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) {
5310 if (err) 5535 err = nf_register_hook(&selinux_ipv4_ops[iter]);
5311 panic("SELinux: nf_register_hook for IPv4: error %d\n", err); 5536 if (err)
5537 panic("SELinux: nf_register_hook for IPv4: error %d\n",
5538 err);
5539 }
5312 5540
5313#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 5541#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5314 5542 for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) {
5315 err = nf_register_hook(&selinux_ipv6_op); 5543 err = nf_register_hook(&selinux_ipv6_ops[iter]);
5316 if (err) 5544 if (err)
5317 panic("SELinux: nf_register_hook for IPv6: error %d\n", err); 5545 panic("SELinux: nf_register_hook for IPv6: error %d\n",
5318 5546 err);
5547 }
5319#endif /* IPV6 */ 5548#endif /* IPV6 */
5320 5549
5321out: 5550out:
@@ -5327,11 +5556,15 @@ __initcall(selinux_nf_ip_init);
5327#ifdef CONFIG_SECURITY_SELINUX_DISABLE 5556#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5328static void selinux_nf_ip_exit(void) 5557static void selinux_nf_ip_exit(void)
5329{ 5558{
5559 u32 iter;
5560
5330 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); 5561 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
5331 5562
5332 nf_unregister_hook(&selinux_ipv4_op); 5563 for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++)
5564 nf_unregister_hook(&selinux_ipv4_ops[iter]);
5333#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 5565#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5334 nf_unregister_hook(&selinux_ipv6_op); 5566 for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++)
5567 nf_unregister_hook(&selinux_ipv6_ops[iter]);
5335#endif /* IPV6 */ 5568#endif /* IPV6 */
5336} 5569}
5337#endif 5570#endif
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index 049bf69429b6..399f868c5c8f 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -37,6 +37,8 @@
37 S_(SECCLASS_NODE, NODE__ENFORCE_DEST, "enforce_dest") 37 S_(SECCLASS_NODE, NODE__ENFORCE_DEST, "enforce_dest")
38 S_(SECCLASS_NODE, NODE__DCCP_RECV, "dccp_recv") 38 S_(SECCLASS_NODE, NODE__DCCP_RECV, "dccp_recv")
39 S_(SECCLASS_NODE, NODE__DCCP_SEND, "dccp_send") 39 S_(SECCLASS_NODE, NODE__DCCP_SEND, "dccp_send")
40 S_(SECCLASS_NODE, NODE__RECVFROM, "recvfrom")
41 S_(SECCLASS_NODE, NODE__SENDTO, "sendto")
40 S_(SECCLASS_NETIF, NETIF__TCP_RECV, "tcp_recv") 42 S_(SECCLASS_NETIF, NETIF__TCP_RECV, "tcp_recv")
41 S_(SECCLASS_NETIF, NETIF__TCP_SEND, "tcp_send") 43 S_(SECCLASS_NETIF, NETIF__TCP_SEND, "tcp_send")
42 S_(SECCLASS_NETIF, NETIF__UDP_RECV, "udp_recv") 44 S_(SECCLASS_NETIF, NETIF__UDP_RECV, "udp_recv")
@@ -45,6 +47,8 @@
45 S_(SECCLASS_NETIF, NETIF__RAWIP_SEND, "rawip_send") 47 S_(SECCLASS_NETIF, NETIF__RAWIP_SEND, "rawip_send")
46 S_(SECCLASS_NETIF, NETIF__DCCP_RECV, "dccp_recv") 48 S_(SECCLASS_NETIF, NETIF__DCCP_RECV, "dccp_recv")
47 S_(SECCLASS_NETIF, NETIF__DCCP_SEND, "dccp_send") 49 S_(SECCLASS_NETIF, NETIF__DCCP_SEND, "dccp_send")
50 S_(SECCLASS_NETIF, NETIF__INGRESS, "ingress")
51 S_(SECCLASS_NETIF, NETIF__EGRESS, "egress")
48 S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__CONNECTTO, "connectto") 52 S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__CONNECTTO, "connectto")
49 S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__NEWCONN, "newconn") 53 S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__NEWCONN, "newconn")
50 S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__ACCEPTFROM, "acceptfrom") 54 S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__ACCEPTFROM, "acceptfrom")
@@ -149,6 +153,10 @@
149 S_(SECCLASS_PACKET, PACKET__SEND, "send") 153 S_(SECCLASS_PACKET, PACKET__SEND, "send")
150 S_(SECCLASS_PACKET, PACKET__RECV, "recv") 154 S_(SECCLASS_PACKET, PACKET__RECV, "recv")
151 S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto") 155 S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto")
156 S_(SECCLASS_PACKET, PACKET__FLOW_IN, "flow_in")
157 S_(SECCLASS_PACKET, PACKET__FLOW_OUT, "flow_out")
158 S_(SECCLASS_PACKET, PACKET__FORWARD_IN, "forward_in")
159 S_(SECCLASS_PACKET, PACKET__FORWARD_OUT, "forward_out")
152 S_(SECCLASS_KEY, KEY__VIEW, "view") 160 S_(SECCLASS_KEY, KEY__VIEW, "view")
153 S_(SECCLASS_KEY, KEY__READ, "read") 161 S_(SECCLASS_KEY, KEY__READ, "read")
154 S_(SECCLASS_KEY, KEY__WRITE, "write") 162 S_(SECCLASS_KEY, KEY__WRITE, "write")
@@ -159,3 +167,4 @@
159 S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind") 167 S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind")
160 S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect") 168 S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect")
161 S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero") 169 S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero")
170 S_(SECCLASS_PEER, PEER__RECV, "recv")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index eda89a2ec635..84c9abc80978 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -292,6 +292,8 @@
292#define NODE__ENFORCE_DEST 0x00000040UL 292#define NODE__ENFORCE_DEST 0x00000040UL
293#define NODE__DCCP_RECV 0x00000080UL 293#define NODE__DCCP_RECV 0x00000080UL
294#define NODE__DCCP_SEND 0x00000100UL 294#define NODE__DCCP_SEND 0x00000100UL
295#define NODE__RECVFROM 0x00000200UL
296#define NODE__SENDTO 0x00000400UL
295#define NETIF__TCP_RECV 0x00000001UL 297#define NETIF__TCP_RECV 0x00000001UL
296#define NETIF__TCP_SEND 0x00000002UL 298#define NETIF__TCP_SEND 0x00000002UL
297#define NETIF__UDP_RECV 0x00000004UL 299#define NETIF__UDP_RECV 0x00000004UL
@@ -300,6 +302,8 @@
300#define NETIF__RAWIP_SEND 0x00000020UL 302#define NETIF__RAWIP_SEND 0x00000020UL
301#define NETIF__DCCP_RECV 0x00000040UL 303#define NETIF__DCCP_RECV 0x00000040UL
302#define NETIF__DCCP_SEND 0x00000080UL 304#define NETIF__DCCP_SEND 0x00000080UL
305#define NETIF__INGRESS 0x00000100UL
306#define NETIF__EGRESS 0x00000200UL
303#define NETLINK_SOCKET__IOCTL 0x00000001UL 307#define NETLINK_SOCKET__IOCTL 0x00000001UL
304#define NETLINK_SOCKET__READ 0x00000002UL 308#define NETLINK_SOCKET__READ 0x00000002UL
305#define NETLINK_SOCKET__WRITE 0x00000004UL 309#define NETLINK_SOCKET__WRITE 0x00000004UL
@@ -792,6 +796,10 @@
792#define PACKET__SEND 0x00000001UL 796#define PACKET__SEND 0x00000001UL
793#define PACKET__RECV 0x00000002UL 797#define PACKET__RECV 0x00000002UL
794#define PACKET__RELABELTO 0x00000004UL 798#define PACKET__RELABELTO 0x00000004UL
799#define PACKET__FLOW_IN 0x00000008UL
800#define PACKET__FLOW_OUT 0x00000010UL
801#define PACKET__FORWARD_IN 0x00000020UL
802#define PACKET__FORWARD_OUT 0x00000040UL
795#define KEY__VIEW 0x00000001UL 803#define KEY__VIEW 0x00000001UL
796#define KEY__READ 0x00000002UL 804#define KEY__READ 0x00000002UL
797#define KEY__WRITE 0x00000004UL 805#define KEY__WRITE 0x00000004UL
@@ -824,3 +832,4 @@
824#define DCCP_SOCKET__NODE_BIND 0x00400000UL 832#define DCCP_SOCKET__NODE_BIND 0x00400000UL
825#define DCCP_SOCKET__NAME_CONNECT 0x00800000UL 833#define DCCP_SOCKET__NAME_CONNECT 0x00800000UL
826#define MEMPROTECT__MMAP_ZERO 0x00000001UL 834#define MEMPROTECT__MMAP_ZERO 0x00000001UL
835#define PEER__RECV 0x00000001UL
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 553607a19e92..80c28fa6621c 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -51,7 +51,7 @@ struct avc_audit_data {
51 struct inode *inode; 51 struct inode *inode;
52 } fs; 52 } fs;
53 struct { 53 struct {
54 char *netif; 54 int netif;
55 struct sock *sk; 55 struct sock *sk;
56 u16 family; 56 u16 family;
57 __be16 dport; 57 __be16 dport;
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h
index e77de0e62ea0..b1b0d1d8f950 100644
--- a/security/selinux/include/class_to_string.h
+++ b/security/selinux/include/class_to_string.h
@@ -64,3 +64,10 @@
64 S_(NULL) 64 S_(NULL)
65 S_("dccp_socket") 65 S_("dccp_socket")
66 S_("memprotect") 66 S_("memprotect")
67 S_(NULL)
68 S_(NULL)
69 S_(NULL)
70 S_(NULL)
71 S_(NULL)
72 S_(NULL)
73 S_("peer")
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
index a9c2b20f14b5..09e9dd23ee1a 100644
--- a/security/selinux/include/flask.h
+++ b/security/selinux/include/flask.h
@@ -50,6 +50,7 @@
50#define SECCLASS_KEY 58 50#define SECCLASS_KEY 58
51#define SECCLASS_DCCP_SOCKET 60 51#define SECCLASS_DCCP_SOCKET 60
52#define SECCLASS_MEMPROTECT 61 52#define SECCLASS_MEMPROTECT 61
53#define SECCLASS_PEER 68
53 54
54/* 55/*
55 * Security identifier indices for initial entities 56 * Security identifier indices for initial entities
diff --git a/security/selinux/include/netif.h b/security/selinux/include/netif.h
index 8bd6f9992d2b..ce23edd128b3 100644
--- a/security/selinux/include/netif.h
+++ b/security/selinux/include/netif.h
@@ -7,6 +7,8 @@
7 * Author: James Morris <jmorris@redhat.com> 7 * Author: James Morris <jmorris@redhat.com>
8 * 8 *
9 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 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 * This program is free software; you can redistribute it and/or modify 13 * 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, 14 * it under the terms of the GNU General Public License version 2,
@@ -15,7 +17,7 @@
15#ifndef _SELINUX_NETIF_H_ 17#ifndef _SELINUX_NETIF_H_
16#define _SELINUX_NETIF_H_ 18#define _SELINUX_NETIF_H_
17 19
18int sel_netif_sids(struct net_device *dev, u32 *if_sid, u32 *msg_sid); 20int sel_netif_sid(int ifindex, u32 *sid);
19 21
20#endif /* _SELINUX_NETIF_H_ */ 22#endif /* _SELINUX_NETIF_H_ */
21 23
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index 218e3f77c350..00a2809c8506 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -46,13 +46,17 @@ void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
46void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, 46void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
47 struct sk_security_struct *newssec); 47 struct sk_security_struct *newssec);
48 48
49int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid); 49int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
50 u16 family,
51 u32 *type,
52 u32 *sid);
50 53
51void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); 54void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
52int selinux_netlbl_socket_post_create(struct socket *sock); 55int selinux_netlbl_socket_post_create(struct socket *sock);
53int selinux_netlbl_inode_permission(struct inode *inode, int mask); 56int selinux_netlbl_inode_permission(struct inode *inode, int mask);
54int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 57int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
55 struct sk_buff *skb, 58 struct sk_buff *skb,
59 u16 family,
56 struct avc_audit_data *ad); 60 struct avc_audit_data *ad);
57int selinux_netlbl_socket_setsockopt(struct socket *sock, 61int selinux_netlbl_socket_setsockopt(struct socket *sock,
58 int level, 62 int level,
@@ -83,9 +87,11 @@ static inline void selinux_netlbl_sk_security_clone(
83} 87}
84 88
85static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 89static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
86 u32 base_sid, 90 u16 family,
91 u32 *type,
87 u32 *sid) 92 u32 *sid)
88{ 93{
94 *type = NETLBL_NLTYPE_NONE;
89 *sid = SECSID_NULL; 95 *sid = SECSID_NULL;
90 return 0; 96 return 0;
91} 97}
@@ -106,6 +112,7 @@ static inline int selinux_netlbl_inode_permission(struct inode *inode,
106} 112}
107static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 113static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
108 struct sk_buff *skb, 114 struct sk_buff *skb,
115 u16 family,
109 struct avc_audit_data *ad) 116 struct avc_audit_data *ad)
110{ 117{
111 return 0; 118 return 0;
diff --git a/security/selinux/include/netnode.h b/security/selinux/include/netnode.h
new file mode 100644
index 000000000000..1b94450d11d2
--- /dev/null
+++ b/security/selinux/include/netnode.h
@@ -0,0 +1,32 @@
1/*
2 * Network node table
3 *
4 * SELinux must keep a mapping of network nodes to labels/SIDs. This
5 * mapping is maintained as part of the normal policy but a fast cache is
6 * needed to reduce the lookup overhead since most of these queries happen on
7 * a per-packet basis.
8 *
9 * Author: Paul Moore <paul.moore@hp.com>
10 *
11 */
12
13/*
14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
15 *
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of version 2 of the GNU General Public License as
18 * published by the Free Software Foundation.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 */
26
27#ifndef _SELINUX_NETNODE_H
28#define _SELINUX_NETNODE_H
29
30int sel_netnode_sid(void *addr, u16 family, u32 *sid);
31
32#endif
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 4138a80f8e27..c6c2bb4ebacc 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -96,17 +96,25 @@ struct bprm_security_struct {
96}; 96};
97 97
98struct netif_security_struct { 98struct netif_security_struct {
99 struct net_device *dev; /* back pointer */ 99 int ifindex; /* device index */
100 u32 if_sid; /* SID for this interface */ 100 u32 sid; /* SID for this interface */
101 u32 msg_sid; /* default SID for messages received on this interface */ 101};
102
103struct netnode_security_struct {
104 union {
105 __be32 ipv4; /* IPv4 node address */
106 struct in6_addr ipv6; /* IPv6 node address */
107 } addr;
108 u32 sid; /* SID for this node */
109 u16 family; /* address family */
102}; 110};
103 111
104struct sk_security_struct { 112struct sk_security_struct {
105 struct sock *sk; /* back pointer to sk object */ 113 struct sock *sk; /* back pointer to sk object */
106 u32 sid; /* SID of this object */ 114 u32 sid; /* SID of this object */
107 u32 peer_sid; /* SID of peer */ 115 u32 peer_sid; /* SID of peer */
108#ifdef CONFIG_NETLABEL
109 u16 sclass; /* sock security class */ 116 u16 sclass; /* sock security class */
117#ifdef CONFIG_NETLABEL
110 enum { /* NetLabel state */ 118 enum { /* NetLabel state */
111 NLBL_UNSET = 0, 119 NLBL_UNSET = 0,
112 NLBL_REQUIRE, 120 NLBL_REQUIRE,
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 39337afffec2..23137c17f917 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -25,13 +25,14 @@
25#define POLICYDB_VERSION_MLS 19 25#define POLICYDB_VERSION_MLS 19
26#define POLICYDB_VERSION_AVTAB 20 26#define POLICYDB_VERSION_AVTAB 20
27#define POLICYDB_VERSION_RANGETRANS 21 27#define POLICYDB_VERSION_RANGETRANS 21
28#define POLICYDB_VERSION_POLCAP 22
28 29
29/* Range of policy versions we understand*/ 30/* Range of policy versions we understand*/
30#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE 31#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
31#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX 32#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
32#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE 33#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
33#else 34#else
34#define POLICYDB_VERSION_MAX POLICYDB_VERSION_RANGETRANS 35#define POLICYDB_VERSION_MAX POLICYDB_VERSION_POLCAP
35#endif 36#endif
36 37
37struct netlbl_lsm_secattr; 38struct netlbl_lsm_secattr;
@@ -39,8 +40,19 @@ struct netlbl_lsm_secattr;
39extern int selinux_enabled; 40extern int selinux_enabled;
40extern int selinux_mls_enabled; 41extern int selinux_mls_enabled;
41 42
43/* Policy capabilities */
44enum {
45 POLICYDB_CAPABILITY_NETPEER,
46 __POLICYDB_CAPABILITY_MAX
47};
48#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
49
50extern int selinux_policycap_netpeer;
51
42int security_load_policy(void * data, size_t len); 52int security_load_policy(void * data, size_t len);
43 53
54int security_policycap_supported(unsigned int req_cap);
55
44#define SEL_VEC_MAX 32 56#define SEL_VEC_MAX 32
45struct av_decision { 57struct av_decision {
46 u32 allowed; 58 u32 allowed;
@@ -77,8 +89,7 @@ int security_get_user_sids(u32 callsid, char *username,
77int security_port_sid(u16 domain, u16 type, u8 protocol, u16 port, 89int security_port_sid(u16 domain, u16 type, u8 protocol, u16 port,
78 u32 *out_sid); 90 u32 *out_sid);
79 91
80int security_netif_sid(char *name, u32 *if_sid, 92int security_netif_sid(char *name, u32 *if_sid);
81 u32 *msg_sid);
82 93
83int security_node_sid(u16 domain, void *addr, u32 addrlen, 94int security_node_sid(u16 domain, void *addr, u32 addrlen,
84 u32 *out_sid); 95 u32 *out_sid);
@@ -88,10 +99,15 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
88 99
89int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); 100int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
90 101
102int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
103 u32 xfrm_sid,
104 u32 *peer_sid);
105
91int security_get_classes(char ***classes, int *nclasses); 106int security_get_classes(char ***classes, int *nclasses);
92int security_get_permissions(char *class, char ***perms, int *nperms); 107int security_get_permissions(char *class, char ***perms, int *nperms);
93int security_get_reject_unknown(void); 108int security_get_reject_unknown(void);
94int security_get_allow_unknown(void); 109int security_get_allow_unknown(void);
110int security_get_policycaps(int *len, int **values);
95 111
96#define SECURITY_FS_USE_XATTR 1 /* use xattr */ 112#define SECURITY_FS_USE_XATTR 1 /* use xattr */
97#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ 113#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
@@ -108,7 +124,6 @@ int security_genfs_sid(const char *fstype, char *name, u16 sclass,
108 124
109#ifdef CONFIG_NETLABEL 125#ifdef CONFIG_NETLABEL
110int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, 126int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
111 u32 base_sid,
112 u32 *sid); 127 u32 *sid);
113 128
114int security_netlbl_sid_to_secattr(u32 sid, 129int security_netlbl_sid_to_secattr(u32 sid,
@@ -116,7 +131,6 @@ int security_netlbl_sid_to_secattr(u32 sid,
116#else 131#else
117static inline int security_netlbl_secattr_to_sid( 132static inline int security_netlbl_secattr_to_sid(
118 struct netlbl_lsm_secattr *secattr, 133 struct netlbl_lsm_secattr *secattr,
119 u32 base_sid,
120 u32 *sid) 134 u32 *sid)
121{ 135{
122 return -EIDRM; 136 return -EIDRM;
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index 31929e39f5ca..36b0510efa7b 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -32,6 +32,13 @@ static inline struct inode_security_struct *get_sock_isec(struct sock *sk)
32} 32}
33 33
34#ifdef CONFIG_SECURITY_NETWORK_XFRM 34#ifdef CONFIG_SECURITY_NETWORK_XFRM
35extern atomic_t selinux_xfrm_refcount;
36
37static inline int selinux_xfrm_enabled(void)
38{
39 return (atomic_read(&selinux_xfrm_refcount) > 0);
40}
41
35int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, 42int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
36 struct avc_audit_data *ad); 43 struct avc_audit_data *ad);
37int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, 44int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
@@ -43,6 +50,11 @@ static inline void selinux_xfrm_notify_policyload(void)
43 atomic_inc(&flow_cache_genid); 50 atomic_inc(&flow_cache_genid);
44} 51}
45#else 52#else
53static inline int selinux_xfrm_enabled(void)
54{
55 return 0;
56}
57
46static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, 58static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
47 struct avc_audit_data *ad) 59 struct avc_audit_data *ad)
48{ 60{
diff --git a/security/selinux/netif.c b/security/selinux/netif.c
index e87ab948104c..013d3117a86b 100644
--- a/security/selinux/netif.c
+++ b/security/selinux/netif.c
@@ -7,6 +7,8 @@
7 * Author: James Morris <jmorris@redhat.com> 7 * Author: James Morris <jmorris@redhat.com>
8 * 8 *
9 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 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 * This program is free software; you can redistribute it and/or modify 13 * 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, 14 * it under the terms of the GNU General Public License version 2,
@@ -29,14 +31,6 @@
29#define SEL_NETIF_HASH_SIZE 64 31#define SEL_NETIF_HASH_SIZE 64
30#define SEL_NETIF_HASH_MAX 1024 32#define SEL_NETIF_HASH_MAX 1024
31 33
32#undef DEBUG
33
34#ifdef DEBUG
35#define DEBUGP printk
36#else
37#define DEBUGP(format, args...)
38#endif
39
40struct sel_netif 34struct sel_netif
41{ 35{
42 struct list_head list; 36 struct list_head list;
@@ -49,174 +43,226 @@ static LIST_HEAD(sel_netif_list);
49static DEFINE_SPINLOCK(sel_netif_lock); 43static DEFINE_SPINLOCK(sel_netif_lock);
50static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; 44static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
51 45
52static inline u32 sel_netif_hasfn(struct net_device *dev) 46/**
47 * sel_netif_hashfn - Hashing function for the interface table
48 * @ifindex: the network interface
49 *
50 * Description:
51 * This is the hashing function for the network interface table, it returns the
52 * bucket number for the given interface.
53 *
54 */
55static inline u32 sel_netif_hashfn(int ifindex)
53{ 56{
54 return (dev->ifindex & (SEL_NETIF_HASH_SIZE - 1)); 57 return (ifindex & (SEL_NETIF_HASH_SIZE - 1));
55} 58}
56 59
57/* 60/**
58 * All of the devices should normally fit in the hash, so we optimize 61 * sel_netif_find - Search for an interface record
59 * for that case. 62 * @ifindex: the network interface
63 *
64 * Description:
65 * Search the network interface table and return the record matching @ifindex.
66 * If an entry can not be found in the table return NULL.
67 *
60 */ 68 */
61static inline struct sel_netif *sel_netif_find(struct net_device *dev) 69static inline struct sel_netif *sel_netif_find(int ifindex)
62{ 70{
63 struct list_head *pos; 71 int idx = sel_netif_hashfn(ifindex);
64 int idx = sel_netif_hasfn(dev); 72 struct sel_netif *netif;
65 73
66 __list_for_each_rcu(pos, &sel_netif_hash[idx]) { 74 list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
67 struct sel_netif *netif = list_entry(pos, 75 /* all of the devices should normally fit in the hash, so we
68 struct sel_netif, list); 76 * optimize for that case */
69 if (likely(netif->nsec.dev == dev)) 77 if (likely(netif->nsec.ifindex == ifindex))
70 return netif; 78 return netif;
71 } 79
72 return NULL; 80 return NULL;
73} 81}
74 82
83/**
84 * sel_netif_insert - Insert a new interface into the table
85 * @netif: the new interface record
86 *
87 * Description:
88 * Add a new interface record to the network interface hash table. Returns
89 * zero on success, negative values on failure.
90 *
91 */
75static int sel_netif_insert(struct sel_netif *netif) 92static int sel_netif_insert(struct sel_netif *netif)
76{ 93{
77 int idx, ret = 0; 94 int idx;
78 95
79 if (sel_netif_total >= SEL_NETIF_HASH_MAX) { 96 if (sel_netif_total >= SEL_NETIF_HASH_MAX)
80 ret = -ENOSPC; 97 return -ENOSPC;
81 goto out;
82 }
83 98
84 idx = sel_netif_hasfn(netif->nsec.dev); 99 idx = sel_netif_hashfn(netif->nsec.ifindex);
85 list_add_rcu(&netif->list, &sel_netif_hash[idx]); 100 list_add_rcu(&netif->list, &sel_netif_hash[idx]);
86 sel_netif_total++; 101 sel_netif_total++;
87out: 102
88 return ret; 103 return 0;
89} 104}
90 105
106/**
107 * sel_netif_free - Frees an interface entry
108 * @p: the entry's RCU field
109 *
110 * Description:
111 * This function is designed to be used as a callback to the call_rcu()
112 * function so that memory allocated to a hash table interface entry can be
113 * released safely.
114 *
115 */
91static void sel_netif_free(struct rcu_head *p) 116static void sel_netif_free(struct rcu_head *p)
92{ 117{
93 struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head); 118 struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head);
94
95 DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name);
96 kfree(netif); 119 kfree(netif);
97} 120}
98 121
122/**
123 * sel_netif_destroy - Remove an interface record from the table
124 * @netif: the existing interface record
125 *
126 * Description:
127 * Remove an existing interface record from the network interface table.
128 *
129 */
99static void sel_netif_destroy(struct sel_netif *netif) 130static void sel_netif_destroy(struct sel_netif *netif)
100{ 131{
101 DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name);
102
103 list_del_rcu(&netif->list); 132 list_del_rcu(&netif->list);
104 sel_netif_total--; 133 sel_netif_total--;
105 call_rcu(&netif->rcu_head, sel_netif_free); 134 call_rcu(&netif->rcu_head, sel_netif_free);
106} 135}
107 136
108static struct sel_netif *sel_netif_lookup(struct net_device *dev) 137/**
138 * sel_netif_sid_slow - Lookup the SID of a network interface using the policy
139 * @ifindex: the network interface
140 * @sid: interface SID
141 *
142 * Description:
143 * This function determines the SID of a network interface by quering the
144 * security policy. The result is added to the network interface table to
145 * speedup future queries. Returns zero on success, negative values on
146 * failure.
147 *
148 */
149static int sel_netif_sid_slow(int ifindex, u32 *sid)
109{ 150{
110 int ret; 151 int ret;
111 struct sel_netif *netif, *new; 152 struct sel_netif *netif;
112 struct netif_security_struct *nsec; 153 struct sel_netif *new = NULL;
113 154 struct net_device *dev;
114 netif = sel_netif_find(dev); 155
115 if (likely(netif != NULL)) 156 /* NOTE: we always use init's network namespace since we don't
116 goto out; 157 * currently support containers */
117 158
118 new = kzalloc(sizeof(*new), GFP_ATOMIC); 159 dev = dev_get_by_index(&init_net, ifindex);
119 if (!new) { 160 if (unlikely(dev == NULL)) {
120 netif = ERR_PTR(-ENOMEM); 161 printk(KERN_WARNING
121 goto out; 162 "SELinux: failure in sel_netif_sid_slow(),"
163 " invalid network interface (%d)\n", ifindex);
164 return -ENOENT;
122 } 165 }
123
124 nsec = &new->nsec;
125 166
126 ret = security_netif_sid(dev->name, &nsec->if_sid, &nsec->msg_sid); 167 spin_lock_bh(&sel_netif_lock);
127 if (ret < 0) { 168 netif = sel_netif_find(ifindex);
128 kfree(new); 169 if (netif != NULL) {
129 netif = ERR_PTR(ret); 170 *sid = netif->nsec.sid;
171 ret = 0;
130 goto out; 172 goto out;
131 } 173 }
132 174 new = kzalloc(sizeof(*new), GFP_ATOMIC);
133 nsec->dev = dev; 175 if (new == NULL) {
134 176 ret = -ENOMEM;
135 spin_lock_bh(&sel_netif_lock);
136
137 netif = sel_netif_find(dev);
138 if (netif) {
139 spin_unlock_bh(&sel_netif_lock);
140 kfree(new);
141 goto out; 177 goto out;
142 } 178 }
143 179 ret = security_netif_sid(dev->name, &new->nsec.sid);
180 if (ret != 0)
181 goto out;
182 new->nsec.ifindex = ifindex;
144 ret = sel_netif_insert(new); 183 ret = sel_netif_insert(new);
145 spin_unlock_bh(&sel_netif_lock); 184 if (ret != 0)
146
147 if (ret) {
148 kfree(new);
149 netif = ERR_PTR(ret);
150 goto out; 185 goto out;
151 } 186 *sid = new->nsec.sid;
152 187
153 netif = new;
154
155 DEBUGP("new: ifindex=%u name=%s if_sid=%u msg_sid=%u\n", dev->ifindex, dev->name,
156 nsec->if_sid, nsec->msg_sid);
157out: 188out:
158 return netif; 189 spin_unlock_bh(&sel_netif_lock);
159} 190 dev_put(dev);
160 191 if (unlikely(ret)) {
161static void sel_netif_assign_sids(u32 if_sid_in, u32 msg_sid_in, u32 *if_sid_out, u32 *msg_sid_out) 192 printk(KERN_WARNING
162{ 193 "SELinux: failure in sel_netif_sid_slow(),"
163 if (if_sid_out) 194 " unable to determine network interface label (%d)\n",
164 *if_sid_out = if_sid_in; 195 ifindex);
165 if (msg_sid_out) 196 kfree(new);
166 *msg_sid_out = msg_sid_in; 197 }
167}
168
169static int sel_netif_sids_slow(struct net_device *dev, u32 *if_sid, u32 *msg_sid)
170{
171 int ret = 0;
172 u32 tmp_if_sid, tmp_msg_sid;
173
174 ret = security_netif_sid(dev->name, &tmp_if_sid, &tmp_msg_sid);
175 if (!ret)
176 sel_netif_assign_sids(tmp_if_sid, tmp_msg_sid, if_sid, msg_sid);
177 return ret; 198 return ret;
178} 199}
179 200
180int sel_netif_sids(struct net_device *dev, u32 *if_sid, u32 *msg_sid) 201/**
202 * sel_netif_sid - Lookup the SID of a network interface
203 * @ifindex: the network interface
204 * @sid: interface SID
205 *
206 * Description:
207 * This function determines the SID of a network interface using the fastest
208 * method possible. First the interface table is queried, but if an entry
209 * can't be found then the policy is queried and the result is added to the
210 * table to speedup future queries. Returns zero on success, negative values
211 * on failure.
212 *
213 */
214int sel_netif_sid(int ifindex, u32 *sid)
181{ 215{
182 int ret = 0;
183 struct sel_netif *netif; 216 struct sel_netif *netif;
184 217
185 rcu_read_lock(); 218 rcu_read_lock();
186 netif = sel_netif_lookup(dev); 219 netif = sel_netif_find(ifindex);
187 if (IS_ERR(netif)) { 220 if (likely(netif != NULL)) {
221 *sid = netif->nsec.sid;
188 rcu_read_unlock(); 222 rcu_read_unlock();
189 ret = sel_netif_sids_slow(dev, if_sid, msg_sid); 223 return 0;
190 goto out;
191 } 224 }
192 sel_netif_assign_sids(netif->nsec.if_sid, netif->nsec.msg_sid, if_sid, msg_sid);
193 rcu_read_unlock(); 225 rcu_read_unlock();
194out: 226
195 return ret; 227 return sel_netif_sid_slow(ifindex, sid);
196} 228}
197 229
198static void sel_netif_kill(struct net_device *dev) 230/**
231 * sel_netif_kill - Remove an entry from the network interface table
232 * @ifindex: the network interface
233 *
234 * Description:
235 * This function removes the entry matching @ifindex from the network interface
236 * table if it exists.
237 *
238 */
239static void sel_netif_kill(int ifindex)
199{ 240{
200 struct sel_netif *netif; 241 struct sel_netif *netif;
201 242
202 spin_lock_bh(&sel_netif_lock); 243 spin_lock_bh(&sel_netif_lock);
203 netif = sel_netif_find(dev); 244 netif = sel_netif_find(ifindex);
204 if (netif) 245 if (netif)
205 sel_netif_destroy(netif); 246 sel_netif_destroy(netif);
206 spin_unlock_bh(&sel_netif_lock); 247 spin_unlock_bh(&sel_netif_lock);
207} 248}
208 249
250/**
251 * sel_netif_flush - Flush the entire network interface table
252 *
253 * Description:
254 * Remove all entries from the network interface table.
255 *
256 */
209static void sel_netif_flush(void) 257static void sel_netif_flush(void)
210{ 258{
211 int idx; 259 int idx;
260 struct sel_netif *netif;
212 261
213 spin_lock_bh(&sel_netif_lock); 262 spin_lock_bh(&sel_netif_lock);
214 for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) { 263 for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++)
215 struct sel_netif *netif;
216
217 list_for_each_entry(netif, &sel_netif_hash[idx], list) 264 list_for_each_entry(netif, &sel_netif_hash[idx], list)
218 sel_netif_destroy(netif); 265 sel_netif_destroy(netif);
219 }
220 spin_unlock_bh(&sel_netif_lock); 266 spin_unlock_bh(&sel_netif_lock);
221} 267}
222 268
@@ -239,7 +285,7 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
239 return NOTIFY_DONE; 285 return NOTIFY_DONE;
240 286
241 if (event == NETDEV_DOWN) 287 if (event == NETDEV_DOWN)
242 sel_netif_kill(dev); 288 sel_netif_kill(dev->ifindex);
243 289
244 return NOTIFY_DONE; 290 return NOTIFY_DONE;
245} 291}
@@ -250,10 +296,10 @@ static struct notifier_block sel_netif_netdev_notifier = {
250 296
251static __init int sel_netif_init(void) 297static __init int sel_netif_init(void)
252{ 298{
253 int i, err = 0; 299 int i, err;
254 300
255 if (!selinux_enabled) 301 if (!selinux_enabled)
256 goto out; 302 return 0;
257 303
258 for (i = 0; i < SEL_NETIF_HASH_SIZE; i++) 304 for (i = 0; i < SEL_NETIF_HASH_SIZE; i++)
259 INIT_LIST_HEAD(&sel_netif_hash[i]); 305 INIT_LIST_HEAD(&sel_netif_hash[i]);
@@ -265,7 +311,6 @@ static __init int sel_netif_init(void)
265 if (err) 311 if (err)
266 panic("avc_add_callback() failed, error %d\n", err); 312 panic("avc_add_callback() failed, error %d\n", err);
267 313
268out:
269 return err; 314 return err;
270} 315}
271 316
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 66e013d6f6f6..0fa2be4149e8 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -36,6 +36,33 @@
36#include "security.h" 36#include "security.h"
37 37
38/** 38/**
39 * selinux_netlbl_sidlookup_cached - Cache a SID lookup
40 * @skb: the packet
41 * @secattr: the NetLabel security attributes
42 * @sid: the SID
43 *
44 * Description:
45 * Query the SELinux security server to lookup the correct SID for the given
46 * security attributes. If the query is successful, cache the result to speed
47 * up future lookups. Returns zero on success, negative values on failure.
48 *
49 */
50static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
51 struct netlbl_lsm_secattr *secattr,
52 u32 *sid)
53{
54 int rc;
55
56 rc = security_netlbl_secattr_to_sid(secattr, sid);
57 if (rc == 0 &&
58 (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
59 (secattr->flags & NETLBL_SECATTR_CACHE))
60 netlbl_cache_add(skb, secattr);
61
62 return rc;
63}
64
65/**
39 * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism 66 * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
40 * @sk: the socket to label 67 * @sk: the socket to label
41 * @sid: the SID to use 68 * @sid: the SID to use
@@ -137,14 +164,14 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
137 * lock as other threads could have access to ssec */ 164 * lock as other threads could have access to ssec */
138 rcu_read_lock(); 165 rcu_read_lock();
139 selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family); 166 selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
140 newssec->sclass = ssec->sclass;
141 rcu_read_unlock(); 167 rcu_read_unlock();
142} 168}
143 169
144/** 170/**
145 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel 171 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
146 * @skb: the packet 172 * @skb: the packet
147 * @base_sid: the SELinux SID to use as a context for MLS only attributes 173 * @family: protocol family
174 * @type: NetLabel labeling protocol type
148 * @sid: the SID 175 * @sid: the SID
149 * 176 *
150 * Description: 177 * Description:
@@ -153,7 +180,10 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
153 * assign to the packet. Returns zero on success, negative values on failure. 180 * assign to the packet. Returns zero on success, negative values on failure.
154 * 181 *
155 */ 182 */
156int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid) 183int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
184 u16 family,
185 u32 *type,
186 u32 *sid)
157{ 187{
158 int rc; 188 int rc;
159 struct netlbl_lsm_secattr secattr; 189 struct netlbl_lsm_secattr secattr;
@@ -164,15 +194,12 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid)
164 } 194 }
165 195
166 netlbl_secattr_init(&secattr); 196 netlbl_secattr_init(&secattr);
167 rc = netlbl_skbuff_getattr(skb, &secattr); 197 rc = netlbl_skbuff_getattr(skb, family, &secattr);
168 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) { 198 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
169 rc = security_netlbl_secattr_to_sid(&secattr, base_sid, sid); 199 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid);
170 if (rc == 0 && 200 else
171 (secattr.flags & NETLBL_SECATTR_CACHEABLE) &&
172 (secattr.flags & NETLBL_SECATTR_CACHE))
173 netlbl_cache_add(skb, &secattr);
174 } else
175 *sid = SECSID_NULL; 201 *sid = SECSID_NULL;
202 *type = secattr.type;
176 netlbl_secattr_destroy(&secattr); 203 netlbl_secattr_destroy(&secattr);
177 204
178 return rc; 205 return rc;
@@ -190,13 +217,10 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid)
190 */ 217 */
191void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) 218void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
192{ 219{
193 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
194 struct sk_security_struct *sksec = sk->sk_security; 220 struct sk_security_struct *sksec = sk->sk_security;
195 struct netlbl_lsm_secattr secattr; 221 struct netlbl_lsm_secattr secattr;
196 u32 nlbl_peer_sid; 222 u32 nlbl_peer_sid;
197 223
198 sksec->sclass = isec->sclass;
199
200 rcu_read_lock(); 224 rcu_read_lock();
201 225
202 if (sksec->nlbl_state != NLBL_REQUIRE) { 226 if (sksec->nlbl_state != NLBL_REQUIRE) {
@@ -207,9 +231,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
207 netlbl_secattr_init(&secattr); 231 netlbl_secattr_init(&secattr);
208 if (netlbl_sock_getattr(sk, &secattr) == 0 && 232 if (netlbl_sock_getattr(sk, &secattr) == 0 &&
209 secattr.flags != NETLBL_SECATTR_NONE && 233 secattr.flags != NETLBL_SECATTR_NONE &&
210 security_netlbl_secattr_to_sid(&secattr, 234 security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0)
211 SECINITSID_NETMSG,
212 &nlbl_peer_sid) == 0)
213 sksec->peer_sid = nlbl_peer_sid; 235 sksec->peer_sid = nlbl_peer_sid;
214 netlbl_secattr_destroy(&secattr); 236 netlbl_secattr_destroy(&secattr);
215 237
@@ -234,11 +256,8 @@ int selinux_netlbl_socket_post_create(struct socket *sock)
234{ 256{
235 int rc = 0; 257 int rc = 0;
236 struct sock *sk = sock->sk; 258 struct sock *sk = sock->sk;
237 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
238 struct sk_security_struct *sksec = sk->sk_security; 259 struct sk_security_struct *sksec = sk->sk_security;
239 260
240 sksec->sclass = isec->sclass;
241
242 rcu_read_lock(); 261 rcu_read_lock();
243 if (sksec->nlbl_state == NLBL_REQUIRE) 262 if (sksec->nlbl_state == NLBL_REQUIRE)
244 rc = selinux_netlbl_sock_setsid(sk, sksec->sid); 263 rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
@@ -292,6 +311,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
292 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel 311 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
293 * @sksec: the sock's sk_security_struct 312 * @sksec: the sock's sk_security_struct
294 * @skb: the packet 313 * @skb: the packet
314 * @family: protocol family
295 * @ad: the audit data 315 * @ad: the audit data
296 * 316 *
297 * Description: 317 * Description:
@@ -302,6 +322,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
302 */ 322 */
303int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 323int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
304 struct sk_buff *skb, 324 struct sk_buff *skb,
325 u16 family,
305 struct avc_audit_data *ad) 326 struct avc_audit_data *ad)
306{ 327{
307 int rc; 328 int rc;
@@ -313,16 +334,10 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
313 return 0; 334 return 0;
314 335
315 netlbl_secattr_init(&secattr); 336 netlbl_secattr_init(&secattr);
316 rc = netlbl_skbuff_getattr(skb, &secattr); 337 rc = netlbl_skbuff_getattr(skb, family, &secattr);
317 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) { 338 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
318 rc = security_netlbl_secattr_to_sid(&secattr, 339 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid);
319 SECINITSID_NETMSG, 340 else
320 &nlbl_sid);
321 if (rc == 0 &&
322 (secattr.flags & NETLBL_SECATTR_CACHEABLE) &&
323 (secattr.flags & NETLBL_SECATTR_CACHE))
324 netlbl_cache_add(skb, &secattr);
325 } else
326 nlbl_sid = SECINITSID_UNLABELED; 341 nlbl_sid = SECINITSID_UNLABELED;
327 netlbl_secattr_destroy(&secattr); 342 netlbl_secattr_destroy(&secattr);
328 if (rc != 0) 343 if (rc != 0)
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
new file mode 100644
index 000000000000..f3c526f2cacb
--- /dev/null
+++ b/security/selinux/netnode.c
@@ -0,0 +1,354 @@
1/*
2 * Network node table
3 *
4 * SELinux must keep a mapping of network nodes to labels/SIDs. This
5 * mapping is maintained as part of the normal policy but a fast cache is
6 * needed to reduce the lookup overhead since most of these queries happen on
7 * a per-packet basis.
8 *
9 * Author: Paul Moore <paul.moore@hp.com>
10 *
11 * This code is heavily based on the "netif" concept originally developed by
12 * James Morris <jmorris@redhat.com>
13 * (see security/selinux/netif.c for more information)
14 *
15 */
16
17/*
18 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
19 *
20 * This program is free software: you can redistribute it and/or modify
21 * it under the terms of version 2 of the GNU General Public License as
22 * published by the Free Software Foundation.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 */
30
31#include <linux/types.h>
32#include <linux/rcupdate.h>
33#include <linux/list.h>
34#include <linux/spinlock.h>
35#include <linux/in.h>
36#include <linux/in6.h>
37#include <linux/ip.h>
38#include <linux/ipv6.h>
39#include <net/ip.h>
40#include <net/ipv6.h>
41#include <asm/bug.h>
42
43#include "objsec.h"
44
45#define SEL_NETNODE_HASH_SIZE 256
46#define SEL_NETNODE_HASH_BKT_LIMIT 16
47
48struct sel_netnode {
49 struct netnode_security_struct nsec;
50
51 struct list_head list;
52 struct rcu_head rcu;
53};
54
55/* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason
56 * for this is that I suspect most users will not make heavy use of both
57 * address families at the same time so one table will usually end up wasted,
58 * if this becomes a problem we can always add a hash table for each address
59 * family later */
60
61static LIST_HEAD(sel_netnode_list);
62static DEFINE_SPINLOCK(sel_netnode_lock);
63static struct list_head sel_netnode_hash[SEL_NETNODE_HASH_SIZE];
64
65/**
66 * sel_netnode_free - Frees a node entry
67 * @p: the entry's RCU field
68 *
69 * Description:
70 * This function is designed to be used as a callback to the call_rcu()
71 * function so that memory allocated to a hash table node entry can be
72 * released safely.
73 *
74 */
75static void sel_netnode_free(struct rcu_head *p)
76{
77 struct sel_netnode *node = container_of(p, struct sel_netnode, rcu);
78 kfree(node);
79}
80
81/**
82 * sel_netnode_hashfn_ipv4 - IPv4 hashing function for the node table
83 * @addr: IPv4 address
84 *
85 * Description:
86 * This is the IPv4 hashing function for the node interface table, it returns
87 * the bucket number for the given IP address.
88 *
89 */
90static u32 sel_netnode_hashfn_ipv4(__be32 addr)
91{
92 /* at some point we should determine if the mismatch in byte order
93 * affects the hash function dramatically */
94 return (addr & (SEL_NETNODE_HASH_SIZE - 1));
95}
96
97/**
98 * sel_netnode_hashfn_ipv6 - IPv6 hashing function for the node table
99 * @addr: IPv6 address
100 *
101 * Description:
102 * This is the IPv6 hashing function for the node interface table, it returns
103 * the bucket number for the given IP address.
104 *
105 */
106static u32 sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
107{
108 /* just hash the least significant 32 bits to keep things fast (they
109 * are the most likely to be different anyway), we can revisit this
110 * later if needed */
111 return (addr->s6_addr32[3] & (SEL_NETNODE_HASH_SIZE - 1));
112}
113
114/**
115 * sel_netnode_find - Search for a node record
116 * @addr: IP address
117 * @family: address family
118 *
119 * Description:
120 * Search the network node table and return the record matching @addr. If an
121 * entry can not be found in the table return NULL.
122 *
123 */
124static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
125{
126 u32 idx;
127 struct sel_netnode *node;
128
129 switch (family) {
130 case PF_INET:
131 idx = sel_netnode_hashfn_ipv4(*(__be32 *)addr);
132 break;
133 case PF_INET6:
134 idx = sel_netnode_hashfn_ipv6(addr);
135 break;
136 default:
137 BUG();
138 }
139
140 list_for_each_entry_rcu(node, &sel_netnode_hash[idx], list)
141 if (node->nsec.family == family)
142 switch (family) {
143 case PF_INET:
144 if (node->nsec.addr.ipv4 == *(__be32 *)addr)
145 return node;
146 break;
147 case PF_INET6:
148 if (ipv6_addr_equal(&node->nsec.addr.ipv6,
149 addr))
150 return node;
151 break;
152 }
153
154 return NULL;
155}
156
157/**
158 * sel_netnode_insert - Insert a new node into the table
159 * @node: the new node record
160 *
161 * Description:
162 * Add a new node record to the network address hash table. Returns zero on
163 * success, negative values on failure.
164 *
165 */
166static int sel_netnode_insert(struct sel_netnode *node)
167{
168 u32 idx;
169 u32 count = 0;
170 struct sel_netnode *iter;
171
172 switch (node->nsec.family) {
173 case PF_INET:
174 idx = sel_netnode_hashfn_ipv4(node->nsec.addr.ipv4);
175 break;
176 case PF_INET6:
177 idx = sel_netnode_hashfn_ipv6(&node->nsec.addr.ipv6);
178 break;
179 default:
180 BUG();
181 }
182 list_add_rcu(&node->list, &sel_netnode_hash[idx]);
183
184 /* we need to impose a limit on the growth of the hash table so check
185 * this bucket to make sure it is within the specified bounds */
186 list_for_each_entry(iter, &sel_netnode_hash[idx], list)
187 if (++count > SEL_NETNODE_HASH_BKT_LIMIT) {
188 list_del_rcu(&iter->list);
189 call_rcu(&iter->rcu, sel_netnode_free);
190 break;
191 }
192
193 return 0;
194}
195
196/**
197 * sel_netnode_destroy - Remove a node record from the table
198 * @node: the existing node record
199 *
200 * Description:
201 * Remove an existing node record from the network address table.
202 *
203 */
204static void sel_netnode_destroy(struct sel_netnode *node)
205{
206 list_del_rcu(&node->list);
207 call_rcu(&node->rcu, sel_netnode_free);
208}
209
210/**
211 * sel_netnode_sid_slow - Lookup the SID of a network address using the policy
212 * @addr: the IP address
213 * @family: the address family
214 * @sid: node SID
215 *
216 * Description:
217 * This function determines the SID of a network address by quering the
218 * security policy. The result is added to the network address table to
219 * speedup future queries. Returns zero on success, negative values on
220 * failure.
221 *
222 */
223static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
224{
225 int ret;
226 struct sel_netnode *node;
227 struct sel_netnode *new = NULL;
228
229 spin_lock_bh(&sel_netnode_lock);
230 node = sel_netnode_find(addr, family);
231 if (node != NULL) {
232 *sid = node->nsec.sid;
233 ret = 0;
234 goto out;
235 }
236 new = kzalloc(sizeof(*new), GFP_ATOMIC);
237 if (new == NULL) {
238 ret = -ENOMEM;
239 goto out;
240 }
241 switch (family) {
242 case PF_INET:
243 ret = security_node_sid(PF_INET,
244 addr, sizeof(struct in_addr),
245 &new->nsec.sid);
246 new->nsec.addr.ipv4 = *(__be32 *)addr;
247 break;
248 case PF_INET6:
249 ret = security_node_sid(PF_INET6,
250 addr, sizeof(struct in6_addr),
251 &new->nsec.sid);
252 ipv6_addr_copy(&new->nsec.addr.ipv6, addr);
253 break;
254 default:
255 BUG();
256 }
257 if (ret != 0)
258 goto out;
259 new->nsec.family = family;
260 ret = sel_netnode_insert(new);
261 if (ret != 0)
262 goto out;
263 *sid = new->nsec.sid;
264
265out:
266 spin_unlock_bh(&sel_netnode_lock);
267 if (unlikely(ret)) {
268 printk(KERN_WARNING
269 "SELinux: failure in sel_netnode_sid_slow(),"
270 " unable to determine network node label\n");
271 kfree(new);
272 }
273 return ret;
274}
275
276/**
277 * sel_netnode_sid - Lookup the SID of a network address
278 * @addr: the IP address
279 * @family: the address family
280 * @sid: node SID
281 *
282 * Description:
283 * This function determines the SID of a network address using the fastest
284 * method possible. First the address table is queried, but if an entry
285 * can't be found then the policy is queried and the result is added to the
286 * table to speedup future queries. Returns zero on success, negative values
287 * on failure.
288 *
289 */
290int sel_netnode_sid(void *addr, u16 family, u32 *sid)
291{
292 struct sel_netnode *node;
293
294 rcu_read_lock();
295 node = sel_netnode_find(addr, family);
296 if (node != NULL) {
297 *sid = node->nsec.sid;
298 rcu_read_unlock();
299 return 0;
300 }
301 rcu_read_unlock();
302
303 return sel_netnode_sid_slow(addr, family, sid);
304}
305
306/**
307 * sel_netnode_flush - Flush the entire network address table
308 *
309 * Description:
310 * Remove all entries from the network address table.
311 *
312 */
313static void sel_netnode_flush(void)
314{
315 u32 idx;
316 struct sel_netnode *node;
317
318 spin_lock_bh(&sel_netnode_lock);
319 for (idx = 0; idx < SEL_NETNODE_HASH_SIZE; idx++)
320 list_for_each_entry(node, &sel_netnode_hash[idx], list)
321 sel_netnode_destroy(node);
322 spin_unlock_bh(&sel_netnode_lock);
323}
324
325static int sel_netnode_avc_callback(u32 event, u32 ssid, u32 tsid,
326 u16 class, u32 perms, u32 *retained)
327{
328 if (event == AVC_CALLBACK_RESET) {
329 sel_netnode_flush();
330 synchronize_net();
331 }
332 return 0;
333}
334
335static __init int sel_netnode_init(void)
336{
337 int iter;
338 int ret;
339
340 if (!selinux_enabled)
341 return 0;
342
343 for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++)
344 INIT_LIST_HEAD(&sel_netnode_hash[iter]);
345
346 ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET,
347 SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
348 if (ret != 0)
349 panic("avc_add_callback() failed, error %d\n", ret);
350
351 return ret;
352}
353
354__initcall(sel_netnode_init);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 397fd4955fe1..a85740530afc 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -2,6 +2,11 @@
2 * 2 *
3 * Added conditional policy language extensions 3 * Added conditional policy language extensions
4 * 4 *
5 * Updated: Hewlett-Packard <paul.moore@hp.com>
6 *
7 * Added support for the policy capability bitmap
8 *
9 * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
5 * Copyright (C) 2003 - 2004 Tresys Technology, LLC 10 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
6 * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> 11 * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
7 * This program is free software; you can redistribute it and/or modify 12 * This program is free software; you can redistribute it and/or modify
@@ -35,6 +40,11 @@
35#include "objsec.h" 40#include "objsec.h"
36#include "conditional.h" 41#include "conditional.h"
37 42
43/* Policy capability filenames */
44static char *policycap_names[] = {
45 "network_peer_controls"
46};
47
38unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; 48unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
39 49
40#ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT 50#ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
@@ -72,6 +82,9 @@ static int *bool_pending_values = NULL;
72static struct dentry *class_dir = NULL; 82static struct dentry *class_dir = NULL;
73static unsigned long last_class_ino; 83static unsigned long last_class_ino;
74 84
85/* global data for policy capabilities */
86static struct dentry *policycap_dir = NULL;
87
75extern void selnl_notify_setenforce(int val); 88extern void selnl_notify_setenforce(int val);
76 89
77/* Check whether a task is allowed to use a security operation. */ 90/* Check whether a task is allowed to use a security operation. */
@@ -111,10 +124,11 @@ enum sel_inos {
111 124
112static unsigned long sel_last_ino = SEL_INO_NEXT - 1; 125static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
113 126
114#define SEL_INITCON_INO_OFFSET 0x01000000 127#define SEL_INITCON_INO_OFFSET 0x01000000
115#define SEL_BOOL_INO_OFFSET 0x02000000 128#define SEL_BOOL_INO_OFFSET 0x02000000
116#define SEL_CLASS_INO_OFFSET 0x04000000 129#define SEL_CLASS_INO_OFFSET 0x04000000
117#define SEL_INO_MASK 0x00ffffff 130#define SEL_POLICYCAP_INO_OFFSET 0x08000000
131#define SEL_INO_MASK 0x00ffffff
118 132
119#define TMPBUFLEN 12 133#define TMPBUFLEN 12
120static ssize_t sel_read_enforce(struct file *filp, char __user *buf, 134static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
@@ -263,6 +277,7 @@ static const struct file_operations sel_policyvers_ops = {
263/* declaration for sel_write_load */ 277/* declaration for sel_write_load */
264static int sel_make_bools(void); 278static int sel_make_bools(void);
265static int sel_make_classes(void); 279static int sel_make_classes(void);
280static int sel_make_policycap(void);
266 281
267/* declaration for sel_make_class_dirs */ 282/* declaration for sel_make_class_dirs */
268static int sel_make_dir(struct inode *dir, struct dentry *dentry, 283static int sel_make_dir(struct inode *dir, struct dentry *dentry,
@@ -323,6 +338,12 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf,
323 } 338 }
324 339
325 ret = sel_make_classes(); 340 ret = sel_make_classes();
341 if (ret) {
342 length = ret;
343 goto out1;
344 }
345
346 ret = sel_make_policycap();
326 if (ret) 347 if (ret)
327 length = ret; 348 length = ret;
328 else 349 else
@@ -1399,6 +1420,24 @@ static const struct file_operations sel_perm_ops = {
1399 .read = sel_read_perm, 1420 .read = sel_read_perm,
1400}; 1421};
1401 1422
1423static ssize_t sel_read_policycap(struct file *file, char __user *buf,
1424 size_t count, loff_t *ppos)
1425{
1426 int value;
1427 char tmpbuf[TMPBUFLEN];
1428 ssize_t length;
1429 unsigned long i_ino = file->f_path.dentry->d_inode->i_ino;
1430
1431 value = security_policycap_supported(i_ino & SEL_INO_MASK);
1432 length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
1433
1434 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
1435}
1436
1437static const struct file_operations sel_policycap_ops = {
1438 .read = sel_read_policycap,
1439};
1440
1402static int sel_make_perm_files(char *objclass, int classvalue, 1441static int sel_make_perm_files(char *objclass, int classvalue,
1403 struct dentry *dir) 1442 struct dentry *dir)
1404{ 1443{
@@ -1545,6 +1584,36 @@ out:
1545 return rc; 1584 return rc;
1546} 1585}
1547 1586
1587static int sel_make_policycap(void)
1588{
1589 unsigned int iter;
1590 struct dentry *dentry = NULL;
1591 struct inode *inode = NULL;
1592
1593 sel_remove_entries(policycap_dir);
1594
1595 for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
1596 if (iter < ARRAY_SIZE(policycap_names))
1597 dentry = d_alloc_name(policycap_dir,
1598 policycap_names[iter]);
1599 else
1600 dentry = d_alloc_name(policycap_dir, "unknown");
1601
1602 if (dentry == NULL)
1603 return -ENOMEM;
1604
1605 inode = sel_make_inode(policycap_dir->d_sb, S_IFREG | S_IRUGO);
1606 if (inode == NULL)
1607 return -ENOMEM;
1608
1609 inode->i_fop = &sel_policycap_ops;
1610 inode->i_ino = iter | SEL_POLICYCAP_INO_OFFSET;
1611 d_add(dentry, inode);
1612 }
1613
1614 return 0;
1615}
1616
1548static int sel_make_dir(struct inode *dir, struct dentry *dentry, 1617static int sel_make_dir(struct inode *dir, struct dentry *dentry,
1549 unsigned long *ino) 1618 unsigned long *ino)
1550{ 1619{
@@ -1673,6 +1742,18 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
1673 1742
1674 class_dir = dentry; 1743 class_dir = dentry;
1675 1744
1745 dentry = d_alloc_name(sb->s_root, "policy_capabilities");
1746 if (!dentry) {
1747 ret = -ENOMEM;
1748 goto err;
1749 }
1750
1751 ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
1752 if (ret)
1753 goto err;
1754
1755 policycap_dir = dentry;
1756
1676out: 1757out:
1677 return ret; 1758 return ret;
1678err: 1759err:
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 3bbcb5369af9..feaf0a5b828f 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -562,7 +562,7 @@ void mls_export_netlbl_lvl(struct context *context,
562 if (!selinux_mls_enabled) 562 if (!selinux_mls_enabled)
563 return; 563 return;
564 564
565 secattr->mls_lvl = context->range.level[0].sens - 1; 565 secattr->attr.mls.lvl = context->range.level[0].sens - 1;
566 secattr->flags |= NETLBL_SECATTR_MLS_LVL; 566 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
567} 567}
568 568
@@ -582,7 +582,7 @@ void mls_import_netlbl_lvl(struct context *context,
582 if (!selinux_mls_enabled) 582 if (!selinux_mls_enabled)
583 return; 583 return;
584 584
585 context->range.level[0].sens = secattr->mls_lvl + 1; 585 context->range.level[0].sens = secattr->attr.mls.lvl + 1;
586 context->range.level[1].sens = context->range.level[0].sens; 586 context->range.level[1].sens = context->range.level[0].sens;
587} 587}
588 588
@@ -605,8 +605,8 @@ int mls_export_netlbl_cat(struct context *context,
605 return 0; 605 return 0;
606 606
607 rc = ebitmap_netlbl_export(&context->range.level[0].cat, 607 rc = ebitmap_netlbl_export(&context->range.level[0].cat,
608 &secattr->mls_cat); 608 &secattr->attr.mls.cat);
609 if (rc == 0 && secattr->mls_cat != NULL) 609 if (rc == 0 && secattr->attr.mls.cat != NULL)
610 secattr->flags |= NETLBL_SECATTR_MLS_CAT; 610 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
611 611
612 return rc; 612 return rc;
@@ -633,7 +633,7 @@ int mls_import_netlbl_cat(struct context *context,
633 return 0; 633 return 0;
634 634
635 rc = ebitmap_netlbl_import(&context->range.level[0].cat, 635 rc = ebitmap_netlbl_import(&context->range.level[0].cat,
636 secattr->mls_cat); 636 secattr->attr.mls.cat);
637 if (rc != 0) 637 if (rc != 0)
638 goto import_netlbl_cat_failure; 638 goto import_netlbl_cat_failure;
639 639
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index b582aae3c62c..bd7d6a00342d 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -13,6 +13,11 @@
13 * 13 *
14 * Added conditional policy language extensions 14 * Added conditional policy language extensions
15 * 15 *
16 * Updated: Hewlett-Packard <paul.moore@hp.com>
17 *
18 * Added support for the policy capability bitmap
19 *
20 * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
16 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. 21 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
17 * Copyright (C) 2003 - 2004 Tresys Technology, LLC 22 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
18 * This program is free software; you can redistribute it and/or modify 23 * This program is free software; you can redistribute it and/or modify
@@ -102,6 +107,11 @@ static struct policydb_compat_info policydb_compat[] = {
102 .sym_num = SYM_NUM, 107 .sym_num = SYM_NUM,
103 .ocon_num = OCON_NUM, 108 .ocon_num = OCON_NUM,
104 }, 109 },
110 {
111 .version = POLICYDB_VERSION_POLCAP,
112 .sym_num = SYM_NUM,
113 .ocon_num = OCON_NUM,
114 }
105}; 115};
106 116
107static struct policydb_compat_info *policydb_lookup_compat(int version) 117static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -183,6 +193,8 @@ static int policydb_init(struct policydb *p)
183 if (rc) 193 if (rc)
184 goto out_free_symtab; 194 goto out_free_symtab;
185 195
196 ebitmap_init(&p->policycaps);
197
186out: 198out:
187 return rc; 199 return rc;
188 200
@@ -673,8 +685,8 @@ void policydb_destroy(struct policydb *p)
673 ebitmap_destroy(&p->type_attr_map[i]); 685 ebitmap_destroy(&p->type_attr_map[i]);
674 } 686 }
675 kfree(p->type_attr_map); 687 kfree(p->type_attr_map);
676
677 kfree(p->undefined_perms); 688 kfree(p->undefined_perms);
689 ebitmap_destroy(&p->policycaps);
678 690
679 return; 691 return;
680} 692}
@@ -1554,6 +1566,10 @@ int policydb_read(struct policydb *p, void *fp)
1554 p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); 1566 p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
1555 p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); 1567 p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
1556 1568
1569 if (p->policyvers >= POLICYDB_VERSION_POLCAP &&
1570 ebitmap_read(&p->policycaps, fp) != 0)
1571 goto bad;
1572
1557 info = policydb_lookup_compat(p->policyvers); 1573 info = policydb_lookup_compat(p->policyvers);
1558 if (!info) { 1574 if (!info) {
1559 printk(KERN_ERR "security: unable to find policy compat info " 1575 printk(KERN_ERR "security: unable to find policy compat info "
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index ed6fc687c66f..c4ce996e202c 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -241,6 +241,8 @@ struct policydb {
241 /* type -> attribute reverse mapping */ 241 /* type -> attribute reverse mapping */
242 struct ebitmap *type_attr_map; 242 struct ebitmap *type_attr_map;
243 243
244 struct ebitmap policycaps;
245
244 unsigned int policyvers; 246 unsigned int policyvers;
245 247
246 unsigned int reject_unknown : 1; 248 unsigned int reject_unknown : 1;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 4bf715d4cf29..f96dec1f9258 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -16,12 +16,13 @@
16 * Updated: Hewlett-Packard <paul.moore@hp.com> 16 * Updated: Hewlett-Packard <paul.moore@hp.com>
17 * 17 *
18 * Added support for NetLabel 18 * Added support for NetLabel
19 * Added support for the policy capability bitmap
19 * 20 *
20 * Updated: Chad Sellers <csellers@tresys.com> 21 * Updated: Chad Sellers <csellers@tresys.com>
21 * 22 *
22 * Added validation of kernel classes and permissions 23 * Added validation of kernel classes and permissions
23 * 24 *
24 * Copyright (C) 2006 Hewlett-Packard Development Company, L.P. 25 * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
25 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 26 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
26 * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC 27 * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
27 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 28 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
@@ -59,6 +60,8 @@
59extern void selnl_notify_policyload(u32 seqno); 60extern void selnl_notify_policyload(u32 seqno);
60unsigned int policydb_loaded_version; 61unsigned int policydb_loaded_version;
61 62
63int selinux_policycap_netpeer;
64
62/* 65/*
63 * This is declared in avc.c 66 * This is declared in avc.c
64 */ 67 */
@@ -1299,6 +1302,12 @@ bad:
1299 goto out; 1302 goto out;
1300} 1303}
1301 1304
1305static void security_load_policycaps(void)
1306{
1307 selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps,
1308 POLICYDB_CAPABILITY_NETPEER);
1309}
1310
1302extern void selinux_complete_init(void); 1311extern void selinux_complete_init(void);
1303static int security_preserve_bools(struct policydb *p); 1312static int security_preserve_bools(struct policydb *p);
1304 1313
@@ -1346,6 +1355,7 @@ int security_load_policy(void *data, size_t len)
1346 avtab_cache_destroy(); 1355 avtab_cache_destroy();
1347 return -EINVAL; 1356 return -EINVAL;
1348 } 1357 }
1358 security_load_policycaps();
1349 policydb_loaded_version = policydb.policyvers; 1359 policydb_loaded_version = policydb.policyvers;
1350 ss_initialized = 1; 1360 ss_initialized = 1;
1351 seqno = ++latest_granting; 1361 seqno = ++latest_granting;
@@ -1404,6 +1414,7 @@ int security_load_policy(void *data, size_t len)
1404 POLICY_WRLOCK; 1414 POLICY_WRLOCK;
1405 memcpy(&policydb, &newpolicydb, sizeof policydb); 1415 memcpy(&policydb, &newpolicydb, sizeof policydb);
1406 sidtab_set(&sidtab, &newsidtab); 1416 sidtab_set(&sidtab, &newsidtab);
1417 security_load_policycaps();
1407 seqno = ++latest_granting; 1418 seqno = ++latest_granting;
1408 policydb_loaded_version = policydb.policyvers; 1419 policydb_loaded_version = policydb.policyvers;
1409 POLICY_WRUNLOCK; 1420 POLICY_WRUNLOCK;
@@ -1478,11 +1489,8 @@ out:
1478 * security_netif_sid - Obtain the SID for a network interface. 1489 * security_netif_sid - Obtain the SID for a network interface.
1479 * @name: interface name 1490 * @name: interface name
1480 * @if_sid: interface SID 1491 * @if_sid: interface SID
1481 * @msg_sid: default SID for received packets
1482 */ 1492 */
1483int security_netif_sid(char *name, 1493int security_netif_sid(char *name, u32 *if_sid)
1484 u32 *if_sid,
1485 u32 *msg_sid)
1486{ 1494{
1487 int rc = 0; 1495 int rc = 0;
1488 struct ocontext *c; 1496 struct ocontext *c;
@@ -1510,11 +1518,8 @@ int security_netif_sid(char *name,
1510 goto out; 1518 goto out;
1511 } 1519 }
1512 *if_sid = c->sid[0]; 1520 *if_sid = c->sid[0];
1513 *msg_sid = c->sid[1]; 1521 } else
1514 } else {
1515 *if_sid = SECINITSID_NETIF; 1522 *if_sid = SECINITSID_NETIF;
1516 *msg_sid = SECINITSID_NETMSG;
1517 }
1518 1523
1519out: 1524out:
1520 POLICY_RDUNLOCK; 1525 POLICY_RDUNLOCK;
@@ -2049,6 +2054,91 @@ out:
2049 return rc; 2054 return rc;
2050} 2055}
2051 2056
2057/**
2058 * security_net_peersid_resolve - Compare and resolve two network peer SIDs
2059 * @nlbl_sid: NetLabel SID
2060 * @nlbl_type: NetLabel labeling protocol type
2061 * @xfrm_sid: XFRM SID
2062 *
2063 * Description:
2064 * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
2065 * resolved into a single SID it is returned via @peer_sid and the function
2066 * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function
2067 * returns a negative value. A table summarizing the behavior is below:
2068 *
2069 * | function return | @sid
2070 * ------------------------------+-----------------+-----------------
2071 * no peer labels | 0 | SECSID_NULL
2072 * single peer label | 0 | <peer_label>
2073 * multiple, consistent labels | 0 | <peer_label>
2074 * multiple, inconsistent labels | -<errno> | SECSID_NULL
2075 *
2076 */
2077int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
2078 u32 xfrm_sid,
2079 u32 *peer_sid)
2080{
2081 int rc;
2082 struct context *nlbl_ctx;
2083 struct context *xfrm_ctx;
2084
2085 /* handle the common (which also happens to be the set of easy) cases
2086 * right away, these two if statements catch everything involving a
2087 * single or absent peer SID/label */
2088 if (xfrm_sid == SECSID_NULL) {
2089 *peer_sid = nlbl_sid;
2090 return 0;
2091 }
2092 /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
2093 * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
2094 * is present */
2095 if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
2096 *peer_sid = xfrm_sid;
2097 return 0;
2098 }
2099
2100 /* we don't need to check ss_initialized here since the only way both
2101 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
2102 * security server was initialized and ss_initialized was true */
2103 if (!selinux_mls_enabled) {
2104 *peer_sid = SECSID_NULL;
2105 return 0;
2106 }
2107
2108 POLICY_RDLOCK;
2109
2110 nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
2111 if (!nlbl_ctx) {
2112 printk(KERN_ERR
2113 "security_sid_mls_cmp: unrecognized SID %d\n",
2114 nlbl_sid);
2115 rc = -EINVAL;
2116 goto out_slowpath;
2117 }
2118 xfrm_ctx = sidtab_search(&sidtab, xfrm_sid);
2119 if (!xfrm_ctx) {
2120 printk(KERN_ERR
2121 "security_sid_mls_cmp: unrecognized SID %d\n",
2122 xfrm_sid);
2123 rc = -EINVAL;
2124 goto out_slowpath;
2125 }
2126 rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
2127
2128out_slowpath:
2129 POLICY_RDUNLOCK;
2130 if (rc == 0)
2131 /* at present NetLabel SIDs/labels really only carry MLS
2132 * information so if the MLS portion of the NetLabel SID
2133 * matches the MLS portion of the labeled XFRM SID/label
2134 * then pass along the XFRM SID as it is the most
2135 * expressive */
2136 *peer_sid = xfrm_sid;
2137 else
2138 *peer_sid = SECSID_NULL;
2139 return rc;
2140}
2141
2052static int get_classes_callback(void *k, void *d, void *args) 2142static int get_classes_callback(void *k, void *d, void *args)
2053{ 2143{
2054 struct class_datum *datum = d; 2144 struct class_datum *datum = d;
@@ -2154,6 +2244,60 @@ int security_get_allow_unknown(void)
2154 return policydb.allow_unknown; 2244 return policydb.allow_unknown;
2155} 2245}
2156 2246
2247/**
2248 * security_get_policycaps - Query the loaded policy for its capabilities
2249 * @len: the number of capability bits
2250 * @values: the capability bit array
2251 *
2252 * Description:
2253 * Get an array of the policy capabilities in @values where each entry in
2254 * @values is either true (1) or false (0) depending the policy's support of
2255 * that feature. The policy capabilities are defined by the
2256 * POLICYDB_CAPABILITY_* enums. The size of the array is stored in @len and it
2257 * is up to the caller to free the array in @values. Returns zero on success,
2258 * negative values on failure.
2259 *
2260 */
2261int security_get_policycaps(int *len, int **values)
2262{
2263 int rc = -ENOMEM;
2264 unsigned int iter;
2265
2266 POLICY_RDLOCK;
2267
2268 *values = kcalloc(POLICYDB_CAPABILITY_MAX, sizeof(int), GFP_ATOMIC);
2269 if (*values == NULL)
2270 goto out;
2271 for (iter = 0; iter < POLICYDB_CAPABILITY_MAX; iter++)
2272 (*values)[iter] = ebitmap_get_bit(&policydb.policycaps, iter);
2273 *len = POLICYDB_CAPABILITY_MAX;
2274
2275out:
2276 POLICY_RDUNLOCK;
2277 return rc;
2278}
2279
2280/**
2281 * security_policycap_supported - Check for a specific policy capability
2282 * @req_cap: capability
2283 *
2284 * Description:
2285 * This function queries the currently loaded policy to see if it supports the
2286 * capability specified by @req_cap. Returns true (1) if the capability is
2287 * supported, false (0) if it isn't supported.
2288 *
2289 */
2290int security_policycap_supported(unsigned int req_cap)
2291{
2292 int rc;
2293
2294 POLICY_RDLOCK;
2295 rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
2296 POLICY_RDUNLOCK;
2297
2298 return rc;
2299}
2300
2157struct selinux_audit_rule { 2301struct selinux_audit_rule {
2158 u32 au_seqno; 2302 u32 au_seqno;
2159 struct context au_ctxt; 2303 struct context au_ctxt;
@@ -2403,50 +2547,10 @@ void selinux_audit_set_callback(int (*callback)(void))
2403} 2547}
2404 2548
2405#ifdef CONFIG_NETLABEL 2549#ifdef CONFIG_NETLABEL
2406/*
2407 * NetLabel cache structure
2408 */
2409#define NETLBL_CACHE(x) ((struct selinux_netlbl_cache *)(x))
2410#define NETLBL_CACHE_T_NONE 0
2411#define NETLBL_CACHE_T_SID 1
2412#define NETLBL_CACHE_T_MLS 2
2413struct selinux_netlbl_cache {
2414 u32 type;
2415 union {
2416 u32 sid;
2417 struct mls_range mls_label;
2418 } data;
2419};
2420
2421/**
2422 * security_netlbl_cache_free - Free the NetLabel cached data
2423 * @data: the data to free
2424 *
2425 * Description:
2426 * This function is intended to be used as the free() callback inside the
2427 * netlbl_lsm_cache structure.
2428 *
2429 */
2430static void security_netlbl_cache_free(const void *data)
2431{
2432 struct selinux_netlbl_cache *cache;
2433
2434 if (data == NULL)
2435 return;
2436
2437 cache = NETLBL_CACHE(data);
2438 switch (cache->type) {
2439 case NETLBL_CACHE_T_MLS:
2440 ebitmap_destroy(&cache->data.mls_label.level[0].cat);
2441 break;
2442 }
2443 kfree(data);
2444}
2445
2446/** 2550/**
2447 * security_netlbl_cache_add - Add an entry to the NetLabel cache 2551 * security_netlbl_cache_add - Add an entry to the NetLabel cache
2448 * @secattr: the NetLabel packet security attributes 2552 * @secattr: the NetLabel packet security attributes
2449 * @ctx: the SELinux context 2553 * @sid: the SELinux SID
2450 * 2554 *
2451 * Description: 2555 * Description:
2452 * Attempt to cache the context in @ctx, which was derived from the packet in 2556 * Attempt to cache the context in @ctx, which was derived from the packet in
@@ -2455,60 +2559,46 @@ static void security_netlbl_cache_free(const void *data)
2455 * 2559 *
2456 */ 2560 */
2457static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, 2561static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
2458 struct context *ctx) 2562 u32 sid)
2459{ 2563{
2460 struct selinux_netlbl_cache *cache = NULL; 2564 u32 *sid_cache;
2461 2565
2462 secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); 2566 sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
2463 if (secattr->cache == NULL) 2567 if (sid_cache == NULL)
2464 return;
2465
2466 cache = kzalloc(sizeof(*cache), GFP_ATOMIC);
2467 if (cache == NULL)
2468 return; 2568 return;
2469 2569 secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
2470 cache->type = NETLBL_CACHE_T_MLS; 2570 if (secattr->cache == NULL) {
2471 if (ebitmap_cpy(&cache->data.mls_label.level[0].cat, 2571 kfree(sid_cache);
2472 &ctx->range.level[0].cat) != 0) {
2473 kfree(cache);
2474 return; 2572 return;
2475 } 2573 }
2476 cache->data.mls_label.level[1].cat.highbit =
2477 cache->data.mls_label.level[0].cat.highbit;
2478 cache->data.mls_label.level[1].cat.node =
2479 cache->data.mls_label.level[0].cat.node;
2480 cache->data.mls_label.level[0].sens = ctx->range.level[0].sens;
2481 cache->data.mls_label.level[1].sens = ctx->range.level[0].sens;
2482 2574
2483 secattr->cache->free = security_netlbl_cache_free; 2575 *sid_cache = sid;
2484 secattr->cache->data = (void *)cache; 2576 secattr->cache->free = kfree;
2577 secattr->cache->data = sid_cache;
2485 secattr->flags |= NETLBL_SECATTR_CACHE; 2578 secattr->flags |= NETLBL_SECATTR_CACHE;
2486} 2579}
2487 2580
2488/** 2581/**
2489 * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID 2582 * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
2490 * @secattr: the NetLabel packet security attributes 2583 * @secattr: the NetLabel packet security attributes
2491 * @base_sid: the SELinux SID to use as a context for MLS only attributes
2492 * @sid: the SELinux SID 2584 * @sid: the SELinux SID
2493 * 2585 *
2494 * Description: 2586 * Description:
2495 * Convert the given NetLabel security attributes in @secattr into a 2587 * Convert the given NetLabel security attributes in @secattr into a
2496 * SELinux SID. If the @secattr field does not contain a full SELinux 2588 * SELinux SID. If the @secattr field does not contain a full SELinux
2497 * SID/context then use the context in @base_sid as the foundation. If 2589 * SID/context then use SECINITSID_NETMSG as the foundation. If possibile the
2498 * possibile the 'cache' field of @secattr is set and the CACHE flag is set; 2590 * 'cache' field of @secattr is set and the CACHE flag is set; this is to
2499 * this is to allow the @secattr to be used by NetLabel to cache the secattr to 2591 * allow the @secattr to be used by NetLabel to cache the secattr to SID
2500 * SID conversion for future lookups. Returns zero on success, negative 2592 * conversion for future lookups. Returns zero on success, negative values on
2501 * values on failure. 2593 * failure.
2502 * 2594 *
2503 */ 2595 */
2504int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, 2596int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
2505 u32 base_sid,
2506 u32 *sid) 2597 u32 *sid)
2507{ 2598{
2508 int rc = -EIDRM; 2599 int rc = -EIDRM;
2509 struct context *ctx; 2600 struct context *ctx;
2510 struct context ctx_new; 2601 struct context ctx_new;
2511 struct selinux_netlbl_cache *cache;
2512 2602
2513 if (!ss_initialized) { 2603 if (!ss_initialized) {
2514 *sid = SECSID_NULL; 2604 *sid = SECSID_NULL;
@@ -2518,40 +2608,13 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
2518 POLICY_RDLOCK; 2608 POLICY_RDLOCK;
2519 2609
2520 if (secattr->flags & NETLBL_SECATTR_CACHE) { 2610 if (secattr->flags & NETLBL_SECATTR_CACHE) {
2521 cache = NETLBL_CACHE(secattr->cache->data); 2611 *sid = *(u32 *)secattr->cache->data;
2522 switch (cache->type) { 2612 rc = 0;
2523 case NETLBL_CACHE_T_SID: 2613 } else if (secattr->flags & NETLBL_SECATTR_SECID) {
2524 *sid = cache->data.sid; 2614 *sid = secattr->attr.secid;
2525 rc = 0; 2615 rc = 0;
2526 break;
2527 case NETLBL_CACHE_T_MLS:
2528 ctx = sidtab_search(&sidtab, base_sid);
2529 if (ctx == NULL)
2530 goto netlbl_secattr_to_sid_return;
2531
2532 ctx_new.user = ctx->user;
2533 ctx_new.role = ctx->role;
2534 ctx_new.type = ctx->type;
2535 ctx_new.range.level[0].sens =
2536 cache->data.mls_label.level[0].sens;
2537 ctx_new.range.level[0].cat.highbit =
2538 cache->data.mls_label.level[0].cat.highbit;
2539 ctx_new.range.level[0].cat.node =
2540 cache->data.mls_label.level[0].cat.node;
2541 ctx_new.range.level[1].sens =
2542 cache->data.mls_label.level[1].sens;
2543 ctx_new.range.level[1].cat.highbit =
2544 cache->data.mls_label.level[1].cat.highbit;
2545 ctx_new.range.level[1].cat.node =
2546 cache->data.mls_label.level[1].cat.node;
2547
2548 rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
2549 break;
2550 default:
2551 goto netlbl_secattr_to_sid_return;
2552 }
2553 } else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { 2616 } else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
2554 ctx = sidtab_search(&sidtab, base_sid); 2617 ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
2555 if (ctx == NULL) 2618 if (ctx == NULL)
2556 goto netlbl_secattr_to_sid_return; 2619 goto netlbl_secattr_to_sid_return;
2557 2620
@@ -2561,7 +2624,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
2561 mls_import_netlbl_lvl(&ctx_new, secattr); 2624 mls_import_netlbl_lvl(&ctx_new, secattr);
2562 if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 2625 if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
2563 if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat, 2626 if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
2564 secattr->mls_cat) != 0) 2627 secattr->attr.mls.cat) != 0)
2565 goto netlbl_secattr_to_sid_return; 2628 goto netlbl_secattr_to_sid_return;
2566 ctx_new.range.level[1].cat.highbit = 2629 ctx_new.range.level[1].cat.highbit =
2567 ctx_new.range.level[0].cat.highbit; 2630 ctx_new.range.level[0].cat.highbit;
@@ -2578,7 +2641,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
2578 if (rc != 0) 2641 if (rc != 0)
2579 goto netlbl_secattr_to_sid_return_cleanup; 2642 goto netlbl_secattr_to_sid_return_cleanup;
2580 2643
2581 security_netlbl_cache_add(secattr, &ctx_new); 2644 security_netlbl_cache_add(secattr, *sid);
2582 2645
2583 ebitmap_destroy(&ctx_new.range.level[0].cat); 2646 ebitmap_destroy(&ctx_new.range.level[0].cat);
2584 } else { 2647 } else {
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index e07603969033..7e158205d081 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -46,11 +46,14 @@
46#include <net/checksum.h> 46#include <net/checksum.h>
47#include <net/udp.h> 47#include <net/udp.h>
48#include <asm/semaphore.h> 48#include <asm/semaphore.h>
49#include <asm/atomic.h>
49 50
50#include "avc.h" 51#include "avc.h"
51#include "objsec.h" 52#include "objsec.h"
52#include "xfrm.h" 53#include "xfrm.h"
53 54
55/* Labeled XFRM instance counter */
56atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0);
54 57
55/* 58/*
56 * Returns true if an LSM/SELinux context 59 * Returns true if an LSM/SELinux context
@@ -293,6 +296,9 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp,
293 BUG_ON(!uctx); 296 BUG_ON(!uctx);
294 297
295 err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); 298 err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0);
299 if (err == 0)
300 atomic_inc(&selinux_xfrm_refcount);
301
296 return err; 302 return err;
297} 303}
298 304
@@ -340,10 +346,13 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp)
340 struct xfrm_sec_ctx *ctx = xp->security; 346 struct xfrm_sec_ctx *ctx = xp->security;
341 int rc = 0; 347 int rc = 0;
342 348
343 if (ctx) 349 if (ctx) {
344 rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 350 rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
345 SECCLASS_ASSOCIATION, 351 SECCLASS_ASSOCIATION,
346 ASSOCIATION__SETCONTEXT, NULL); 352 ASSOCIATION__SETCONTEXT, NULL);
353 if (rc == 0)
354 atomic_dec(&selinux_xfrm_refcount);
355 }
347 356
348 return rc; 357 return rc;
349} 358}
@@ -360,6 +369,8 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct
360 BUG_ON(!x); 369 BUG_ON(!x);
361 370
362 err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); 371 err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid);
372 if (err == 0)
373 atomic_inc(&selinux_xfrm_refcount);
363 return err; 374 return err;
364} 375}
365 376
@@ -382,10 +393,13 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
382 struct xfrm_sec_ctx *ctx = x->security; 393 struct xfrm_sec_ctx *ctx = x->security;
383 int rc = 0; 394 int rc = 0;
384 395
385 if (ctx) 396 if (ctx) {
386 rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 397 rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
387 SECCLASS_ASSOCIATION, 398 SECCLASS_ASSOCIATION,
388 ASSOCIATION__SETCONTEXT, NULL); 399 ASSOCIATION__SETCONTEXT, NULL);
400 if (rc == 0)
401 atomic_dec(&selinux_xfrm_refcount);
402 }
389 403
390 return rc; 404 return rc;
391} 405}