aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2008-02-25 11:40:33 -0500
committerJames Morris <jmorris@namei.org>2008-04-18 06:26:03 -0400
commitf74af6e816c940c678c235d49486fe40d7e49ce9 (patch)
tree06f2fa54bd7ceabac2ad29a6ab0aca1deb87c032
parent4b119e21d0c66c22e8ca03df05d9de623d0eb50f (diff)
SELinux: Correct the NetLabel locking for the sk_security_struct
The RCU/spinlock locking approach for the nlbl_state in the sk_security_struct was almost certainly overkill. This patch removes both the RCU and spinlock locking, relying on the existing socket locks to handle the case of multiple writers. This change also makes several code reductions possible. Less locking, less code - it's a Good Thing. Signed-off-by: Paul Moore <paul.moore@hp.com> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--security/selinux/hooks.c4
-rw-r--r--security/selinux/include/netlabel.h16
-rw-r--r--security/selinux/include/objsec.h1
-rw-r--r--security/selinux/netlabel.c81
4 files changed, 15 insertions, 87 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d39b59cf8a08..d51bd40a04a8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -280,7 +280,7 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
280 ssec->sid = SECINITSID_UNLABELED; 280 ssec->sid = SECINITSID_UNLABELED;
281 sk->sk_security = ssec; 281 sk->sk_security = ssec;
282 282
283 selinux_netlbl_sk_security_init(ssec, family); 283 selinux_netlbl_sk_security_reset(ssec, family);
284 284
285 return 0; 285 return 0;
286} 286}
@@ -4139,7 +4139,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4139 newssec->peer_sid = ssec->peer_sid; 4139 newssec->peer_sid = ssec->peer_sid;
4140 newssec->sclass = ssec->sclass; 4140 newssec->sclass = ssec->sclass;
4141 4141
4142 selinux_netlbl_sk_security_clone(ssec, newssec); 4142 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
4143} 4143}
4144 4144
4145static void selinux_sk_getsecid(struct sock *sk, u32 *secid) 4145static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index 00a2809c8506..9a9e7cd9a379 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -41,10 +41,6 @@ void selinux_netlbl_cache_invalidate(void);
41 41
42void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, 42void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
43 int family); 43 int family);
44void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
45 int family);
46void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
47 struct sk_security_struct *newssec);
48 44
49int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 45int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
50 u16 family, 46 u16 family,
@@ -73,18 +69,6 @@ static inline void selinux_netlbl_sk_security_reset(
73{ 69{
74 return; 70 return;
75} 71}
76static inline void selinux_netlbl_sk_security_init(
77 struct sk_security_struct *ssec,
78 int family)
79{
80 return;
81}
82static inline void selinux_netlbl_sk_security_clone(
83 struct sk_security_struct *ssec,
84 struct sk_security_struct *newssec)
85{
86 return;
87}
88 72
89static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 73static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
90 u16 family, 74 u16 family,
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index c6c2bb4ebacc..0b74077eed4f 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -120,7 +120,6 @@ struct sk_security_struct {
120 NLBL_REQUIRE, 120 NLBL_REQUIRE,
121 NLBL_LABELED, 121 NLBL_LABELED,
122 } nlbl_state; 122 } nlbl_state;
123 spinlock_t nlbl_lock; /* protects nlbl_state */
124#endif 123#endif
125}; 124};
126 125
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 0fa2be4149e8..ccf71f69a185 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -69,9 +69,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
69 * 69 *
70 * Description: 70 * Description:
71 * Attempt to label a socket using the NetLabel mechanism using the given 71 * Attempt to label a socket using the NetLabel mechanism using the given
72 * SID. Returns zero values on success, negative values on failure. The 72 * SID. Returns zero values on success, negative values on failure.
73 * caller is responsibile for calling rcu_read_lock() before calling this
74 * this function and rcu_read_unlock() after this function returns.
75 * 73 *
76 */ 74 */
77static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) 75static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
@@ -86,11 +84,8 @@ static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
86 if (rc != 0) 84 if (rc != 0)
87 goto sock_setsid_return; 85 goto sock_setsid_return;
88 rc = netlbl_sock_setattr(sk, &secattr); 86 rc = netlbl_sock_setattr(sk, &secattr);
89 if (rc == 0) { 87 if (rc == 0)
90 spin_lock_bh(&sksec->nlbl_lock);
91 sksec->nlbl_state = NLBL_LABELED; 88 sksec->nlbl_state = NLBL_LABELED;
92 spin_unlock_bh(&sksec->nlbl_lock);
93 }
94 89
95sock_setsid_return: 90sock_setsid_return:
96 netlbl_secattr_destroy(&secattr); 91 netlbl_secattr_destroy(&secattr);
@@ -129,45 +124,6 @@ void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
129} 124}
130 125
131/** 126/**
132 * selinux_netlbl_sk_security_init - Setup the NetLabel fields
133 * @ssec: the sk_security_struct
134 * @family: the socket family
135 *
136 * Description:
137 * Called when a new sk_security_struct is allocated to initialize the NetLabel
138 * fields.
139 *
140 */
141void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
142 int family)
143{
144 /* No locking needed, we are the only one who has access to ssec */
145 selinux_netlbl_sk_security_reset(ssec, family);
146 spin_lock_init(&ssec->nlbl_lock);
147}
148
149/**
150 * selinux_netlbl_sk_security_clone - Copy the NetLabel fields
151 * @ssec: the original sk_security_struct
152 * @newssec: the cloned sk_security_struct
153 *
154 * Description:
155 * Clone the NetLabel specific sk_security_struct fields from @ssec to
156 * @newssec.
157 *
158 */
159void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
160 struct sk_security_struct *newssec)
161{
162 /* We don't need to take newssec->nlbl_lock because we are the only
163 * thread with access to newssec, but we do need to take the RCU read
164 * lock as other threads could have access to ssec */
165 rcu_read_lock();
166 selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
167 rcu_read_unlock();
168}
169
170/**
171 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel 127 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
172 * @skb: the packet 128 * @skb: the packet
173 * @family: protocol family 129 * @family: protocol family
@@ -221,12 +177,8 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
221 struct netlbl_lsm_secattr secattr; 177 struct netlbl_lsm_secattr secattr;
222 u32 nlbl_peer_sid; 178 u32 nlbl_peer_sid;
223 179
224 rcu_read_lock(); 180 if (sksec->nlbl_state != NLBL_REQUIRE)
225
226 if (sksec->nlbl_state != NLBL_REQUIRE) {
227 rcu_read_unlock();
228 return; 181 return;
229 }
230 182
231 netlbl_secattr_init(&secattr); 183 netlbl_secattr_init(&secattr);
232 if (netlbl_sock_getattr(sk, &secattr) == 0 && 184 if (netlbl_sock_getattr(sk, &secattr) == 0 &&
@@ -239,8 +191,6 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
239 * here we will pick up the pieces in later calls to 191 * here we will pick up the pieces in later calls to
240 * selinux_netlbl_inode_permission(). */ 192 * selinux_netlbl_inode_permission(). */
241 selinux_netlbl_sock_setsid(sk, sksec->sid); 193 selinux_netlbl_sock_setsid(sk, sksec->sid);
242
243 rcu_read_unlock();
244} 194}
245 195
246/** 196/**
@@ -254,16 +204,13 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
254 */ 204 */
255int selinux_netlbl_socket_post_create(struct socket *sock) 205int selinux_netlbl_socket_post_create(struct socket *sock)
256{ 206{
257 int rc = 0;
258 struct sock *sk = sock->sk; 207 struct sock *sk = sock->sk;
259 struct sk_security_struct *sksec = sk->sk_security; 208 struct sk_security_struct *sksec = sk->sk_security;
260 209
261 rcu_read_lock(); 210 if (sksec->nlbl_state != NLBL_REQUIRE)
262 if (sksec->nlbl_state == NLBL_REQUIRE) 211 return 0;
263 rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
264 rcu_read_unlock();
265 212
266 return rc; 213 return selinux_netlbl_sock_setsid(sk, sksec->sid);
267} 214}
268 215
269/** 216/**
@@ -288,21 +235,21 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
288 if (!S_ISSOCK(inode->i_mode) || 235 if (!S_ISSOCK(inode->i_mode) ||
289 ((mask & (MAY_WRITE | MAY_APPEND)) == 0)) 236 ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
290 return 0; 237 return 0;
238
291 sock = SOCKET_I(inode); 239 sock = SOCKET_I(inode);
292 sk = sock->sk; 240 sk = sock->sk;
293 sksec = sk->sk_security; 241 sksec = sk->sk_security;
294 242 if (sksec->nlbl_state != NLBL_REQUIRE)
295 rcu_read_lock();
296 if (sksec->nlbl_state != NLBL_REQUIRE) {
297 rcu_read_unlock();
298 return 0; 243 return 0;
299 } 244
300 local_bh_disable(); 245 local_bh_disable();
301 bh_lock_sock_nested(sk); 246 bh_lock_sock_nested(sk);
302 rc = selinux_netlbl_sock_setsid(sk, sksec->sid); 247 if (likely(sksec->nlbl_state == NLBL_REQUIRE))
248 rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
249 else
250 rc = 0;
303 bh_unlock_sock(sk); 251 bh_unlock_sock(sk);
304 local_bh_enable(); 252 local_bh_enable();
305 rcu_read_unlock();
306 253
307 return rc; 254 return rc;
308} 255}
@@ -385,7 +332,6 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
385 struct sk_security_struct *sksec = sk->sk_security; 332 struct sk_security_struct *sksec = sk->sk_security;
386 struct netlbl_lsm_secattr secattr; 333 struct netlbl_lsm_secattr secattr;
387 334
388 rcu_read_lock();
389 if (level == IPPROTO_IP && optname == IP_OPTIONS && 335 if (level == IPPROTO_IP && optname == IP_OPTIONS &&
390 sksec->nlbl_state == NLBL_LABELED) { 336 sksec->nlbl_state == NLBL_LABELED) {
391 netlbl_secattr_init(&secattr); 337 netlbl_secattr_init(&secattr);
@@ -396,7 +342,6 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
396 rc = -EACCES; 342 rc = -EACCES;
397 netlbl_secattr_destroy(&secattr); 343 netlbl_secattr_destroy(&secattr);
398 } 344 }
399 rcu_read_unlock();
400 345
401 return rc; 346 return rc;
402} 347}