aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/netlabel.c
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2007-02-28 15:14:22 -0500
committerJames Morris <jmorris@namei.org>2007-04-26 01:35:48 -0400
commit5778eabd9cdbf16ea3e40248c452b4fd25554d11 (patch)
treea488fd5fc07c01b93fe38621888cc50c64cfc0a1 /security/selinux/netlabel.c
parent128c6b6cbffc8203e13ea5712a8aa65d2ed82e4e (diff)
SELinux: extract the NetLabel SELinux support from the security server
Up until this patch the functions which have provided NetLabel support to SELinux have been integrated into the SELinux security server, which for various reasons is not really ideal. This patch makes an effort to extract as much of the NetLabel support from the security server as possibile and move it into it's own file within the SELinux directory structure. Signed-off-by: Paul Moore <paul.moore@hp.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/netlabel.c')
-rw-r--r--security/selinux/netlabel.c363
1 files changed, 363 insertions, 0 deletions
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
new file mode 100644
index 000000000000..bf8750791dd1
--- /dev/null
+++ b/security/selinux/netlabel.c
@@ -0,0 +1,363 @@
1/*
2 * SELinux NetLabel Support
3 *
4 * This file provides the necessary glue to tie NetLabel into the SELinux
5 * subsystem.
6 *
7 * Author: Paul Moore <paul.moore@hp.com>
8 *
9 */
10
11/*
12 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
22 * the GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30#include <linux/spinlock.h>
31#include <linux/rcupdate.h>
32#include <net/sock.h>
33#include <net/netlabel.h>
34
35#include "objsec.h"
36#include "security.h"
37
38/**
39 * selinux_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
40 * @sock: the socket to label
41 * @sid: the SID to use
42 *
43 * Description:
44 * Attempt to label a socket using the NetLabel mechanism using the given
45 * SID. Returns zero values on success, negative values on failure. The
46 * caller is responsibile for calling rcu_read_lock() before calling this
47 * this function and rcu_read_unlock() after this function returns.
48 *
49 */
50static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
51{
52 int rc;
53 struct sk_security_struct *sksec = sock->sk->sk_security;
54 struct netlbl_lsm_secattr secattr;
55
56 rc = security_netlbl_sid_to_secattr(sid, &secattr);
57 if (rc != 0)
58 return rc;
59
60 rc = netlbl_socket_setattr(sock, &secattr);
61 if (rc == 0) {
62 spin_lock_bh(&sksec->nlbl_lock);
63 sksec->nlbl_state = NLBL_LABELED;
64 spin_unlock_bh(&sksec->nlbl_lock);
65 }
66
67 return rc;
68}
69
70/**
71 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
72 *
73 * Description:
74 * Invalidate the NetLabel security attribute mapping cache.
75 *
76 */
77void selinux_netlbl_cache_invalidate(void)
78{
79 netlbl_cache_invalidate();
80}
81
82/**
83 * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
84 * @ssec: the sk_security_struct
85 * @family: the socket family
86 *
87 * Description:
88 * Called when the NetLabel state of a sk_security_struct needs to be reset.
89 * The caller is responsibile for all the NetLabel sk_security_struct locking.
90 *
91 */
92void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
93 int family)
94{
95 if (family == PF_INET)
96 ssec->nlbl_state = NLBL_REQUIRE;
97 else
98 ssec->nlbl_state = NLBL_UNSET;
99}
100
101/**
102 * selinux_netlbl_sk_security_init - Setup the NetLabel fields
103 * @ssec: the sk_security_struct
104 * @family: the socket family
105 *
106 * Description:
107 * Called when a new sk_security_struct is allocated to initialize the NetLabel
108 * fields.
109 *
110 */
111void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
112 int family)
113{
114 /* No locking needed, we are the only one who has access to ssec */
115 selinux_netlbl_sk_security_reset(ssec, family);
116 spin_lock_init(&ssec->nlbl_lock);
117}
118
119/**
120 * selinux_netlbl_sk_security_clone - Copy the NetLabel fields
121 * @ssec: the original sk_security_struct
122 * @newssec: the cloned sk_security_struct
123 *
124 * Description:
125 * Clone the NetLabel specific sk_security_struct fields from @ssec to
126 * @newssec.
127 *
128 */
129void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
130 struct sk_security_struct *newssec)
131{
132 /* We don't need to take newssec->nlbl_lock because we are the only
133 * thread with access to newssec, but we do need to take the RCU read
134 * lock as other threads could have access to ssec */
135 rcu_read_lock();
136 selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
137 newssec->sclass = ssec->sclass;
138 rcu_read_unlock();
139}
140
141/**
142 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
143 * @skb: the packet
144 * @base_sid: the SELinux SID to use as a context for MLS only attributes
145 * @sid: the SID
146 *
147 * Description:
148 * Call the NetLabel mechanism to get the security attributes of the given
149 * packet and use those attributes to determine the correct context/SID to
150 * assign to the packet. Returns zero on success, negative values on failure.
151 *
152 */
153int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid)
154{
155 int rc;
156 struct netlbl_lsm_secattr secattr;
157
158 netlbl_secattr_init(&secattr);
159 rc = netlbl_skbuff_getattr(skb, &secattr);
160 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
161 rc = security_netlbl_secattr_to_sid(&secattr,
162 base_sid,
163 sid);
164 else
165 *sid = SECSID_NULL;
166 netlbl_secattr_destroy(&secattr);
167
168 return rc;
169}
170
171/**
172 * selinux_netlbl_sock_graft - Netlabel the new socket
173 * @sk: the new connection
174 * @sock: the new socket
175 *
176 * Description:
177 * The connection represented by @sk is being grafted onto @sock so set the
178 * socket's NetLabel to match the SID of @sk.
179 *
180 */
181void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
182{
183 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
184 struct sk_security_struct *sksec = sk->sk_security;
185 struct netlbl_lsm_secattr secattr;
186 u32 nlbl_peer_sid;
187
188 sksec->sclass = isec->sclass;
189
190 rcu_read_lock();
191
192 if (sksec->nlbl_state != NLBL_REQUIRE) {
193 rcu_read_unlock();
194 return;
195 }
196
197 netlbl_secattr_init(&secattr);
198 if (netlbl_sock_getattr(sk, &secattr) == 0 &&
199 secattr.flags != NETLBL_SECATTR_NONE &&
200 security_netlbl_secattr_to_sid(&secattr,
201 SECINITSID_UNLABELED,
202 &nlbl_peer_sid) == 0)
203 sksec->peer_sid = nlbl_peer_sid;
204 netlbl_secattr_destroy(&secattr);
205
206 /* Try to set the NetLabel on the socket to save time later, if we fail
207 * here we will pick up the pieces in later calls to
208 * selinux_netlbl_inode_permission(). */
209 selinux_netlbl_socket_setsid(sock, sksec->sid);
210
211 rcu_read_unlock();
212}
213
214/**
215 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
216 * @sock: the socket to label
217 *
218 * Description:
219 * Attempt to label a socket using the NetLabel mechanism using the given
220 * SID. Returns zero values on success, negative values on failure.
221 *
222 */
223int selinux_netlbl_socket_post_create(struct socket *sock)
224{
225 int rc = 0;
226 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
227 struct sk_security_struct *sksec = sock->sk->sk_security;
228
229 sksec->sclass = isec->sclass;
230
231 rcu_read_lock();
232 if (sksec->nlbl_state == NLBL_REQUIRE)
233 rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
234 rcu_read_unlock();
235
236 return rc;
237}
238
239/**
240 * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled
241 * @inode: the file descriptor's inode
242 * @mask: the permission mask
243 *
244 * Description:
245 * Looks at a file's inode and if it is marked as a socket protected by
246 * NetLabel then verify that the socket has been labeled, if not try to label
247 * the socket now with the inode's SID. Returns zero on success, negative
248 * values on failure.
249 *
250 */
251int selinux_netlbl_inode_permission(struct inode *inode, int mask)
252{
253 int rc;
254 struct sk_security_struct *sksec;
255 struct socket *sock;
256
257 if (!S_ISSOCK(inode->i_mode) ||
258 ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
259 return 0;
260 sock = SOCKET_I(inode);
261 sksec = sock->sk->sk_security;
262
263 rcu_read_lock();
264 if (sksec->nlbl_state != NLBL_REQUIRE) {
265 rcu_read_unlock();
266 return 0;
267 }
268 local_bh_disable();
269 bh_lock_sock_nested(sock->sk);
270 rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
271 bh_unlock_sock(sock->sk);
272 local_bh_enable();
273 rcu_read_unlock();
274
275 return rc;
276}
277
278/**
279 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
280 * @sksec: the sock's sk_security_struct
281 * @skb: the packet
282 * @ad: the audit data
283 *
284 * Description:
285 * Fetch the NetLabel security attributes from @skb and perform an access check
286 * against the receiving socket. Returns zero on success, negative values on
287 * error.
288 *
289 */
290int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
291 struct sk_buff *skb,
292 struct avc_audit_data *ad)
293{
294 int rc;
295 u32 netlbl_sid;
296 u32 recv_perm;
297
298 rc = selinux_netlbl_skbuff_getsid(skb,
299 SECINITSID_UNLABELED,
300 &netlbl_sid);
301 if (rc != 0)
302 return rc;
303
304 if (netlbl_sid == SECSID_NULL)
305 return 0;
306
307 switch (sksec->sclass) {
308 case SECCLASS_UDP_SOCKET:
309 recv_perm = UDP_SOCKET__RECVFROM;
310 break;
311 case SECCLASS_TCP_SOCKET:
312 recv_perm = TCP_SOCKET__RECVFROM;
313 break;
314 default:
315 recv_perm = RAWIP_SOCKET__RECVFROM;
316 }
317
318 rc = avc_has_perm(sksec->sid,
319 netlbl_sid,
320 sksec->sclass,
321 recv_perm,
322 ad);
323 if (rc == 0)
324 return 0;
325
326 netlbl_skbuff_err(skb, rc);
327 return rc;
328}
329
330/**
331 * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
332 * @sock: the socket
333 * @level: the socket level or protocol
334 * @optname: the socket option name
335 *
336 * Description:
337 * Check the setsockopt() call and if the user is trying to replace the IP
338 * options on a socket and a NetLabel is in place for the socket deny the
339 * access; otherwise allow the access. Returns zero when the access is
340 * allowed, -EACCES when denied, and other negative values on error.
341 *
342 */
343int selinux_netlbl_socket_setsockopt(struct socket *sock,
344 int level,
345 int optname)
346{
347 int rc = 0;
348 struct sk_security_struct *sksec = sock->sk->sk_security;
349 struct netlbl_lsm_secattr secattr;
350
351 rcu_read_lock();
352 if (level == IPPROTO_IP && optname == IP_OPTIONS &&
353 sksec->nlbl_state == NLBL_LABELED) {
354 netlbl_secattr_init(&secattr);
355 rc = netlbl_socket_getattr(sock, &secattr);
356 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
357 rc = -EACCES;
358 netlbl_secattr_destroy(&secattr);
359 }
360 rcu_read_unlock();
361
362 return rc;
363}