]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - security/selinux/netlabel.c
netlabel: Add functionality to set the security attributes of a packet
[mirror_ubuntu-bionic-kernel.git] / security / selinux / netlabel.c
CommitLineData
5778eabd
PM
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/*
948bf85c 12 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
5778eabd
PM
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>
948bf85c
PM
34#include <net/inet_sock.h>
35#include <net/inet_connection_sock.h>
5778eabd
PM
36
37#include "objsec.h"
38#include "security.h"
d4ee4231 39#include "netlabel.h"
5778eabd 40
5dbe1eb0
PM
41/**
42 * selinux_netlbl_sidlookup_cached - Cache a SID lookup
43 * @skb: the packet
44 * @secattr: the NetLabel security attributes
45 * @sid: the SID
46 *
47 * Description:
48 * Query the SELinux security server to lookup the correct SID for the given
49 * security attributes. If the query is successful, cache the result to speed
50 * up future lookups. Returns zero on success, negative values on failure.
51 *
52 */
53static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
54 struct netlbl_lsm_secattr *secattr,
55 u32 *sid)
56{
57 int rc;
58
59 rc = security_netlbl_secattr_to_sid(secattr, sid);
60 if (rc == 0 &&
61 (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
62 (secattr->flags & NETLBL_SECATTR_CACHE))
63 netlbl_cache_add(skb, secattr);
64
65 return rc;
66}
67
5778eabd 68/**
ba6ff9f2
PM
69 * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
70 * @sk: the socket to label
5778eabd
PM
71 *
72 * Description:
accc6093
PM
73 * Attempt to label a socket using the NetLabel mechanism. Returns zero values
74 * on success, negative values on failure.
5778eabd
PM
75 *
76 */
accc6093 77static int selinux_netlbl_sock_setsid(struct sock *sk)
5778eabd
PM
78{
79 int rc;
ba6ff9f2 80 struct sk_security_struct *sksec = sk->sk_security;
5778eabd 81 struct netlbl_lsm_secattr secattr;
948bf85c
PM
82 struct inet_sock *sk_inet;
83 struct inet_connection_sock *sk_conn;
5778eabd 84
accc6093
PM
85 if (sksec->nlbl_state != NLBL_REQUIRE)
86 return 0;
87
45c950e0
PM
88 netlbl_secattr_init(&secattr);
89
accc6093 90 rc = security_netlbl_sid_to_secattr(sksec->sid, &secattr);
5778eabd 91 if (rc != 0)
45c950e0 92 goto sock_setsid_return;
ba6ff9f2 93 rc = netlbl_sock_setattr(sk, &secattr);
948bf85c
PM
94 switch (rc) {
95 case 0:
5778eabd 96 sksec->nlbl_state = NLBL_LABELED;
948bf85c
PM
97 break;
98 case -EDESTADDRREQ:
99 /* we are going to possibly end up labeling the individual
100 * packets later which is problematic for stream sockets
101 * because of the additional IP header size, our solution is to
102 * allow for the maximum IP header length (40 bytes for IPv4,
103 * we don't have to worry about IPv6 yet) just in case */
104 sk_inet = inet_sk(sk);
105 if (sk_inet->is_icsk) {
106 sk_conn = inet_csk(sk);
107 if (sk_inet->opt)
108 sk_conn->icsk_ext_hdr_len -=
109 sk_inet->opt->optlen;
110 sk_conn->icsk_ext_hdr_len += 40;
111 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
112 }
113 sksec->nlbl_state = NLBL_REQSKB;
114 rc = 0;
115 break;
116 }
5778eabd 117
45c950e0
PM
118sock_setsid_return:
119 netlbl_secattr_destroy(&secattr);
5778eabd
PM
120 return rc;
121}
122
123/**
124 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
125 *
126 * Description:
127 * Invalidate the NetLabel security attribute mapping cache.
128 *
129 */
130void selinux_netlbl_cache_invalidate(void)
131{
132 netlbl_cache_invalidate();
133}
134
dfaebe98
PM
135/**
136 * selinux_netlbl_err - Handle a NetLabel packet error
137 * @skb: the packet
138 * @error: the error code
139 * @gateway: true if host is acting as a gateway, false otherwise
140 *
141 * Description:
142 * When a packet is dropped due to a call to avc_has_perm() pass the error
143 * code to the NetLabel subsystem so any protocol specific processing can be
144 * done. This is safe to call even if you are unsure if NetLabel labeling is
145 * present on the packet, NetLabel is smart enough to only act when it should.
146 *
147 */
148void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
149{
150 netlbl_skbuff_err(skb, error, gateway);
151}
152
5778eabd
PM
153/**
154 * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
155 * @ssec: the sk_security_struct
156 * @family: the socket family
157 *
158 * Description:
159 * Called when the NetLabel state of a sk_security_struct needs to be reset.
160 * The caller is responsibile for all the NetLabel sk_security_struct locking.
161 *
162 */
163void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
164 int family)
165{
a6aaafee 166 if (family == PF_INET)
5778eabd
PM
167 ssec->nlbl_state = NLBL_REQUIRE;
168 else
169 ssec->nlbl_state = NLBL_UNSET;
170}
171
5778eabd
PM
172/**
173 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
174 * @skb: the packet
75e22910 175 * @family: protocol family
220deb96 176 * @type: NetLabel labeling protocol type
5778eabd
PM
177 * @sid: the SID
178 *
179 * Description:
180 * Call the NetLabel mechanism to get the security attributes of the given
181 * packet and use those attributes to determine the correct context/SID to
182 * assign to the packet. Returns zero on success, negative values on failure.
183 *
184 */
75e22910
PM
185int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
186 u16 family,
220deb96 187 u32 *type,
75e22910 188 u32 *sid)
5778eabd
PM
189{
190 int rc;
191 struct netlbl_lsm_secattr secattr;
192
23bcdc1a
PM
193 if (!netlbl_enabled()) {
194 *sid = SECSID_NULL;
195 return 0;
196 }
197
5778eabd 198 netlbl_secattr_init(&secattr);
75e22910 199 rc = netlbl_skbuff_getattr(skb, family, &secattr);
5dbe1eb0
PM
200 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
201 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid);
202 else
5778eabd 203 *sid = SECSID_NULL;
220deb96 204 *type = secattr.type;
5778eabd
PM
205 netlbl_secattr_destroy(&secattr);
206
207 return rc;
208}
209
948bf85c
PM
210/**
211 * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
212 * @skb: the packet
213 * @family: protocol family
214 * @sid: the SID
215 *
216 * Description
217 * Call the NetLabel mechanism to set the label of a packet using @sid.
218 * Returns zero on auccess, negative values on failure.
219 *
220 */
221int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
222 u16 family,
223 u32 sid)
224{
225 int rc;
226 struct netlbl_lsm_secattr secattr;
227 struct sock *sk;
228
229 /* if this is a locally generated packet check to see if it is already
230 * being labeled by it's parent socket, if it is just exit */
231 sk = skb->sk;
232 if (sk != NULL) {
233 struct sk_security_struct *sksec = sk->sk_security;
234 if (sksec->nlbl_state != NLBL_REQSKB)
235 return 0;
236 }
237
238 netlbl_secattr_init(&secattr);
239 rc = security_netlbl_sid_to_secattr(sid, &secattr);
240 if (rc != 0)
241 goto skbuff_setsid_return;
242 rc = netlbl_skbuff_setattr(skb, family, &secattr);
243
244skbuff_setsid_return:
245 netlbl_secattr_destroy(&secattr);
246 return rc;
247}
248
5778eabd
PM
249/**
250 * selinux_netlbl_sock_graft - Netlabel the new socket
251 * @sk: the new connection
252 * @sock: the new socket
253 *
254 * Description:
255 * The connection represented by @sk is being grafted onto @sock so set the
256 * socket's NetLabel to match the SID of @sk.
257 *
258 */
259void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
260{
5778eabd
PM
261 /* Try to set the NetLabel on the socket to save time later, if we fail
262 * here we will pick up the pieces in later calls to
263 * selinux_netlbl_inode_permission(). */
accc6093 264 selinux_netlbl_sock_setsid(sk);
5778eabd
PM
265}
266
267/**
268 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
269 * @sock: the socket to label
270 *
271 * Description:
272 * Attempt to label a socket using the NetLabel mechanism using the given
273 * SID. Returns zero values on success, negative values on failure.
274 *
275 */
276int selinux_netlbl_socket_post_create(struct socket *sock)
277{
accc6093 278 return selinux_netlbl_sock_setsid(sock->sk);
5778eabd
PM
279}
280
281/**
282 * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled
283 * @inode: the file descriptor's inode
284 * @mask: the permission mask
285 *
286 * Description:
287 * Looks at a file's inode and if it is marked as a socket protected by
288 * NetLabel then verify that the socket has been labeled, if not try to label
289 * the socket now with the inode's SID. Returns zero on success, negative
290 * values on failure.
291 *
292 */
293int selinux_netlbl_inode_permission(struct inode *inode, int mask)
294{
295 int rc;
ba6ff9f2 296 struct sock *sk;
5778eabd 297 struct socket *sock;
ba6ff9f2 298 struct sk_security_struct *sksec;
5778eabd
PM
299
300 if (!S_ISSOCK(inode->i_mode) ||
301 ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
302 return 0;
f74af6e8 303
5778eabd 304 sock = SOCKET_I(inode);
ba6ff9f2
PM
305 sk = sock->sk;
306 sksec = sk->sk_security;
f74af6e8 307 if (sksec->nlbl_state != NLBL_REQUIRE)
5778eabd 308 return 0;
f74af6e8 309
5778eabd 310 local_bh_disable();
ba6ff9f2 311 bh_lock_sock_nested(sk);
f74af6e8 312 if (likely(sksec->nlbl_state == NLBL_REQUIRE))
accc6093 313 rc = selinux_netlbl_sock_setsid(sk);
f74af6e8
PM
314 else
315 rc = 0;
ba6ff9f2 316 bh_unlock_sock(sk);
5778eabd 317 local_bh_enable();
5778eabd
PM
318
319 return rc;
320}
321
322/**
323 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
324 * @sksec: the sock's sk_security_struct
325 * @skb: the packet
75e22910 326 * @family: protocol family
5778eabd
PM
327 * @ad: the audit data
328 *
329 * Description:
330 * Fetch the NetLabel security attributes from @skb and perform an access check
331 * against the receiving socket. Returns zero on success, negative values on
332 * error.
333 *
334 */
335int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
336 struct sk_buff *skb,
75e22910 337 u16 family,
5778eabd
PM
338 struct avc_audit_data *ad)
339{
340 int rc;
f36158c4
PM
341 u32 nlbl_sid;
342 u32 perm;
343 struct netlbl_lsm_secattr secattr;
5778eabd 344
23bcdc1a
PM
345 if (!netlbl_enabled())
346 return 0;
347
f36158c4 348 netlbl_secattr_init(&secattr);
75e22910 349 rc = netlbl_skbuff_getattr(skb, family, &secattr);
5dbe1eb0
PM
350 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
351 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid);
352 else
f36158c4
PM
353 nlbl_sid = SECINITSID_UNLABELED;
354 netlbl_secattr_destroy(&secattr);
5778eabd
PM
355 if (rc != 0)
356 return rc;
8d9107e8 357
5778eabd
PM
358 switch (sksec->sclass) {
359 case SECCLASS_UDP_SOCKET:
f36158c4 360 perm = UDP_SOCKET__RECVFROM;
5778eabd
PM
361 break;
362 case SECCLASS_TCP_SOCKET:
f36158c4 363 perm = TCP_SOCKET__RECVFROM;
5778eabd
PM
364 break;
365 default:
f36158c4 366 perm = RAWIP_SOCKET__RECVFROM;
5778eabd
PM
367 }
368
f36158c4 369 rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
5778eabd
PM
370 if (rc == 0)
371 return 0;
372
f36158c4 373 if (nlbl_sid != SECINITSID_UNLABELED)
dfaebe98 374 netlbl_skbuff_err(skb, rc, 0);
5778eabd
PM
375 return rc;
376}
377
378/**
379 * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
380 * @sock: the socket
381 * @level: the socket level or protocol
382 * @optname: the socket option name
383 *
384 * Description:
385 * Check the setsockopt() call and if the user is trying to replace the IP
386 * options on a socket and a NetLabel is in place for the socket deny the
387 * access; otherwise allow the access. Returns zero when the access is
388 * allowed, -EACCES when denied, and other negative values on error.
389 *
390 */
391int selinux_netlbl_socket_setsockopt(struct socket *sock,
392 int level,
393 int optname)
394{
395 int rc = 0;
ba6ff9f2
PM
396 struct sock *sk = sock->sk;
397 struct sk_security_struct *sksec = sk->sk_security;
5778eabd
PM
398 struct netlbl_lsm_secattr secattr;
399
5778eabd
PM
400 if (level == IPPROTO_IP && optname == IP_OPTIONS &&
401 sksec->nlbl_state == NLBL_LABELED) {
402 netlbl_secattr_init(&secattr);
ba6ff9f2
PM
403 lock_sock(sk);
404 rc = netlbl_sock_getattr(sk, &secattr);
405 release_sock(sk);
5778eabd
PM
406 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
407 rc = -EACCES;
408 netlbl_secattr_destroy(&secattr);
409 }
5778eabd
PM
410
411 return rc;
412}