aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVenkat Yekkirala <vyekkirala@TrustedCS.com>2006-08-05 02:17:57 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 17:53:36 -0400
commit7420ed23a4f77480b5b7b3245e5da30dd24b7575 (patch)
tree016f5bb996c5eae66754b10243c5be6226d773f2
parent96cb8e3313c7a12e026c1ed510522ae6f6023875 (diff)
[NetLabel]: SELinux support
Add NetLabel support to the SELinux LSM and modify the socket_post_create() LSM hook to return an error code. The most significant part of this patch is the addition of NetLabel hooks into the following SELinux LSM hooks: * selinux_file_permission() * selinux_socket_sendmsg() * selinux_socket_post_create() * selinux_socket_sock_rcv_skb() * selinux_socket_getpeersec_stream() * selinux_socket_getpeersec_dgram() * selinux_sock_graft() * selinux_inet_conn_request() The basic reasoning behind this patch is that outgoing packets are "NetLabel'd" by labeling their socket and the NetLabel security attributes are checked via the additional hook in selinux_socket_sock_rcv_skb(). NetLabel itself is only a labeling mechanism, similar to filesystem extended attributes, it is up to the SELinux enforcement mechanism to perform the actual access checks. In addition to the changes outlined above this patch also includes some changes to the extended bitmap (ebitmap) and multi-level security (mls) code to import and export SELinux TE/MLS attributes into and out of NetLabel. Signed-off-by: Paul Moore <paul.moore@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/security.h25
-rw-r--r--net/socket.c13
-rw-r--r--security/dummy.c6
-rw-r--r--security/selinux/hooks.c56
-rw-r--r--security/selinux/include/objsec.h8
-rw-r--r--security/selinux/include/selinux_netlabel.h125
-rw-r--r--security/selinux/ss/ebitmap.c144
-rw-r--r--security/selinux/ss/ebitmap.h6
-rw-r--r--security/selinux/ss/mls.c156
-rw-r--r--security/selinux/ss/mls.h21
-rw-r--r--security/selinux/ss/services.c488
11 files changed, 1020 insertions, 28 deletions
diff --git a/include/linux/security.h b/include/linux/security.h
index bb4c80fdfe7a..9f56fb8a4a6c 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1341,8 +1341,8 @@ struct security_operations {
1341 int (*unix_may_send) (struct socket * sock, struct socket * other); 1341 int (*unix_may_send) (struct socket * sock, struct socket * other);
1342 1342
1343 int (*socket_create) (int family, int type, int protocol, int kern); 1343 int (*socket_create) (int family, int type, int protocol, int kern);
1344 void (*socket_post_create) (struct socket * sock, int family, 1344 int (*socket_post_create) (struct socket * sock, int family,
1345 int type, int protocol, int kern); 1345 int type, int protocol, int kern);
1346 int (*socket_bind) (struct socket * sock, 1346 int (*socket_bind) (struct socket * sock,
1347 struct sockaddr * address, int addrlen); 1347 struct sockaddr * address, int addrlen);
1348 int (*socket_connect) (struct socket * sock, 1348 int (*socket_connect) (struct socket * sock,
@@ -2824,13 +2824,13 @@ static inline int security_socket_create (int family, int type,
2824 return security_ops->socket_create(family, type, protocol, kern); 2824 return security_ops->socket_create(family, type, protocol, kern);
2825} 2825}
2826 2826
2827static inline void security_socket_post_create(struct socket * sock, 2827static inline int security_socket_post_create(struct socket * sock,
2828 int family, 2828 int family,
2829 int type, 2829 int type,
2830 int protocol, int kern) 2830 int protocol, int kern)
2831{ 2831{
2832 security_ops->socket_post_create(sock, family, type, 2832 return security_ops->socket_post_create(sock, family, type,
2833 protocol, kern); 2833 protocol, kern);
2834} 2834}
2835 2835
2836static inline int security_socket_bind(struct socket * sock, 2836static inline int security_socket_bind(struct socket * sock,
@@ -2982,11 +2982,12 @@ static inline int security_socket_create (int family, int type,
2982 return 0; 2982 return 0;
2983} 2983}
2984 2984
2985static inline void security_socket_post_create(struct socket * sock, 2985static inline int security_socket_post_create(struct socket * sock,
2986 int family, 2986 int family,
2987 int type, 2987 int type,
2988 int protocol, int kern) 2988 int protocol, int kern)
2989{ 2989{
2990 return 0;
2990} 2991}
2991 2992
2992static inline int security_socket_bind(struct socket * sock, 2993static inline int security_socket_bind(struct socket * sock,
diff --git a/net/socket.c b/net/socket.c
index 6d261bf206fc..6756e57e1ff0 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -973,11 +973,18 @@ int sock_create_lite(int family, int type, int protocol, struct socket **res)
973 goto out; 973 goto out;
974 } 974 }
975 975
976 security_socket_post_create(sock, family, type, protocol, 1);
977 sock->type = type; 976 sock->type = type;
977 err = security_socket_post_create(sock, family, type, protocol, 1);
978 if (err)
979 goto out_release;
980
978out: 981out:
979 *res = sock; 982 *res = sock;
980 return err; 983 return err;
984out_release:
985 sock_release(sock);
986 sock = NULL;
987 goto out;
981} 988}
982 989
983/* No kernel lock held - perfect */ 990/* No kernel lock held - perfect */
@@ -1214,7 +1221,9 @@ static int __sock_create(int family, int type, int protocol, struct socket **res
1214 */ 1221 */
1215 module_put(net_families[family]->owner); 1222 module_put(net_families[family]->owner);
1216 *res = sock; 1223 *res = sock;
1217 security_socket_post_create(sock, family, type, protocol, kern); 1224 err = security_socket_post_create(sock, family, type, protocol, kern);
1225 if (err)
1226 goto out_release;
1218 1227
1219out: 1228out:
1220 net_family_read_unlock(); 1229 net_family_read_unlock();
diff --git a/security/dummy.c b/security/dummy.c
index 1c45f8e4aad1..aeee70565509 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -709,10 +709,10 @@ static int dummy_socket_create (int family, int type,
709 return 0; 709 return 0;
710} 710}
711 711
712static void dummy_socket_post_create (struct socket *sock, int family, int type, 712static int dummy_socket_post_create (struct socket *sock, int family, int type,
713 int protocol, int kern) 713 int protocol, int kern)
714{ 714{
715 return; 715 return 0;
716} 716}
717 717
718static int dummy_socket_bind (struct socket *sock, struct sockaddr *address, 718static int dummy_socket_bind (struct socket *sock, struct sockaddr *address,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 33028b3b19ce..2a6bbb921e1e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -12,6 +12,8 @@
12 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 12 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
13 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. 13 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
14 * <dgoeddel@trustedcs.com> 14 * <dgoeddel@trustedcs.com>
15 * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
16 * Paul Moore, <paul.moore@hp.com>
15 * 17 *
16 * This program is free software; you can redistribute it and/or modify 18 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2, 19 * it under the terms of the GNU General Public License version 2,
@@ -74,6 +76,7 @@
74#include "objsec.h" 76#include "objsec.h"
75#include "netif.h" 77#include "netif.h"
76#include "xfrm.h" 78#include "xfrm.h"
79#include "selinux_netlabel.h"
77 80
78#define XATTR_SELINUX_SUFFIX "selinux" 81#define XATTR_SELINUX_SUFFIX "selinux"
79#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX 82#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
@@ -2395,6 +2398,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
2395 2398
2396static int selinux_file_permission(struct file *file, int mask) 2399static int selinux_file_permission(struct file *file, int mask)
2397{ 2400{
2401 int rc;
2398 struct inode *inode = file->f_dentry->d_inode; 2402 struct inode *inode = file->f_dentry->d_inode;
2399 2403
2400 if (!mask) { 2404 if (!mask) {
@@ -2406,8 +2410,12 @@ static int selinux_file_permission(struct file *file, int mask)
2406 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) 2410 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2407 mask |= MAY_APPEND; 2411 mask |= MAY_APPEND;
2408 2412
2409 return file_has_perm(current, file, 2413 rc = file_has_perm(current, file,
2410 file_mask_to_av(inode->i_mode, mask)); 2414 file_mask_to_av(inode->i_mode, mask));
2415 if (rc)
2416 return rc;
2417
2418 return selinux_netlbl_inode_permission(inode, mask);
2411} 2419}
2412 2420
2413static int selinux_file_alloc_security(struct file *file) 2421static int selinux_file_alloc_security(struct file *file)
@@ -3058,9 +3066,10 @@ out:
3058 return err; 3066 return err;
3059} 3067}
3060 3068
3061static void selinux_socket_post_create(struct socket *sock, int family, 3069static int selinux_socket_post_create(struct socket *sock, int family,
3062 int type, int protocol, int kern) 3070 int type, int protocol, int kern)
3063{ 3071{
3072 int err = 0;
3064 struct inode_security_struct *isec; 3073 struct inode_security_struct *isec;
3065 struct task_security_struct *tsec; 3074 struct task_security_struct *tsec;
3066 struct sk_security_struct *sksec; 3075 struct sk_security_struct *sksec;
@@ -3077,9 +3086,12 @@ static void selinux_socket_post_create(struct socket *sock, int family,
3077 if (sock->sk) { 3086 if (sock->sk) {
3078 sksec = sock->sk->sk_security; 3087 sksec = sock->sk->sk_security;
3079 sksec->sid = isec->sid; 3088 sksec->sid = isec->sid;
3089 err = selinux_netlbl_socket_post_create(sock,
3090 family,
3091 isec->sid);
3080 } 3092 }
3081 3093
3082 return; 3094 return err;
3083} 3095}
3084 3096
3085/* Range of port numbers used to automatically bind. 3097/* Range of port numbers used to automatically bind.
@@ -3260,7 +3272,13 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3260static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, 3272static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
3261 int size) 3273 int size)
3262{ 3274{
3263 return socket_has_perm(current, sock, SOCKET__WRITE); 3275 int rc;
3276
3277 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3278 if (rc)
3279 return rc;
3280
3281 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
3264} 3282}
3265 3283
3266static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, 3284static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -3468,6 +3486,10 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
3468 if (err) 3486 if (err)
3469 goto out; 3487 goto out;
3470 3488
3489 err = selinux_netlbl_sock_rcv_skb(sksec, skb, &ad);
3490 if (err)
3491 goto out;
3492
3471 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); 3493 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
3472out: 3494out:
3473 return err; 3495 return err;
@@ -3491,8 +3513,9 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
3491 peer_sid = ssec->peer_sid; 3513 peer_sid = ssec->peer_sid;
3492 } 3514 }
3493 else if (isec->sclass == SECCLASS_TCP_SOCKET) { 3515 else if (isec->sclass == SECCLASS_TCP_SOCKET) {
3494 peer_sid = selinux_socket_getpeer_stream(sock->sk); 3516 peer_sid = selinux_netlbl_socket_getpeersec_stream(sock);
3495 3517 if (peer_sid == SECSID_NULL)
3518 peer_sid = selinux_socket_getpeer_stream(sock->sk);
3496 if (peer_sid == SECSID_NULL) { 3519 if (peer_sid == SECSID_NULL) {
3497 err = -ENOPROTOOPT; 3520 err = -ENOPROTOOPT;
3498 goto out; 3521 goto out;
@@ -3532,8 +3555,11 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
3532 3555
3533 if (sock && (sock->sk->sk_family == PF_UNIX)) 3556 if (sock && (sock->sk->sk_family == PF_UNIX))
3534 selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); 3557 selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
3535 else if (skb) 3558 else if (skb) {
3536 peer_secid = selinux_socket_getpeer_dgram(skb); 3559 peer_secid = selinux_netlbl_socket_getpeersec_dgram(skb);
3560 if (peer_secid == SECSID_NULL)
3561 peer_secid = selinux_socket_getpeer_dgram(skb);
3562 }
3537 3563
3538 if (peer_secid == SECSID_NULL) 3564 if (peer_secid == SECSID_NULL)
3539 err = -EINVAL; 3565 err = -EINVAL;
@@ -3578,6 +3604,8 @@ void selinux_sock_graft(struct sock* sk, struct socket *parent)
3578 struct sk_security_struct *sksec = sk->sk_security; 3604 struct sk_security_struct *sksec = sk->sk_security;
3579 3605
3580 isec->sid = sksec->sid; 3606 isec->sid = sksec->sid;
3607
3608 selinux_netlbl_sock_graft(sk, parent);
3581} 3609}
3582 3610
3583int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, 3611int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
@@ -3585,9 +3613,15 @@ int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
3585{ 3613{
3586 struct sk_security_struct *sksec = sk->sk_security; 3614 struct sk_security_struct *sksec = sk->sk_security;
3587 int err; 3615 int err;
3588 u32 newsid = 0; 3616 u32 newsid;
3589 u32 peersid; 3617 u32 peersid;
3590 3618
3619 newsid = selinux_netlbl_inet_conn_request(skb, sksec->sid);
3620 if (newsid != SECSID_NULL) {
3621 req->secid = newsid;
3622 return 0;
3623 }
3624
3591 err = selinux_xfrm_decode_session(skb, &peersid, 0); 3625 err = selinux_xfrm_decode_session(skb, &peersid, 0);
3592 BUG_ON(err); 3626 BUG_ON(err);
3593 3627
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 79b9e0af19a0..0a39bfd1319f 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -101,6 +101,14 @@ struct sk_security_struct {
101 struct sock *sk; /* back pointer to sk object */ 101 struct sock *sk; /* back pointer to sk object */
102 u32 sid; /* SID of this object */ 102 u32 sid; /* SID of this object */
103 u32 peer_sid; /* SID of peer */ 103 u32 peer_sid; /* SID of peer */
104#ifdef CONFIG_NETLABEL
105 u16 sclass; /* sock security class */
106 enum { /* NetLabel state */
107 NLBL_UNSET = 0,
108 NLBL_REQUIRE,
109 NLBL_LABELED,
110 } nlbl_state;
111#endif
104}; 112};
105 113
106struct key_security_struct { 114struct key_security_struct {
diff --git a/security/selinux/include/selinux_netlabel.h b/security/selinux/include/selinux_netlabel.h
new file mode 100644
index 000000000000..88c463eef1e1
--- /dev/null
+++ b/security/selinux/include/selinux_netlabel.h
@@ -0,0 +1,125 @@
1/*
2 * SELinux interface to the NetLabel subsystem
3 *
4 * Author : Paul Moore <paul.moore@hp.com>
5 *
6 */
7
8/*
9 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
19 * the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27#ifndef _SELINUX_NETLABEL_H_
28#define _SELINUX_NETLABEL_H_
29
30#ifdef CONFIG_NETLABEL
31void selinux_netlbl_cache_invalidate(void);
32int selinux_netlbl_socket_post_create(struct socket *sock,
33 int sock_family,
34 u32 sid);
35void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
36u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid);
37int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
38 struct sk_buff *skb,
39 struct avc_audit_data *ad);
40u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock);
41u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb);
42
43int __selinux_netlbl_inode_permission(struct inode *inode, int mask);
44/**
45 * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled
46 * @inode: the file descriptor's inode
47 * @mask: the permission mask
48 *
49 * Description:
50 * Looks at a file's inode and if it is marked as a socket protected by
51 * NetLabel then verify that the socket has been labeled, if not try to label
52 * the socket now with the inode's SID. Returns zero on success, negative
53 * values on failure.
54 *
55 */
56static inline int selinux_netlbl_inode_permission(struct inode *inode,
57 int mask)
58{
59 int rc = 0;
60 struct inode_security_struct *isec;
61 struct sk_security_struct *sksec;
62
63 if (!S_ISSOCK(inode->i_mode))
64 return 0;
65
66 isec = inode->i_security;
67 sksec = SOCKET_I(inode)->sk->sk_security;
68 down(&isec->sem);
69 if (unlikely(sksec->nlbl_state == NLBL_REQUIRE &&
70 (mask & (MAY_WRITE | MAY_APPEND))))
71 rc = __selinux_netlbl_inode_permission(inode, mask);
72 up(&isec->sem);
73
74 return rc;
75}
76#else
77static inline void selinux_netlbl_cache_invalidate(void)
78{
79 return;
80}
81
82static inline int selinux_netlbl_socket_post_create(struct socket *sock,
83 int sock_family,
84 u32 sid)
85{
86 return 0;
87}
88
89static inline void selinux_netlbl_sock_graft(struct sock *sk,
90 struct socket *sock)
91{
92 return;
93}
94
95static inline u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb,
96 u32 sock_sid)
97{
98 return SECSID_NULL;
99}
100
101static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
102 struct sk_buff *skb,
103 struct avc_audit_data *ad)
104{
105 return 0;
106}
107
108static inline u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock)
109{
110 return SECSID_NULL;
111}
112
113static inline u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb)
114{
115 return SECSID_NULL;
116}
117
118static inline int selinux_netlbl_inode_permission(struct inode *inode,
119 int mask)
120{
121 return 0;
122}
123#endif /* CONFIG_NETLABEL */
124
125#endif
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index 47024a6e1844..4b915eb60c45 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -3,6 +3,14 @@
3 * 3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil> 4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */ 5 */
6/*
7 * Updated: Hewlett-Packard <paul.moore@hp.com>
8 *
9 * Added ebitmap_export() and ebitmap_import()
10 *
11 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
12 */
13
6#include <linux/kernel.h> 14#include <linux/kernel.h>
7#include <linux/slab.h> 15#include <linux/slab.h>
8#include <linux/errno.h> 16#include <linux/errno.h>
@@ -59,6 +67,142 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
59 return 0; 67 return 0;
60} 68}
61 69
70/**
71 * ebitmap_export - Export an ebitmap to a unsigned char bitmap string
72 * @src: the ebitmap to export
73 * @dst: the resulting bitmap string
74 * @dst_len: length of dst in bytes
75 *
76 * Description:
77 * Allocate a buffer at least src->highbit bits long and export the extensible
78 * bitmap into the buffer. The bitmap string will be in little endian format,
79 * i.e. LSB first. The value returned in dst_len may not the true size of the
80 * buffer as the length of the buffer is rounded up to a multiple of MAPTYPE.
81 * The caller must free the buffer when finished. Returns zero on success,
82 * negative values on failure.
83 *
84 */
85int ebitmap_export(const struct ebitmap *src,
86 unsigned char **dst,
87 size_t *dst_len)
88{
89 size_t bitmap_len;
90 unsigned char *bitmap;
91 struct ebitmap_node *iter_node;
92 MAPTYPE node_val;
93 size_t bitmap_byte;
94 unsigned char bitmask;
95
96 bitmap_len = src->highbit / 8;
97 if (src->highbit % 7)
98 bitmap_len += 1;
99 if (bitmap_len == 0)
100 return -EINVAL;
101
102 bitmap = kzalloc((bitmap_len & ~(sizeof(MAPTYPE) - 1)) +
103 sizeof(MAPTYPE),
104 GFP_ATOMIC);
105 if (bitmap == NULL)
106 return -ENOMEM;
107
108 iter_node = src->node;
109 do {
110 bitmap_byte = iter_node->startbit / 8;
111 bitmask = 0x80;
112 node_val = iter_node->map;
113 do {
114 if (bitmask == 0) {
115 bitmap_byte++;
116 bitmask = 0x80;
117 }
118 if (node_val & (MAPTYPE)0x01)
119 bitmap[bitmap_byte] |= bitmask;
120 node_val >>= 1;
121 bitmask >>= 1;
122 } while (node_val > 0);
123 iter_node = iter_node->next;
124 } while (iter_node);
125
126 *dst = bitmap;
127 *dst_len = bitmap_len;
128 return 0;
129}
130
131/**
132 * ebitmap_import - Import an unsigned char bitmap string into an ebitmap
133 * @src: the bitmap string
134 * @src_len: the bitmap length in bytes
135 * @dst: the empty ebitmap
136 *
137 * Description:
138 * This function takes a little endian bitmap string in src and imports it into
139 * the ebitmap pointed to by dst. Returns zero on success, negative values on
140 * failure.
141 *
142 */
143int ebitmap_import(const unsigned char *src,
144 size_t src_len,
145 struct ebitmap *dst)
146{
147 size_t src_off = 0;
148 struct ebitmap_node *node_new;
149 struct ebitmap_node *node_last = NULL;
150 size_t iter;
151 size_t iter_bit;
152 size_t iter_limit;
153 unsigned char src_byte;
154
155 do {
156 iter_limit = src_len - src_off;
157 if (iter_limit >= sizeof(MAPTYPE)) {
158 if (*(MAPTYPE *)&src[src_off] == 0) {
159 src_off += sizeof(MAPTYPE);
160 continue;
161 }
162 iter_limit = sizeof(MAPTYPE);
163 } else {
164 iter = src_off;
165 src_byte = 0;
166 do {
167 src_byte |= src[iter++];
168 } while (iter < src_len && src_byte == 0);
169 if (src_byte == 0)
170 break;
171 }
172
173 node_new = kzalloc(sizeof(*node_new), GFP_ATOMIC);
174 if (unlikely(node_new == NULL)) {
175 ebitmap_destroy(dst);
176 return -ENOMEM;
177 }
178 node_new->startbit = src_off * 8;
179 iter = 0;
180 do {
181 src_byte = src[src_off++];
182 iter_bit = iter++ * 8;
183 while (src_byte != 0) {
184 if (src_byte & 0x80)
185 node_new->map |= MAPBIT << iter_bit;
186 iter_bit++;
187 src_byte <<= 1;
188 }
189 } while (iter < iter_limit);
190
191 if (node_last != NULL)
192 node_last->next = node_new;
193 else
194 dst->node = node_new;
195 node_last = node_new;
196 } while (src_off < src_len);
197
198 if (likely(node_last != NULL))
199 dst->highbit = node_last->startbit + MAPSIZE;
200 else
201 ebitmap_init(dst);
202
203 return 0;
204}
205
62int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) 206int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
63{ 207{
64 struct ebitmap_node *n1, *n2; 208 struct ebitmap_node *n1, *n2;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 8bf41055a6cb..da2d4651b10d 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -69,6 +69,12 @@ static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
69 69
70int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); 70int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
71int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); 71int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
72int ebitmap_export(const struct ebitmap *src,
73 unsigned char **dst,
74 size_t *dst_len);
75int ebitmap_import(const unsigned char *src,
76 size_t src_len,
77 struct ebitmap *dst);
72int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); 78int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
73int ebitmap_get_bit(struct ebitmap *e, unsigned long bit); 79int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
74int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); 80int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index e15f7e0399b8..119bd6078ba1 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -10,6 +10,13 @@
10 * 10 *
11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12 */ 12 */
13/*
14 * Updated: Hewlett-Packard <paul.moore@hp.com>
15 *
16 * Added support to import/export the MLS label
17 *
18 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
19 */
13 20
14#include <linux/kernel.h> 21#include <linux/kernel.h>
15#include <linux/slab.h> 22#include <linux/slab.h>
@@ -565,3 +572,152 @@ int mls_compute_sid(struct context *scontext,
565 return -EINVAL; 572 return -EINVAL;
566} 573}
567 574
575/**
576 * mls_export_lvl - Export the MLS sensitivity levels
577 * @context: the security context
578 * @low: the low sensitivity level
579 * @high: the high sensitivity level
580 *
581 * Description:
582 * Given the security context copy the low MLS sensitivity level into lvl_low
583 * and the high sensitivity level in lvl_high. The MLS levels are only
584 * exported if the pointers are not NULL, if they are NULL then that level is
585 * not exported.
586 *
587 */
588void mls_export_lvl(const struct context *context, u32 *low, u32 *high)
589{
590 if (!selinux_mls_enabled)
591 return;
592
593 if (low != NULL)
594 *low = context->range.level[0].sens - 1;
595 if (high != NULL)
596 *high = context->range.level[1].sens - 1;
597}
598
599/**
600 * mls_import_lvl - Import the MLS sensitivity levels
601 * @context: the security context
602 * @low: the low sensitivity level
603 * @high: the high sensitivity level
604 *
605 * Description:
606 * Given the security context and the two sensitivty levels, set the MLS levels
607 * in the context according the two given as parameters. Returns zero on
608 * success, negative values on failure.
609 *
610 */
611void mls_import_lvl(struct context *context, u32 low, u32 high)
612{
613 if (!selinux_mls_enabled)
614 return;
615
616 context->range.level[0].sens = low + 1;
617 context->range.level[1].sens = high + 1;
618}
619
620/**
621 * mls_export_cat - Export the MLS categories
622 * @context: the security context
623 * @low: the low category
624 * @low_len: length of the cat_low bitmap in bytes
625 * @high: the high category
626 * @high_len: length of the cat_high bitmap in bytes
627 *
628 * Description:
629 * Given the security context export the low MLS category bitmap into cat_low
630 * and the high category bitmap into cat_high. The MLS categories are only
631 * exported if the pointers are not NULL, if they are NULL then that level is
632 * not exported. The caller is responsibile for freeing the memory when
633 * finished. Returns zero on success, negative values on failure.
634 *
635 */
636int mls_export_cat(const struct context *context,
637 unsigned char **low,
638 size_t *low_len,
639 unsigned char **high,
640 size_t *high_len)
641{
642 int rc = -EPERM;
643
644 if (!selinux_mls_enabled)
645 return 0;
646
647 if (low != NULL) {
648 rc = ebitmap_export(&context->range.level[0].cat,
649 low,
650 low_len);
651 if (rc != 0)
652 goto export_cat_failure;
653 }
654 if (high != NULL) {
655 rc = ebitmap_export(&context->range.level[1].cat,
656 high,
657 high_len);
658 if (rc != 0)
659 goto export_cat_failure;
660 }
661
662 return 0;
663
664export_cat_failure:
665 if (low != NULL)
666 kfree(*low);
667 if (high != NULL)
668 kfree(*high);
669 return rc;
670}
671
672/**
673 * mls_import_cat - Import the MLS categories
674 * @context: the security context
675 * @low: the low category
676 * @low_len: length of the cat_low bitmap in bytes
677 * @high: the high category
678 * @high_len: length of the cat_high bitmap in bytes
679 *
680 * Description:
681 * Given the security context and the two category bitmap strings import the
682 * categories into the security context. The MLS categories are only imported
683 * if the pointers are not NULL, if they are NULL they are skipped. Returns
684 * zero on success, negative values on failure.
685 *
686 */
687int mls_import_cat(struct context *context,
688 const unsigned char *low,
689 size_t low_len,
690 const unsigned char *high,
691 size_t high_len)
692{
693 int rc = -EPERM;
694
695 if (!selinux_mls_enabled)
696 return 0;
697
698 if (low != NULL) {
699 rc = ebitmap_import(low,
700 low_len,
701 &context->range.level[0].cat);
702 if (rc != 0)
703 goto import_cat_failure;
704 }
705 if (high != NULL) {
706 if (high == low)
707 rc = ebitmap_cpy(&context->range.level[1].cat,
708 &context->range.level[0].cat);
709 else
710 rc = ebitmap_import(high,
711 high_len,
712 &context->range.level[1].cat);
713 if (rc != 0)
714 goto import_cat_failure;
715 }
716
717 return 0;
718
719import_cat_failure:
720 ebitmap_destroy(&context->range.level[0].cat);
721 ebitmap_destroy(&context->range.level[1].cat);
722 return rc;
723}
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 90c5e88987fa..df6032c6d492 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -10,6 +10,13 @@
10 * 10 *
11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12 */ 12 */
13/*
14 * Updated: Hewlett-Packard <paul.moore@hp.com>
15 *
16 * Added support to import/export the MLS label
17 *
18 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
19 */
13 20
14#ifndef _SS_MLS_H_ 21#ifndef _SS_MLS_H_
15#define _SS_MLS_H_ 22#define _SS_MLS_H_
@@ -62,5 +69,19 @@ int mls_compute_sid(struct context *scontext,
62int mls_setup_user_range(struct context *fromcon, struct user_datum *user, 69int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
63 struct context *usercon); 70 struct context *usercon);
64 71
72void mls_export_lvl(const struct context *context, u32 *low, u32 *high);
73void mls_import_lvl(struct context *context, u32 low, u32 high);
74
75int mls_export_cat(const struct context *context,
76 unsigned char **low,
77 size_t *low_len,
78 unsigned char **high,
79 size_t *high_len);
80int mls_import_cat(struct context *context,
81 const unsigned char *low,
82 size_t low_len,
83 const unsigned char *high,
84 size_t high_len);
85
65#endif /* _SS_MLS_H */ 86#endif /* _SS_MLS_H */
66 87
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index b00ec69f0ffd..910afa1ffc31 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -13,6 +13,11 @@
13 * 13 *
14 * Added conditional policy language extensions 14 * Added conditional policy language extensions
15 * 15 *
16 * Updated: Hewlett-Packard <paul.moore@hp.com>
17 *
18 * Added support for NetLabel
19 *
20 * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
16 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 21 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
17 * Copyright (C) 2003 - 2004 Tresys Technology, LLC 22 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
18 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 23 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
@@ -29,6 +34,8 @@
29#include <linux/sched.h> 34#include <linux/sched.h>
30#include <linux/audit.h> 35#include <linux/audit.h>
31#include <linux/mutex.h> 36#include <linux/mutex.h>
37#include <net/sock.h>
38#include <net/netlabel.h>
32 39
33#include "flask.h" 40#include "flask.h"
34#include "avc.h" 41#include "avc.h"
@@ -40,6 +47,8 @@
40#include "services.h" 47#include "services.h"
41#include "conditional.h" 48#include "conditional.h"
42#include "mls.h" 49#include "mls.h"
50#include "objsec.h"
51#include "selinux_netlabel.h"
43 52
44extern void selnl_notify_policyload(u32 seqno); 53extern void selnl_notify_policyload(u32 seqno);
45unsigned int policydb_loaded_version; 54unsigned int policydb_loaded_version;
@@ -1241,6 +1250,7 @@ int security_load_policy(void *data, size_t len)
1241 selinux_complete_init(); 1250 selinux_complete_init();
1242 avc_ss_reset(seqno); 1251 avc_ss_reset(seqno);
1243 selnl_notify_policyload(seqno); 1252 selnl_notify_policyload(seqno);
1253 selinux_netlbl_cache_invalidate();
1244 return 0; 1254 return 0;
1245 } 1255 }
1246 1256
@@ -1295,6 +1305,7 @@ int security_load_policy(void *data, size_t len)
1295 1305
1296 avc_ss_reset(seqno); 1306 avc_ss_reset(seqno);
1297 selnl_notify_policyload(seqno); 1307 selnl_notify_policyload(seqno);
1308 selinux_netlbl_cache_invalidate();
1298 1309
1299 return 0; 1310 return 0;
1300 1311
@@ -2133,3 +2144,480 @@ void selinux_audit_set_callback(int (*callback)(void))
2133{ 2144{
2134 aurule_callback = callback; 2145 aurule_callback = callback;
2135} 2146}
2147
2148#ifdef CONFIG_NETLABEL
2149/*
2150 * This is the structure we store inside the NetLabel cache block.
2151 */
2152#define NETLBL_CACHE(x) ((struct netlbl_cache *)(x))
2153#define NETLBL_CACHE_T_NONE 0
2154#define NETLBL_CACHE_T_SID 1
2155#define NETLBL_CACHE_T_MLS 2
2156struct netlbl_cache {
2157 u32 type;
2158 union {
2159 u32 sid;
2160 struct mls_range mls_label;
2161 } data;
2162};
2163
2164/**
2165 * selinux_netlbl_cache_free - Free the NetLabel cached data
2166 * @data: the data to free
2167 *
2168 * Description:
2169 * This function is intended to be used as the free() callback inside the
2170 * netlbl_lsm_cache structure.
2171 *
2172 */
2173static void selinux_netlbl_cache_free(const void *data)
2174{
2175 struct netlbl_cache *cache = NETLBL_CACHE(data);
2176 switch (cache->type) {
2177 case NETLBL_CACHE_T_MLS:
2178 ebitmap_destroy(&cache->data.mls_label.level[0].cat);
2179 break;
2180 }
2181 kfree(data);
2182}
2183
2184/**
2185 * selinux_netlbl_cache_add - Add an entry to the NetLabel cache
2186 * @skb: the packet
2187 * @ctx: the SELinux context
2188 *
2189 * Description:
2190 * Attempt to cache the context in @ctx, which was derived from the packet in
2191 * @skb, in the NetLabel subsystem cache.
2192 *
2193 */
2194static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx)
2195{
2196 struct netlbl_cache *cache = NULL;
2197 struct netlbl_lsm_secattr secattr;
2198
2199 netlbl_secattr_init(&secattr);
2200
2201 cache = kzalloc(sizeof(*cache), GFP_ATOMIC);
2202 if (cache == NULL)
2203 goto netlbl_cache_add_failure;
2204 secattr.cache.free = selinux_netlbl_cache_free;
2205 secattr.cache.data = (void *)cache;
2206
2207 cache->type = NETLBL_CACHE_T_MLS;
2208 if (ebitmap_cpy(&cache->data.mls_label.level[0].cat,
2209 &ctx->range.level[0].cat) != 0)
2210 goto netlbl_cache_add_failure;
2211 cache->data.mls_label.level[1].cat.highbit =
2212 cache->data.mls_label.level[0].cat.highbit;
2213 cache->data.mls_label.level[1].cat.node =
2214 cache->data.mls_label.level[0].cat.node;
2215 cache->data.mls_label.level[0].sens = ctx->range.level[0].sens;
2216 cache->data.mls_label.level[1].sens = ctx->range.level[0].sens;
2217
2218 if (netlbl_cache_add(skb, &secattr) != 0)
2219 goto netlbl_cache_add_failure;
2220
2221 return;
2222
2223netlbl_cache_add_failure:
2224 netlbl_secattr_destroy(&secattr, 1);
2225}
2226
2227/**
2228 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
2229 *
2230 * Description:
2231 * Invalidate the NetLabel security attribute mapping cache.
2232 *
2233 */
2234void selinux_netlbl_cache_invalidate(void)
2235{
2236 netlbl_cache_invalidate();
2237}
2238
2239/**
2240 * selinux_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
2241 * @skb: the network packet
2242 * @secattr: the NetLabel packet security attributes
2243 * @base_sid: the SELinux SID to use as a context for MLS only attributes
2244 * @sid: the SELinux SID
2245 *
2246 * Description:
2247 * Convert the given NetLabel packet security attributes in @secattr into a
2248 * SELinux SID. If the @secattr field does not contain a full SELinux
2249 * SID/context then use the context in @base_sid as the foundation. If @skb
2250 * is not NULL attempt to cache as much data as possibile. Returns zero on
2251 * success, negative values on failure.
2252 *
2253 */
2254static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb,
2255 struct netlbl_lsm_secattr *secattr,
2256 u32 base_sid,
2257 u32 *sid)
2258{
2259 int rc = -EIDRM;
2260 struct context *ctx;
2261 struct context ctx_new;
2262 struct netlbl_cache *cache;
2263
2264 POLICY_RDLOCK;
2265
2266 if (secattr->cache.data) {
2267 cache = NETLBL_CACHE(secattr->cache.data);
2268 switch (cache->type) {
2269 case NETLBL_CACHE_T_SID:
2270 *sid = cache->data.sid;
2271 rc = 0;
2272 break;
2273 case NETLBL_CACHE_T_MLS:
2274 ctx = sidtab_search(&sidtab, base_sid);
2275 if (ctx == NULL)
2276 goto netlbl_secattr_to_sid_return;
2277
2278 ctx_new.user = ctx->user;
2279 ctx_new.role = ctx->role;
2280 ctx_new.type = ctx->type;
2281 ctx_new.range.level[0].sens =
2282 cache->data.mls_label.level[0].sens;
2283 ctx_new.range.level[0].cat.highbit =
2284 cache->data.mls_label.level[0].cat.highbit;
2285 ctx_new.range.level[0].cat.node =
2286 cache->data.mls_label.level[0].cat.node;
2287 ctx_new.range.level[1].sens =
2288 cache->data.mls_label.level[1].sens;
2289 ctx_new.range.level[1].cat.highbit =
2290 cache->data.mls_label.level[1].cat.highbit;
2291 ctx_new.range.level[1].cat.node =
2292 cache->data.mls_label.level[1].cat.node;
2293
2294 rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
2295 break;
2296 default:
2297 goto netlbl_secattr_to_sid_return;
2298 }
2299 } else if (secattr->mls_lvl_vld) {
2300 ctx = sidtab_search(&sidtab, base_sid);
2301 if (ctx == NULL)
2302 goto netlbl_secattr_to_sid_return;
2303
2304 ctx_new.user = ctx->user;
2305 ctx_new.role = ctx->role;
2306 ctx_new.type = ctx->type;
2307 mls_import_lvl(&ctx_new, secattr->mls_lvl, secattr->mls_lvl);
2308 if (secattr->mls_cat) {
2309 if (mls_import_cat(&ctx_new,
2310 secattr->mls_cat,
2311 secattr->mls_cat_len,
2312 NULL,
2313 0) != 0)
2314 goto netlbl_secattr_to_sid_return;
2315 ctx_new.range.level[1].cat.highbit =
2316 ctx_new.range.level[0].cat.highbit;
2317 ctx_new.range.level[1].cat.node =
2318 ctx_new.range.level[0].cat.node;
2319 } else {
2320 ebitmap_init(&ctx_new.range.level[0].cat);
2321 ebitmap_init(&ctx_new.range.level[1].cat);
2322 }
2323 if (mls_context_isvalid(&policydb, &ctx_new) != 1)
2324 goto netlbl_secattr_to_sid_return_cleanup;
2325
2326 rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
2327 if (rc != 0)
2328 goto netlbl_secattr_to_sid_return_cleanup;
2329
2330 if (skb != NULL)
2331 selinux_netlbl_cache_add(skb, &ctx_new);
2332 ebitmap_destroy(&ctx_new.range.level[0].cat);
2333 } else {
2334 *sid = SECINITSID_UNLABELED;
2335 rc = 0;
2336 }
2337
2338netlbl_secattr_to_sid_return:
2339 POLICY_RDUNLOCK;
2340 return rc;
2341netlbl_secattr_to_sid_return_cleanup:
2342 ebitmap_destroy(&ctx_new.range.level[0].cat);
2343 goto netlbl_secattr_to_sid_return;
2344}
2345
2346/**
2347 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
2348 * @skb: the packet
2349 * @base_sid: the SELinux SID to use as a context for MLS only attributes
2350 * @sid: the SID
2351 *
2352 * Description:
2353 * Call the NetLabel mechanism to get the security attributes of the given
2354 * packet and use those attributes to determine the correct context/SID to
2355 * assign to the packet. Returns zero on success, negative values on failure.
2356 *
2357 */
2358static int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
2359 u32 base_sid,
2360 u32 *sid)
2361{
2362 int rc;
2363 struct netlbl_lsm_secattr secattr;
2364
2365 netlbl_secattr_init(&secattr);
2366 rc = netlbl_skbuff_getattr(skb, &secattr);
2367 if (rc == 0)
2368 rc = selinux_netlbl_secattr_to_sid(skb,
2369 &secattr,
2370 base_sid,
2371 sid);
2372 netlbl_secattr_destroy(&secattr, 0);
2373
2374 return rc;
2375}
2376
2377/**
2378 * selinux_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
2379 * @sock: the socket to label
2380 * @sid: the SID to use
2381 *
2382 * Description:
2383 * Attempt to label a socket using the NetLabel mechanism using the given
2384 * SID. Returns zero values on success, negative values on failure.
2385 *
2386 */
2387static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
2388{
2389 int rc = -ENOENT;
2390 struct sk_security_struct *sksec = sock->sk->sk_security;
2391 struct netlbl_lsm_secattr secattr;
2392 struct context *ctx;
2393
2394 if (!ss_initialized)
2395 return 0;
2396
2397 POLICY_RDLOCK;
2398
2399 ctx = sidtab_search(&sidtab, sid);
2400 if (ctx == NULL)
2401 goto netlbl_socket_setsid_return;
2402
2403 netlbl_secattr_init(&secattr);
2404 secattr.domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
2405 GFP_ATOMIC);
2406 mls_export_lvl(ctx, &secattr.mls_lvl, NULL);
2407 secattr.mls_lvl_vld = 1;
2408 mls_export_cat(ctx,
2409 &secattr.mls_cat,
2410 &secattr.mls_cat_len,
2411 NULL,
2412 NULL);
2413
2414 rc = netlbl_socket_setattr(sock, &secattr);
2415 if (rc == 0)
2416 sksec->nlbl_state = NLBL_LABELED;
2417
2418 netlbl_secattr_destroy(&secattr, 0);
2419
2420netlbl_socket_setsid_return:
2421 POLICY_RDUNLOCK;
2422 return rc;
2423}
2424
2425/**
2426 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
2427 * @sock: the socket to label
2428 * @sock_family: the socket family
2429 * @sid: the SID to use
2430 *
2431 * Description:
2432 * Attempt to label a socket using the NetLabel mechanism using the given
2433 * SID. Returns zero values on success, negative values on failure.
2434 *
2435 */
2436int selinux_netlbl_socket_post_create(struct socket *sock,
2437 int sock_family,
2438 u32 sid)
2439{
2440 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
2441 struct sk_security_struct *sksec = sock->sk->sk_security;
2442
2443 if (sock_family != PF_INET)
2444 return 0;
2445
2446 sksec->sclass = isec->sclass;
2447 sksec->nlbl_state = NLBL_REQUIRE;
2448 return selinux_netlbl_socket_setsid(sock, sid);
2449}
2450
2451/**
2452 * selinux_netlbl_sock_graft - Netlabel the new socket
2453 * @sk: the new connection
2454 * @sock: the new socket
2455 *
2456 * Description:
2457 * The connection represented by @sk is being grafted onto @sock so set the
2458 * socket's NetLabel to match the SID of @sk.
2459 *
2460 */
2461void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
2462{
2463 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
2464 struct sk_security_struct *sksec = sk->sk_security;
2465
2466 if (sk->sk_family != PF_INET)
2467 return;
2468
2469 sksec->nlbl_state = NLBL_REQUIRE;
2470 sksec->peer_sid = sksec->sid;
2471 sksec->sclass = isec->sclass;
2472
2473 /* Try to set the NetLabel on the socket to save time later, if we fail
2474 * here we will pick up the pieces in later calls to
2475 * selinux_netlbl_inode_permission(). */
2476 selinux_netlbl_socket_setsid(sock, sksec->sid);
2477}
2478
2479/**
2480 * selinux_netlbl_inet_conn_request - Handle a new connection request
2481 * @skb: the packet
2482 * @sock_sid: the SID of the parent socket
2483 *
2484 * Description:
2485 * If present, use the security attributes of the packet in @skb and the
2486 * parent sock's SID to arrive at a SID for the new child sock. Returns the
2487 * SID of the connection or SECSID_NULL on failure.
2488 *
2489 */
2490u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid)
2491{
2492 int rc;
2493 u32 peer_sid;
2494
2495 rc = selinux_netlbl_skbuff_getsid(skb, sock_sid, &peer_sid);
2496 if (rc != 0)
2497 return SECSID_NULL;
2498
2499 if (peer_sid == SECINITSID_UNLABELED)
2500 return SECSID_NULL;
2501
2502 return peer_sid;
2503}
2504
2505/**
2506 * __selinux_netlbl_inode_permission - Label a socket using NetLabel
2507 * @inode: the file descriptor's inode
2508 * @mask: the permission mask
2509 *
2510 * Description:
2511 * Try to label a socket with the inode's SID using NetLabel. Returns zero on
2512 * success, negative values on failure.
2513 *
2514 */
2515int __selinux_netlbl_inode_permission(struct inode *inode, int mask)
2516{
2517 int rc;
2518 struct socket *sock = SOCKET_I(inode);
2519 struct sk_security_struct *sksec = sock->sk->sk_security;
2520
2521 lock_sock(sock->sk);
2522 rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
2523 release_sock(sock->sk);
2524
2525 return rc;
2526}
2527
2528/**
2529 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
2530 * @sksec: the sock's sk_security_struct
2531 * @skb: the packet
2532 * @ad: the audit data
2533 *
2534 * Description:
2535 * Fetch the NetLabel security attributes from @skb and perform an access check
2536 * against the receiving socket. Returns zero on success, negative values on
2537 * error.
2538 *
2539 */
2540int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
2541 struct sk_buff *skb,
2542 struct avc_audit_data *ad)
2543{
2544 int rc;
2545 u32 netlbl_sid;
2546 u32 recv_perm;
2547
2548 rc = selinux_netlbl_skbuff_getsid(skb, sksec->sid, &netlbl_sid);
2549 if (rc != 0)
2550 return rc;
2551
2552 if (netlbl_sid == SECINITSID_UNLABELED)
2553 return 0;
2554
2555 switch (sksec->sclass) {
2556 case SECCLASS_UDP_SOCKET:
2557 recv_perm = UDP_SOCKET__RECV_MSG;
2558 break;
2559 case SECCLASS_TCP_SOCKET:
2560 recv_perm = TCP_SOCKET__RECV_MSG;
2561 break;
2562 default:
2563 recv_perm = RAWIP_SOCKET__RECV_MSG;
2564 }
2565
2566 rc = avc_has_perm(sksec->sid,
2567 netlbl_sid,
2568 sksec->sclass,
2569 recv_perm,
2570 ad);
2571 if (rc == 0)
2572 return 0;
2573
2574 netlbl_skbuff_err(skb, rc);
2575 return rc;
2576}
2577
2578/**
2579 * selinux_netlbl_socket_peersid - Return the peer SID of a connected socket
2580 * @sock: the socket
2581 *
2582 * Description:
2583 * Examine @sock to find the connected peer's SID. Returns the SID on success
2584 * or SECSID_NULL on error.
2585 *
2586 */
2587u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock)
2588{
2589 struct sk_security_struct *sksec = sock->sk->sk_security;
2590
2591 if (sksec->peer_sid == SECINITSID_UNLABELED)
2592 return SECSID_NULL;
2593
2594 return sksec->peer_sid;
2595}
2596
2597/**
2598 * selinux_netlbl_socket_getpeersec_dgram - Return the SID of a NetLabel packet
2599 * @skb: the packet
2600 *
2601 * Description:
2602 * Examine @skb to find the SID assigned to it by NetLabel. Returns the SID on
2603 * success, SECSID_NULL on error.
2604 *
2605 */
2606u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb)
2607{
2608 int peer_sid;
2609 struct sock *sk = skb->sk;
2610 struct inode_security_struct *isec;
2611
2612 if (sk == NULL || sk->sk_socket == NULL)
2613 return SECSID_NULL;
2614
2615 isec = SOCK_INODE(sk->sk_socket)->i_security;
2616 if (selinux_netlbl_skbuff_getsid(skb, isec->sid, &peer_sid) != 0)
2617 return SECSID_NULL;
2618 if (peer_sid == SECINITSID_UNLABELED)
2619 return SECSID_NULL;
2620
2621 return peer_sid;
2622}
2623#endif /* CONFIG_NETLABEL */