diff options
author | Paul Moore <paul.moore@hp.com> | 2008-02-25 11:40:33 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-04-18 06:26:03 -0400 |
commit | f74af6e816c940c678c235d49486fe40d7e49ce9 (patch) | |
tree | 06f2fa54bd7ceabac2ad29a6ab0aca1deb87c032 | |
parent | 4b119e21d0c66c22e8ca03df05d9de623d0eb50f (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.c | 4 | ||||
-rw-r--r-- | security/selinux/include/netlabel.h | 16 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 1 | ||||
-rw-r--r-- | security/selinux/netlabel.c | 81 |
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 | ||
4145 | static void selinux_sk_getsecid(struct sock *sk, u32 *secid) | 4145 | static 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 | ||
42 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, | 42 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, |
43 | int family); | 43 | int family); |
44 | void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, | ||
45 | int family); | ||
46 | void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, | ||
47 | struct sk_security_struct *newssec); | ||
48 | 44 | ||
49 | int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | 45 | int 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 | } |
76 | static inline void selinux_netlbl_sk_security_init( | ||
77 | struct sk_security_struct *ssec, | ||
78 | int family) | ||
79 | { | ||
80 | return; | ||
81 | } | ||
82 | static 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 | ||
89 | static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | 73 | static 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 | */ |
77 | static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) | 75 | static 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 | ||
95 | sock_setsid_return: | 90 | sock_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 | */ | ||
141 | void 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 | */ | ||
159 | void 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 | */ |
255 | int selinux_netlbl_socket_post_create(struct socket *sock) | 205 | int 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 | } |