aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2008-01-29 08:43:36 -0500
committerJames Morris <jmorris@namei.org>2008-01-29 16:17:26 -0500
commitd621d35e576aa20a0ddae8022c3810f38357c8ff (patch)
tree318e8aa890dbe715b901b11b019ebac3badb693d
parent220deb966ea51e0dedb6a187c0763120809f3e64 (diff)
SELinux: Enable dynamic enable/disable of the network access checks
This patch introduces a mechanism for checking when labeled IPsec or SECMARK are in use by keeping introducing a configuration reference counter for each subsystem. In the case of labeled IPsec, whenever a labeled SA or SPD entry is created the labeled IPsec/XFRM reference count is increased and when the entry is removed it is decreased. In the case of SECMARK, when a SECMARK target is created the reference count is increased and later decreased when the target is removed. These reference counters allow SELinux to quickly determine if either of these subsystems are enabled. NetLabel already has a similar mechanism which provides the netlbl_enabled() function. This patch also renames the selinux_relabel_packet_permission() function to selinux_secmark_relabel_packet_permission() as the original name and description were misleading in that they referenced a single packet label which is not the case. Signed-off-by: Paul Moore <paul.moore@hp.com> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--include/linux/selinux.h45
-rw-r--r--net/netfilter/xt_SECMARK.c13
-rw-r--r--security/selinux/exports.c20
-rw-r--r--security/selinux/hooks.c46
-rw-r--r--security/selinux/include/xfrm.h12
-rw-r--r--security/selinux/xfrm.c18
6 files changed, 132 insertions, 22 deletions
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/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/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 bfe9a05db3a2..6156241c8770 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -51,8 +51,10 @@
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> 53#include <net/net_namespace.h>
54#include <net/netlabel.h>
54#include <asm/uaccess.h> 55#include <asm/uaccess.h>
55#include <asm/ioctls.h> 56#include <asm/ioctls.h>
57#include <asm/atomic.h>
56#include <linux/bitops.h> 58#include <linux/bitops.h>
57#include <linux/interrupt.h> 59#include <linux/interrupt.h>
58#include <linux/netdevice.h> /* for network interface checks */ 60#include <linux/netdevice.h> /* for network interface checks */
@@ -91,6 +93,9 @@ extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
91extern int selinux_compat_net; 93extern int selinux_compat_net;
92extern struct security_operations *security_ops; 94extern struct security_operations *security_ops;
93 95
96/* SECMARK reference count */
97atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
98
94#ifdef CONFIG_SECURITY_SELINUX_DEVELOP 99#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
95int selinux_enforcing = 0; 100int selinux_enforcing = 0;
96 101
@@ -157,6 +162,21 @@ getsecurity_exit:
157 return len; 162 return len;
158} 163}
159 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
160/* Allocate and free functions for each kind of security blob. */ 180/* Allocate and free functions for each kind of security blob. */
161 181
162static int task_alloc_security(struct task_struct *task) 182static int task_alloc_security(struct task_struct *task)
@@ -3931,7 +3951,6 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
3931 struct sk_security_struct *sksec = sk->sk_security; 3951 struct sk_security_struct *sksec = sk->sk_security;
3932 u16 family = sk->sk_family; 3952 u16 family = sk->sk_family;
3933 u32 sk_sid = sksec->sid; 3953 u32 sk_sid = sksec->sid;
3934 u32 peer_sid;
3935 struct avc_audit_data ad; 3954 struct avc_audit_data ad;
3936 char *addrp; 3955 char *addrp;
3937 3956
@@ -3957,15 +3976,24 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
3957 return selinux_sock_rcv_skb_compat(sk, skb, &ad, 3976 return selinux_sock_rcv_skb_compat(sk, skb, &ad,
3958 family, addrp); 3977 family, addrp);
3959 3978
3960 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, 3979 if (selinux_secmark_enabled()) {
3961 PACKET__RECV, &ad); 3980 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
3962 if (err) 3981 PACKET__RECV, &ad);
3963 return err; 3982 if (err)
3983 return err;
3984 }
3964 3985
3965 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); 3986 if (netlbl_enabled() || selinux_xfrm_enabled()) {
3966 if (err) 3987 u32 peer_sid;
3967 return err; 3988
3968 return avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, PEER__RECV, &ad); 3989 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
3990 if (err)
3991 return err;
3992 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
3993 PEER__RECV, &ad);
3994 }
3995
3996 return err;
3969} 3997}
3970 3998
3971static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, 3999static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
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/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}