aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2006-01-12 17:47:08 -0500
committerSteve French <sfrench@us.ibm.com>2006-01-12 17:47:08 -0500
commit94bc2be31a01a3055ec94176e595dfe208e92d3b (patch)
treeebfbe81c6718a6390bfa1b99c6d228237d818576 /security/selinux
parentc32a0b689cb9cc160cfcd19735bbf50bb70c6ef4 (diff)
parent58cba4650a7a414eabd2b40cc9d8e45fcdf192d9 (diff)
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/Makefile2
-rw-r--r--security/selinux/hooks.c41
-rw-r--r--security/selinux/include/av_perm_to_string.h1
-rw-r--r--security/selinux/include/av_permissions.h1
-rw-r--r--security/selinux/include/xfrm.h54
-rw-r--r--security/selinux/selinuxfs.c6
-rw-r--r--security/selinux/ss/avtab.c2
-rw-r--r--security/selinux/ss/policydb.c2
-rw-r--r--security/selinux/ss/services.c6
-rw-r--r--security/selinux/xfrm.c305
10 files changed, 411 insertions, 9 deletions
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index b038cd0fae2e..06d54d9d20a5 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -8,5 +8,7 @@ selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o
8 8
9selinux-$(CONFIG_SECURITY_NETWORK) += netif.o 9selinux-$(CONFIG_SECURITY_NETWORK) += netif.o
10 10
11selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
12
11EXTRA_CFLAGS += -Isecurity/selinux/include 13EXTRA_CFLAGS += -Isecurity/selinux/include
12 14
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index fc774436a264..6647204e4636 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -73,6 +73,7 @@
73#include "avc.h" 73#include "avc.h"
74#include "objsec.h" 74#include "objsec.h"
75#include "netif.h" 75#include "netif.h"
76#include "xfrm.h"
76 77
77#define XATTR_SELINUX_SUFFIX "selinux" 78#define XATTR_SELINUX_SUFFIX "selinux"
78#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX 79#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
@@ -1662,7 +1663,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
1662 continue; 1663 continue;
1663 } 1664 }
1664 if (devnull) { 1665 if (devnull) {
1665 rcuref_inc(&devnull->f_count); 1666 get_file(devnull);
1666 } else { 1667 } else {
1667 devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR); 1668 devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
1668 if (!devnull) { 1669 if (!devnull) {
@@ -3349,6 +3350,10 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
3349 err = avc_has_perm(sock_sid, port_sid, 3350 err = avc_has_perm(sock_sid, port_sid,
3350 sock_class, recv_perm, &ad); 3351 sock_class, recv_perm, &ad);
3351 } 3352 }
3353
3354 if (!err)
3355 err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
3356
3352out: 3357out:
3353 return err; 3358 return err;
3354} 3359}
@@ -3401,6 +3406,24 @@ static void selinux_sk_free_security(struct sock *sk)
3401 sk_free_security(sk); 3406 sk_free_security(sk);
3402} 3407}
3403 3408
3409static unsigned int selinux_sk_getsid_security(struct sock *sk, struct flowi *fl, u8 dir)
3410{
3411 struct inode_security_struct *isec;
3412 u32 sock_sid = SECINITSID_ANY_SOCKET;
3413
3414 if (!sk)
3415 return selinux_no_sk_sid(fl);
3416
3417 read_lock_bh(&sk->sk_callback_lock);
3418 isec = get_sock_isec(sk);
3419
3420 if (isec)
3421 sock_sid = isec->sid;
3422
3423 read_unlock_bh(&sk->sk_callback_lock);
3424 return sock_sid;
3425}
3426
3404static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) 3427static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
3405{ 3428{
3406 int err = 0; 3429 int err = 0;
@@ -3536,6 +3559,11 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
3536 send_perm, &ad) ? NF_DROP : NF_ACCEPT; 3559 send_perm, &ad) ? NF_DROP : NF_ACCEPT;
3537 } 3560 }
3538 3561
3562 if (err != NF_ACCEPT)
3563 goto out;
3564
3565 err = selinux_xfrm_postroute_last(isec->sid, skb);
3566
3539out: 3567out:
3540 return err; 3568 return err;
3541} 3569}
@@ -4380,6 +4408,16 @@ static struct security_operations selinux_ops = {
4380 .socket_getpeersec = selinux_socket_getpeersec, 4408 .socket_getpeersec = selinux_socket_getpeersec,
4381 .sk_alloc_security = selinux_sk_alloc_security, 4409 .sk_alloc_security = selinux_sk_alloc_security,
4382 .sk_free_security = selinux_sk_free_security, 4410 .sk_free_security = selinux_sk_free_security,
4411 .sk_getsid = selinux_sk_getsid_security,
4412#endif
4413
4414#ifdef CONFIG_SECURITY_NETWORK_XFRM
4415 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
4416 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
4417 .xfrm_policy_free_security = selinux_xfrm_policy_free,
4418 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
4419 .xfrm_state_free_security = selinux_xfrm_state_free,
4420 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
4383#endif 4421#endif
4384}; 4422};
4385 4423
@@ -4491,6 +4529,7 @@ static int __init selinux_nf_ip_init(void)
4491 panic("SELinux: nf_register_hook for IPv6: error %d\n", err); 4529 panic("SELinux: nf_register_hook for IPv6: error %d\n", err);
4492 4530
4493#endif /* IPV6 */ 4531#endif /* IPV6 */
4532
4494out: 4533out:
4495 return err; 4534 return err;
4496} 4535}
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index 1deb59e1b762..591e98d9315a 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -238,3 +238,4 @@
238 S_(SECCLASS_NSCD, NSCD__SHMEMHOST, "shmemhost") 238 S_(SECCLASS_NSCD, NSCD__SHMEMHOST, "shmemhost")
239 S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto") 239 S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto")
240 S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom") 240 S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom")
241 S_(SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, "setcontext")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index a78b5d59c9fc..d7f02edf3930 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -908,6 +908,7 @@
908 908
909#define ASSOCIATION__SENDTO 0x00000001UL 909#define ASSOCIATION__SENDTO 0x00000001UL
910#define ASSOCIATION__RECVFROM 0x00000002UL 910#define ASSOCIATION__RECVFROM 0x00000002UL
911#define ASSOCIATION__SETCONTEXT 0x00000004UL
911 912
912#define NETLINK_KOBJECT_UEVENT_SOCKET__IOCTL 0x00000001UL 913#define NETLINK_KOBJECT_UEVENT_SOCKET__IOCTL 0x00000001UL
913#define NETLINK_KOBJECT_UEVENT_SOCKET__READ 0x00000002UL 914#define NETLINK_KOBJECT_UEVENT_SOCKET__READ 0x00000002UL
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
new file mode 100644
index 000000000000..8e87996c6dd5
--- /dev/null
+++ b/security/selinux/include/xfrm.h
@@ -0,0 +1,54 @@
1/*
2 * SELinux support for the XFRM LSM hooks
3 *
4 * Author : Trent Jaeger, <jaegert@us.ibm.com>
5 */
6#ifndef _SELINUX_XFRM_H_
7#define _SELINUX_XFRM_H_
8
9int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx);
10int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new);
11void selinux_xfrm_policy_free(struct xfrm_policy *xp);
12int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx);
13void selinux_xfrm_state_free(struct xfrm_state *x);
14int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir);
15
16/*
17 * Extract the security blob from the sock (it's actually on the socket)
18 */
19static inline struct inode_security_struct *get_sock_isec(struct sock *sk)
20{
21 if (!sk->sk_socket)
22 return NULL;
23
24 return SOCK_INODE(sk->sk_socket)->i_security;
25}
26
27
28static inline u32 selinux_no_sk_sid(struct flowi *fl)
29{
30 /* NOTE: no sock occurs on ICMP reply, forwards, ... */
31 /* icmp_reply: authorize as kernel packet */
32 if (fl && fl->proto == IPPROTO_ICMP) {
33 return SECINITSID_KERNEL;
34 }
35
36 return SECINITSID_ANY_SOCKET;
37}
38
39#ifdef CONFIG_SECURITY_NETWORK_XFRM
40int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb);
41int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb);
42#else
43static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
44{
45 return 0;
46}
47
48static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
49{
50 return NF_ACCEPT;
51}
52#endif
53
54#endif /* _SELINUX_XFRM_H_ */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 0e1352a555c8..b5fa02d17b1e 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -376,7 +376,7 @@ static ssize_t selinux_transaction_write(struct file *file, const char __user *b
376 char *data; 376 char *data;
377 ssize_t rv; 377 ssize_t rv;
378 378
379 if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino]) 379 if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
380 return -EINVAL; 380 return -EINVAL;
381 381
382 data = simple_transaction_get(file, buf, size); 382 data = simple_transaction_get(file, buf, size);
@@ -889,7 +889,7 @@ static void sel_remove_bools(struct dentry *de)
889 spin_lock(&dcache_lock); 889 spin_lock(&dcache_lock);
890 node = de->d_subdirs.next; 890 node = de->d_subdirs.next;
891 while (node != &de->d_subdirs) { 891 while (node != &de->d_subdirs) {
892 struct dentry *d = list_entry(node, struct dentry, d_child); 892 struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
893 list_del_init(node); 893 list_del_init(node);
894 894
895 if (d->d_inode) { 895 if (d->d_inode) {
@@ -1161,7 +1161,7 @@ static int sel_make_avc_files(struct dentry *dir)
1161#endif 1161#endif
1162 }; 1162 };
1163 1163
1164 for (i = 0; i < sizeof (files) / sizeof (files[0]); i++) { 1164 for (i = 0; i < ARRAY_SIZE(files); i++) {
1165 struct inode *inode; 1165 struct inode *inode;
1166 struct dentry *dentry; 1166 struct dentry *dentry;
1167 1167
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index dde094feb20d..d049c7acbc8b 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -359,7 +359,7 @@ int avtab_read_item(void *fp, u32 vers, struct avtab *a,
359 return -1; 359 return -1;
360 } 360 }
361 361
362 for (i = 0; i < sizeof(spec_order)/sizeof(u16); i++) { 362 for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
363 if (val & spec_order[i]) { 363 if (val & spec_order[i]) {
364 key.specified = spec_order[i] | enabled; 364 key.specified = spec_order[i] | enabled;
365 datum.data = le32_to_cpu(buf32[items++]); 365 datum.data = le32_to_cpu(buf32[items++]);
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 0ac311dc8371..0111990ba837 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -103,7 +103,7 @@ static struct policydb_compat_info *policydb_lookup_compat(int version)
103 int i; 103 int i;
104 struct policydb_compat_info *info = NULL; 104 struct policydb_compat_info *info = NULL;
105 105
106 for (i = 0; i < sizeof(policydb_compat)/sizeof(*info); i++) { 106 for (i = 0; i < ARRAY_SIZE(policydb_compat); i++) {
107 if (policydb_compat[i].version == version) { 107 if (policydb_compat[i].version == version) {
108 info = &policydb_compat[i]; 108 info = &policydb_compat[i];
109 break; 109 break;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 44eb4d74908d..8a764928ff4b 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1712,11 +1712,11 @@ int security_get_bools(int *len, char ***names, int **values)
1712 goto out; 1712 goto out;
1713 } 1713 }
1714 1714
1715 *names = (char**)kcalloc(*len, sizeof(char*), GFP_ATOMIC); 1715 *names = kcalloc(*len, sizeof(char*), GFP_ATOMIC);
1716 if (!*names) 1716 if (!*names)
1717 goto err; 1717 goto err;
1718 1718
1719 *values = (int*)kcalloc(*len, sizeof(int), GFP_ATOMIC); 1719 *values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
1720 if (!*values) 1720 if (!*values)
1721 goto err; 1721 goto err;
1722 1722
@@ -1724,7 +1724,7 @@ int security_get_bools(int *len, char ***names, int **values)
1724 size_t name_len; 1724 size_t name_len;
1725 (*values)[i] = policydb.bool_val_to_struct[i]->state; 1725 (*values)[i] = policydb.bool_val_to_struct[i]->state;
1726 name_len = strlen(policydb.p_bool_val_to_name[i]) + 1; 1726 name_len = strlen(policydb.p_bool_val_to_name[i]) + 1;
1727 (*names)[i] = (char*)kmalloc(sizeof(char) * name_len, GFP_ATOMIC); 1727 (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
1728 if (!(*names)[i]) 1728 if (!(*names)[i])
1729 goto err; 1729 goto err;
1730 strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len); 1730 strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len);
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
new file mode 100644
index 000000000000..b2af7ca496c1
--- /dev/null
+++ b/security/selinux/xfrm.c
@@ -0,0 +1,305 @@
1/*
2 * NSA Security-Enhanced Linux (SELinux) security module
3 *
4 * This file contains the SELinux XFRM hook function implementations.
5 *
6 * Authors: Serge Hallyn <sergeh@us.ibm.com>
7 * Trent Jaeger <jaegert@us.ibm.com>
8 *
9 * Copyright (C) 2005 International Business Machines Corporation
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 version 2,
13 * as published by the Free Software Foundation.
14 */
15
16/*
17 * USAGE:
18 * NOTES:
19 * 1. Make sure to enable the following options in your kernel config:
20 * CONFIG_SECURITY=y
21 * CONFIG_SECURITY_NETWORK=y
22 * CONFIG_SECURITY_NETWORK_XFRM=y
23 * CONFIG_SECURITY_SELINUX=m/y
24 * ISSUES:
25 * 1. Caching packets, so they are not dropped during negotiation
26 * 2. Emulating a reasonable SO_PEERSEC across machines
27 * 3. Testing addition of sk_policy's with security context via setsockopt
28 */
29#include <linux/config.h>
30#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/init.h>
33#include <linux/security.h>
34#include <linux/types.h>
35#include <linux/netfilter.h>
36#include <linux/netfilter_ipv4.h>
37#include <linux/netfilter_ipv6.h>
38#include <linux/ip.h>
39#include <linux/tcp.h>
40#include <linux/skbuff.h>
41#include <linux/xfrm.h>
42#include <net/xfrm.h>
43#include <net/checksum.h>
44#include <net/udp.h>
45#include <asm/semaphore.h>
46
47#include "avc.h"
48#include "objsec.h"
49#include "xfrm.h"
50
51
52/*
53 * Returns true if an LSM/SELinux context
54 */
55static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx)
56{
57 return (ctx &&
58 (ctx->ctx_doi == XFRM_SC_DOI_LSM) &&
59 (ctx->ctx_alg == XFRM_SC_ALG_SELINUX));
60}
61
62/*
63 * Returns true if the xfrm contains a security blob for SELinux
64 */
65static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
66{
67 return selinux_authorizable_ctx(x->security);
68}
69
70/*
71 * LSM hook implementation that authorizes that a socket can be used
72 * with the corresponding xfrm_sec_ctx and direction.
73 */
74int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir)
75{
76 int rc = 0;
77 u32 sel_sid = SECINITSID_UNLABELED;
78 struct xfrm_sec_ctx *ctx;
79
80 /* Context sid is either set to label or ANY_ASSOC */
81 if ((ctx = xp->security)) {
82 if (!selinux_authorizable_ctx(ctx))
83 return -EINVAL;
84
85 sel_sid = ctx->ctx_sid;
86 }
87
88 rc = avc_has_perm(sk_sid, sel_sid, SECCLASS_ASSOCIATION,
89 ((dir == FLOW_DIR_IN) ? ASSOCIATION__RECVFROM :
90 ((dir == FLOW_DIR_OUT) ? ASSOCIATION__SENDTO :
91 (ASSOCIATION__SENDTO | ASSOCIATION__RECVFROM))),
92 NULL);
93
94 return rc;
95}
96
97/*
98 * Security blob allocation for xfrm_policy and xfrm_state
99 * CTX does not have a meaningful value on input
100 */
101static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *uctx)
102{
103 int rc = 0;
104 struct task_security_struct *tsec = current->security;
105 struct xfrm_sec_ctx *ctx;
106
107 BUG_ON(!uctx);
108 BUG_ON(uctx->ctx_doi != XFRM_SC_ALG_SELINUX);
109
110 if (uctx->ctx_len >= PAGE_SIZE)
111 return -ENOMEM;
112
113 *ctxp = ctx = kmalloc(sizeof(*ctx) +
114 uctx->ctx_len,
115 GFP_KERNEL);
116
117 if (!ctx)
118 return -ENOMEM;
119
120 ctx->ctx_doi = uctx->ctx_doi;
121 ctx->ctx_len = uctx->ctx_len;
122 ctx->ctx_alg = uctx->ctx_alg;
123
124 memcpy(ctx->ctx_str,
125 uctx+1,
126 ctx->ctx_len);
127 rc = security_context_to_sid(ctx->ctx_str,
128 ctx->ctx_len,
129 &ctx->ctx_sid);
130
131 if (rc)
132 goto out;
133
134 /*
135 * Does the subject have permission to set security or permission to
136 * do the relabel?
137 * Must be permitted to relabel from default socket type (process type)
138 * to specified context
139 */
140 rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
141 SECCLASS_ASSOCIATION,
142 ASSOCIATION__SETCONTEXT, NULL);
143 if (rc)
144 goto out;
145
146 return rc;
147
148out:
149 *ctxp = NULL;
150 kfree(ctx);
151 return rc;
152}
153
154/*
155 * LSM hook implementation that allocs and transfers uctx spec to
156 * xfrm_policy.
157 */
158int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *uctx)
159{
160 int err;
161
162 BUG_ON(!xp);
163
164 err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx);
165 return err;
166}
167
168
169/*
170 * LSM hook implementation that copies security data structure from old to
171 * new for policy cloning.
172 */
173int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new)
174{
175 struct xfrm_sec_ctx *old_ctx, *new_ctx;
176
177 old_ctx = old->security;
178
179 if (old_ctx) {
180 new_ctx = new->security = kmalloc(sizeof(*new_ctx) +
181 old_ctx->ctx_len,
182 GFP_KERNEL);
183
184 if (!new_ctx)
185 return -ENOMEM;
186
187 memcpy(new_ctx, old_ctx, sizeof(*new_ctx));
188 memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len);
189 }
190 return 0;
191}
192
193/*
194 * LSM hook implementation that frees xfrm_policy security information.
195 */
196void selinux_xfrm_policy_free(struct xfrm_policy *xp)
197{
198 struct xfrm_sec_ctx *ctx = xp->security;
199 if (ctx)
200 kfree(ctx);
201}
202
203/*
204 * LSM hook implementation that allocs and transfers sec_ctx spec to
205 * xfrm_state.
206 */
207int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx)
208{
209 int err;
210
211 BUG_ON(!x);
212
213 err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx);
214 return err;
215}
216
217/*
218 * LSM hook implementation that frees xfrm_state security information.
219 */
220void selinux_xfrm_state_free(struct xfrm_state *x)
221{
222 struct xfrm_sec_ctx *ctx = x->security;
223 if (ctx)
224 kfree(ctx);
225}
226
227/*
228 * LSM hook that controls access to unlabelled packets. If
229 * a xfrm_state is authorizable (defined by macro) then it was
230 * already authorized by the IPSec process. If not, then
231 * we need to check for unlabelled access since this may not have
232 * gone thru the IPSec process.
233 */
234int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
235{
236 int i, rc = 0;
237 struct sec_path *sp;
238
239 sp = skb->sp;
240
241 if (sp) {
242 /*
243 * __xfrm_policy_check does not approve unless xfrm_policy_ok
244 * says that spi's match for policy and the socket.
245 *
246 * Only need to verify the existence of an authorizable sp.
247 */
248 for (i = 0; i < sp->len; i++) {
249 struct xfrm_state *x = sp->x[i].xvec;
250
251 if (x && selinux_authorizable_xfrm(x))
252 goto accept;
253 }
254 }
255
256 /* check SELinux sock for unlabelled access */
257 rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
258 ASSOCIATION__RECVFROM, NULL);
259 if (rc)
260 goto drop;
261
262accept:
263 return 0;
264
265drop:
266 return rc;
267}
268
269/*
270 * POSTROUTE_LAST hook's XFRM processing:
271 * If we have no security association, then we need to determine
272 * whether the socket is allowed to send to an unlabelled destination.
273 * If we do have a authorizable security association, then it has already been
274 * checked in xfrm_policy_lookup hook.
275 */
276int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
277{
278 struct dst_entry *dst;
279 int rc = 0;
280
281 dst = skb->dst;
282
283 if (dst) {
284 struct dst_entry *dst_test;
285
286 for (dst_test = dst; dst_test != 0;
287 dst_test = dst_test->child) {
288 struct xfrm_state *x = dst_test->xfrm;
289
290 if (x && selinux_authorizable_xfrm(x))
291 goto accept;
292 }
293 }
294
295 rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
296 ASSOCIATION__SENDTO, NULL);
297 if (rc)
298 goto drop;
299
300accept:
301 return NF_ACCEPT;
302
303drop:
304 return NF_DROP;
305}