diff options
Diffstat (limited to 'security')
25 files changed, 1633 insertions, 116 deletions
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore index 0a0a99f3b083..4d995aeaebc0 100644 --- a/security/apparmor/.gitignore +++ b/security/apparmor/.gitignore | |||
@@ -3,3 +3,4 @@ | |||
3 | # | 3 | # |
4 | af_names.h | 4 | af_names.h |
5 | capability_names.h | 5 | capability_names.h |
6 | rlim_names.h | ||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index a27086d16f05..0848292982a2 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c | |||
@@ -29,7 +29,7 @@ | |||
29 | * aa_simple_write_to_buffer - common routine for getting policy from user | 29 | * aa_simple_write_to_buffer - common routine for getting policy from user |
30 | * @op: operation doing the user buffer copy | 30 | * @op: operation doing the user buffer copy |
31 | * @userbuf: user buffer to copy data from (NOT NULL) | 31 | * @userbuf: user buffer to copy data from (NOT NULL) |
32 | * @alloc_size: size of user buffer | 32 | * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size) |
33 | * @copy_size: size of data to copy from user buffer | 33 | * @copy_size: size of data to copy from user buffer |
34 | * @pos: position write is at in the file (NOT NULL) | 34 | * @pos: position write is at in the file (NOT NULL) |
35 | * | 35 | * |
@@ -42,6 +42,8 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, | |||
42 | { | 42 | { |
43 | char *data; | 43 | char *data; |
44 | 44 | ||
45 | BUG_ON(copy_size > alloc_size); | ||
46 | |||
45 | if (*pos != 0) | 47 | if (*pos != 0) |
46 | /* only writes from pos 0, that is complete writes */ | 48 | /* only writes from pos 0, that is complete writes */ |
47 | return ERR_PTR(-ESPIPE); | 49 | return ERR_PTR(-ESPIPE); |
diff --git a/security/capability.c b/security/capability.c index 95a6599a37bb..30ae00fbecd5 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -677,7 +677,18 @@ static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb) | |||
677 | { | 677 | { |
678 | } | 678 | } |
679 | 679 | ||
680 | static int cap_secmark_relabel_packet(u32 secid) | ||
681 | { | ||
682 | return 0; | ||
683 | } | ||
680 | 684 | ||
685 | static void cap_secmark_refcount_inc(void) | ||
686 | { | ||
687 | } | ||
688 | |||
689 | static void cap_secmark_refcount_dec(void) | ||
690 | { | ||
691 | } | ||
681 | 692 | ||
682 | static void cap_req_classify_flow(const struct request_sock *req, | 693 | static void cap_req_classify_flow(const struct request_sock *req, |
683 | struct flowi *fl) | 694 | struct flowi *fl) |
@@ -777,7 +788,8 @@ static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | |||
777 | 788 | ||
778 | static int cap_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) | 789 | static int cap_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) |
779 | { | 790 | { |
780 | return -EOPNOTSUPP; | 791 | *secid = 0; |
792 | return 0; | ||
781 | } | 793 | } |
782 | 794 | ||
783 | static void cap_release_secctx(char *secdata, u32 seclen) | 795 | static void cap_release_secctx(char *secdata, u32 seclen) |
@@ -1018,6 +1030,9 @@ void __init security_fixup_ops(struct security_operations *ops) | |||
1018 | set_to_cap_if_null(ops, inet_conn_request); | 1030 | set_to_cap_if_null(ops, inet_conn_request); |
1019 | set_to_cap_if_null(ops, inet_csk_clone); | 1031 | set_to_cap_if_null(ops, inet_csk_clone); |
1020 | set_to_cap_if_null(ops, inet_conn_established); | 1032 | set_to_cap_if_null(ops, inet_conn_established); |
1033 | set_to_cap_if_null(ops, secmark_relabel_packet); | ||
1034 | set_to_cap_if_null(ops, secmark_refcount_inc); | ||
1035 | set_to_cap_if_null(ops, secmark_refcount_dec); | ||
1021 | set_to_cap_if_null(ops, req_classify_flow); | 1036 | set_to_cap_if_null(ops, req_classify_flow); |
1022 | set_to_cap_if_null(ops, tun_dev_create); | 1037 | set_to_cap_if_null(ops, tun_dev_create); |
1023 | set_to_cap_if_null(ops, tun_dev_post_create); | 1038 | set_to_cap_if_null(ops, tun_dev_post_create); |
diff --git a/security/commoncap.c b/security/commoncap.c index 9d172e6e330c..5e632b4857e4 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -719,14 +719,11 @@ static int cap_safe_nice(struct task_struct *p) | |||
719 | /** | 719 | /** |
720 | * cap_task_setscheduler - Detemine if scheduler policy change is permitted | 720 | * cap_task_setscheduler - Detemine if scheduler policy change is permitted |
721 | * @p: The task to affect | 721 | * @p: The task to affect |
722 | * @policy: The policy to effect | ||
723 | * @lp: The parameters to the scheduling policy | ||
724 | * | 722 | * |
725 | * Detemine if the requested scheduler policy change is permitted for the | 723 | * Detemine if the requested scheduler policy change is permitted for the |
726 | * specified task, returning 0 if permission is granted, -ve if denied. | 724 | * specified task, returning 0 if permission is granted, -ve if denied. |
727 | */ | 725 | */ |
728 | int cap_task_setscheduler(struct task_struct *p, int policy, | 726 | int cap_task_setscheduler(struct task_struct *p) |
729 | struct sched_param *lp) | ||
730 | { | 727 | { |
731 | return cap_safe_nice(p); | 728 | return cap_safe_nice(p); |
732 | } | 729 | } |
diff --git a/security/security.c b/security/security.c index c53949f17d9e..b50f472061a4 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -89,20 +89,12 @@ __setup("security=", choose_lsm); | |||
89 | * Return true if: | 89 | * Return true if: |
90 | * -The passed LSM is the one chosen by user at boot time, | 90 | * -The passed LSM is the one chosen by user at boot time, |
91 | * -or the passed LSM is configured as the default and the user did not | 91 | * -or the passed LSM is configured as the default and the user did not |
92 | * choose an alternate LSM at boot time, | 92 | * choose an alternate LSM at boot time. |
93 | * -or there is no default LSM set and the user didn't specify a | ||
94 | * specific LSM and we're the first to ask for registration permission, | ||
95 | * -or the passed LSM is currently loaded. | ||
96 | * Otherwise, return false. | 93 | * Otherwise, return false. |
97 | */ | 94 | */ |
98 | int __init security_module_enable(struct security_operations *ops) | 95 | int __init security_module_enable(struct security_operations *ops) |
99 | { | 96 | { |
100 | if (!*chosen_lsm) | 97 | return !strcmp(ops->name, chosen_lsm); |
101 | strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX); | ||
102 | else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX)) | ||
103 | return 0; | ||
104 | |||
105 | return 1; | ||
106 | } | 98 | } |
107 | 99 | ||
108 | /** | 100 | /** |
@@ -786,10 +778,9 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource, | |||
786 | return security_ops->task_setrlimit(p, resource, new_rlim); | 778 | return security_ops->task_setrlimit(p, resource, new_rlim); |
787 | } | 779 | } |
788 | 780 | ||
789 | int security_task_setscheduler(struct task_struct *p, | 781 | int security_task_setscheduler(struct task_struct *p) |
790 | int policy, struct sched_param *lp) | ||
791 | { | 782 | { |
792 | return security_ops->task_setscheduler(p, policy, lp); | 783 | return security_ops->task_setscheduler(p); |
793 | } | 784 | } |
794 | 785 | ||
795 | int security_task_getscheduler(struct task_struct *p) | 786 | int security_task_getscheduler(struct task_struct *p) |
@@ -1145,6 +1136,24 @@ void security_inet_conn_established(struct sock *sk, | |||
1145 | security_ops->inet_conn_established(sk, skb); | 1136 | security_ops->inet_conn_established(sk, skb); |
1146 | } | 1137 | } |
1147 | 1138 | ||
1139 | int security_secmark_relabel_packet(u32 secid) | ||
1140 | { | ||
1141 | return security_ops->secmark_relabel_packet(secid); | ||
1142 | } | ||
1143 | EXPORT_SYMBOL(security_secmark_relabel_packet); | ||
1144 | |||
1145 | void security_secmark_refcount_inc(void) | ||
1146 | { | ||
1147 | security_ops->secmark_refcount_inc(); | ||
1148 | } | ||
1149 | EXPORT_SYMBOL(security_secmark_refcount_inc); | ||
1150 | |||
1151 | void security_secmark_refcount_dec(void) | ||
1152 | { | ||
1153 | security_ops->secmark_refcount_dec(); | ||
1154 | } | ||
1155 | EXPORT_SYMBOL(security_secmark_refcount_dec); | ||
1156 | |||
1148 | int security_tun_dev_create(void) | 1157 | int security_tun_dev_create(void) |
1149 | { | 1158 | { |
1150 | return security_ops->tun_dev_create(); | 1159 | return security_ops->tun_dev_create(); |
diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 58d80f3bd6f6..ad5cd76ec231 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile | |||
@@ -2,25 +2,20 @@ | |||
2 | # Makefile for building the SELinux module as part of the kernel tree. | 2 | # Makefile for building the SELinux module as part of the kernel tree. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/ | 5 | obj-$(CONFIG_SECURITY_SELINUX) := selinux.o |
6 | 6 | ||
7 | selinux-y := avc.o \ | 7 | selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \ |
8 | hooks.o \ | 8 | netnode.o netport.o exports.o \ |
9 | selinuxfs.o \ | 9 | ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \ |
10 | netlink.o \ | 10 | ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o |
11 | nlmsgtab.o \ | ||
12 | netif.o \ | ||
13 | netnode.o \ | ||
14 | netport.o \ | ||
15 | exports.o | ||
16 | 11 | ||
17 | selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o | 12 | selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o |
18 | 13 | ||
19 | selinux-$(CONFIG_NETLABEL) += netlabel.o | 14 | selinux-$(CONFIG_NETLABEL) += netlabel.o |
20 | 15 | ||
21 | EXTRA_CFLAGS += -Isecurity/selinux -Isecurity/selinux/include | 16 | ccflags-y := -Isecurity/selinux -Isecurity/selinux/include |
22 | 17 | ||
23 | $(obj)/avc.o: $(obj)/flask.h | 18 | $(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h |
24 | 19 | ||
25 | quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h | 20 | quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h |
26 | cmd_flask = scripts/selinux/genheaders/genheaders $(obj)/flask.h $(obj)/av_permissions.h | 21 | cmd_flask = scripts/selinux/genheaders/genheaders $(obj)/flask.h $(obj)/av_permissions.h |
diff --git a/security/selinux/exports.c b/security/selinux/exports.c index c0a454aee1e0..90664385dead 100644 --- a/security/selinux/exports.c +++ b/security/selinux/exports.c | |||
@@ -11,58 +11,9 @@ | |||
11 | * it under the terms of the GNU General Public License version 2, | 11 | * it under the terms of the GNU General Public License version 2, |
12 | * as published by the Free Software Foundation. | 12 | * as published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | #include <linux/types.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | 14 | #include <linux/module.h> |
17 | #include <linux/selinux.h> | ||
18 | #include <linux/fs.h> | ||
19 | #include <linux/ipc.h> | ||
20 | #include <asm/atomic.h> | ||
21 | 15 | ||
22 | #include "security.h" | 16 | #include "security.h" |
23 | #include "objsec.h" | ||
24 | |||
25 | /* SECMARK reference count */ | ||
26 | extern atomic_t selinux_secmark_refcount; | ||
27 | |||
28 | int selinux_string_to_sid(char *str, u32 *sid) | ||
29 | { | ||
30 | if (selinux_enabled) | ||
31 | return security_context_to_sid(str, strlen(str), sid); | ||
32 | else { | ||
33 | *sid = 0; | ||
34 | return 0; | ||
35 | } | ||
36 | } | ||
37 | EXPORT_SYMBOL_GPL(selinux_string_to_sid); | ||
38 | |||
39 | int selinux_secmark_relabel_packet_permission(u32 sid) | ||
40 | { | ||
41 | if (selinux_enabled) { | ||
42 | const struct task_security_struct *__tsec; | ||
43 | u32 tsid; | ||
44 | |||
45 | __tsec = current_security(); | ||
46 | tsid = __tsec->sid; | ||
47 | |||
48 | return avc_has_perm(tsid, sid, SECCLASS_PACKET, | ||
49 | PACKET__RELABELTO, NULL); | ||
50 | } | ||
51 | return 0; | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(selinux_secmark_relabel_packet_permission); | ||
54 | |||
55 | void selinux_secmark_refcount_inc(void) | ||
56 | { | ||
57 | atomic_inc(&selinux_secmark_refcount); | ||
58 | } | ||
59 | EXPORT_SYMBOL_GPL(selinux_secmark_refcount_inc); | ||
60 | |||
61 | void selinux_secmark_refcount_dec(void) | ||
62 | { | ||
63 | atomic_dec(&selinux_secmark_refcount); | ||
64 | } | ||
65 | EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec); | ||
66 | 17 | ||
67 | bool selinux_is_enabled(void) | 18 | bool selinux_is_enabled(void) |
68 | { | 19 | { |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4796ddd4e721..d9154cf90ae1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -3354,11 +3354,11 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, | |||
3354 | return 0; | 3354 | return 0; |
3355 | } | 3355 | } |
3356 | 3356 | ||
3357 | static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp) | 3357 | static int selinux_task_setscheduler(struct task_struct *p) |
3358 | { | 3358 | { |
3359 | int rc; | 3359 | int rc; |
3360 | 3360 | ||
3361 | rc = cap_task_setscheduler(p, policy, lp); | 3361 | rc = cap_task_setscheduler(p); |
3362 | if (rc) | 3362 | if (rc) |
3363 | return rc; | 3363 | return rc; |
3364 | 3364 | ||
@@ -4279,6 +4279,27 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) | |||
4279 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | 4279 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); |
4280 | } | 4280 | } |
4281 | 4281 | ||
4282 | static int selinux_secmark_relabel_packet(u32 sid) | ||
4283 | { | ||
4284 | const struct task_security_struct *__tsec; | ||
4285 | u32 tsid; | ||
4286 | |||
4287 | __tsec = current_security(); | ||
4288 | tsid = __tsec->sid; | ||
4289 | |||
4290 | return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL); | ||
4291 | } | ||
4292 | |||
4293 | static void selinux_secmark_refcount_inc(void) | ||
4294 | { | ||
4295 | atomic_inc(&selinux_secmark_refcount); | ||
4296 | } | ||
4297 | |||
4298 | static void selinux_secmark_refcount_dec(void) | ||
4299 | { | ||
4300 | atomic_dec(&selinux_secmark_refcount); | ||
4301 | } | ||
4302 | |||
4282 | static void selinux_req_classify_flow(const struct request_sock *req, | 4303 | static void selinux_req_classify_flow(const struct request_sock *req, |
4283 | struct flowi *fl) | 4304 | struct flowi *fl) |
4284 | { | 4305 | { |
@@ -5533,6 +5554,9 @@ static struct security_operations selinux_ops = { | |||
5533 | .inet_conn_request = selinux_inet_conn_request, | 5554 | .inet_conn_request = selinux_inet_conn_request, |
5534 | .inet_csk_clone = selinux_inet_csk_clone, | 5555 | .inet_csk_clone = selinux_inet_csk_clone, |
5535 | .inet_conn_established = selinux_inet_conn_established, | 5556 | .inet_conn_established = selinux_inet_conn_established, |
5557 | .secmark_relabel_packet = selinux_secmark_relabel_packet, | ||
5558 | .secmark_refcount_inc = selinux_secmark_refcount_inc, | ||
5559 | .secmark_refcount_dec = selinux_secmark_refcount_dec, | ||
5536 | .req_classify_flow = selinux_req_classify_flow, | 5560 | .req_classify_flow = selinux_req_classify_flow, |
5537 | .tun_dev_create = selinux_tun_dev_create, | 5561 | .tun_dev_create = selinux_tun_dev_create, |
5538 | .tun_dev_post_create = selinux_tun_dev_post_create, | 5562 | .tun_dev_post_create = selinux_tun_dev_post_create, |
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index b4c9eb4bd6f9..8858d2b2d4b6 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h | |||
@@ -17,7 +17,7 @@ struct security_class_mapping secclass_map[] = { | |||
17 | { "compute_av", "compute_create", "compute_member", | 17 | { "compute_av", "compute_create", "compute_member", |
18 | "check_context", "load_policy", "compute_relabel", | 18 | "check_context", "load_policy", "compute_relabel", |
19 | "compute_user", "setenforce", "setbool", "setsecparam", | 19 | "compute_user", "setenforce", "setbool", "setsecparam", |
20 | "setcheckreqprot", NULL } }, | 20 | "setcheckreqprot", "read_policy", NULL } }, |
21 | { "process", | 21 | { "process", |
22 | { "fork", "transition", "sigchld", "sigkill", | 22 | { "fork", "transition", "sigchld", "sigkill", |
23 | "sigstop", "signull", "signal", "ptrace", "getsched", "setsched", | 23 | "sigstop", "signull", "signal", "ptrace", "getsched", "setsched", |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 1f7c2491d3dc..671273eb1115 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #define _SELINUX_SECURITY_H_ | 9 | #define _SELINUX_SECURITY_H_ |
10 | 10 | ||
11 | #include <linux/magic.h> | 11 | #include <linux/magic.h> |
12 | #include <linux/types.h> | ||
12 | #include "flask.h" | 13 | #include "flask.h" |
13 | 14 | ||
14 | #define SECSID_NULL 0x00000000 /* unspecified SID */ | 15 | #define SECSID_NULL 0x00000000 /* unspecified SID */ |
@@ -82,6 +83,8 @@ extern int selinux_policycap_openperm; | |||
82 | int security_mls_enabled(void); | 83 | int security_mls_enabled(void); |
83 | 84 | ||
84 | int security_load_policy(void *data, size_t len); | 85 | int security_load_policy(void *data, size_t len); |
86 | int security_read_policy(void **data, ssize_t *len); | ||
87 | size_t security_policydb_len(void); | ||
85 | 88 | ||
86 | int security_policycap_supported(unsigned int req_cap); | 89 | int security_policycap_supported(unsigned int req_cap); |
87 | 90 | ||
@@ -191,5 +194,25 @@ static inline int security_netlbl_sid_to_secattr(u32 sid, | |||
191 | 194 | ||
192 | const char *security_get_initial_sid_context(u32 sid); | 195 | const char *security_get_initial_sid_context(u32 sid); |
193 | 196 | ||
197 | /* | ||
198 | * status notifier using mmap interface | ||
199 | */ | ||
200 | extern struct page *selinux_kernel_status_page(void); | ||
201 | |||
202 | #define SELINUX_KERNEL_STATUS_VERSION 1 | ||
203 | struct selinux_kernel_status { | ||
204 | u32 version; /* version number of thie structure */ | ||
205 | u32 sequence; /* sequence number of seqlock logic */ | ||
206 | u32 enforcing; /* current setting of enforcing mode */ | ||
207 | u32 policyload; /* times of policy reloaded */ | ||
208 | u32 deny_unknown; /* current setting of deny_unknown */ | ||
209 | /* | ||
210 | * The version > 0 supports above members. | ||
211 | */ | ||
212 | } __attribute__((packed)); | ||
213 | |||
214 | extern void selinux_status_update_setenforce(int enforcing); | ||
215 | extern void selinux_status_update_policyload(int seqno); | ||
216 | |||
194 | #endif /* _SELINUX_SECURITY_H_ */ | 217 | #endif /* _SELINUX_SECURITY_H_ */ |
195 | 218 | ||
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 79a1bb635662..87e0556bae70 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -68,6 +68,8 @@ static int *bool_pending_values; | |||
68 | static struct dentry *class_dir; | 68 | static struct dentry *class_dir; |
69 | static unsigned long last_class_ino; | 69 | static unsigned long last_class_ino; |
70 | 70 | ||
71 | static char policy_opened; | ||
72 | |||
71 | /* global data for policy capabilities */ | 73 | /* global data for policy capabilities */ |
72 | static struct dentry *policycap_dir; | 74 | static struct dentry *policycap_dir; |
73 | 75 | ||
@@ -110,6 +112,8 @@ enum sel_inos { | |||
110 | SEL_COMPAT_NET, /* whether to use old compat network packet controls */ | 112 | SEL_COMPAT_NET, /* whether to use old compat network packet controls */ |
111 | SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */ | 113 | SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */ |
112 | SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */ | 114 | SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */ |
115 | SEL_STATUS, /* export current status using mmap() */ | ||
116 | SEL_POLICY, /* allow userspace to read the in kernel policy */ | ||
113 | SEL_INO_NEXT, /* The next inode number to use */ | 117 | SEL_INO_NEXT, /* The next inode number to use */ |
114 | }; | 118 | }; |
115 | 119 | ||
@@ -171,6 +175,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, | |||
171 | if (selinux_enforcing) | 175 | if (selinux_enforcing) |
172 | avc_ss_reset(0); | 176 | avc_ss_reset(0); |
173 | selnl_notify_setenforce(selinux_enforcing); | 177 | selnl_notify_setenforce(selinux_enforcing); |
178 | selinux_status_update_setenforce(selinux_enforcing); | ||
174 | } | 179 | } |
175 | length = count; | 180 | length = count; |
176 | out: | 181 | out: |
@@ -205,6 +210,59 @@ static const struct file_operations sel_handle_unknown_ops = { | |||
205 | .llseek = generic_file_llseek, | 210 | .llseek = generic_file_llseek, |
206 | }; | 211 | }; |
207 | 212 | ||
213 | static int sel_open_handle_status(struct inode *inode, struct file *filp) | ||
214 | { | ||
215 | struct page *status = selinux_kernel_status_page(); | ||
216 | |||
217 | if (!status) | ||
218 | return -ENOMEM; | ||
219 | |||
220 | filp->private_data = status; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static ssize_t sel_read_handle_status(struct file *filp, char __user *buf, | ||
226 | size_t count, loff_t *ppos) | ||
227 | { | ||
228 | struct page *status = filp->private_data; | ||
229 | |||
230 | BUG_ON(!status); | ||
231 | |||
232 | return simple_read_from_buffer(buf, count, ppos, | ||
233 | page_address(status), | ||
234 | sizeof(struct selinux_kernel_status)); | ||
235 | } | ||
236 | |||
237 | static int sel_mmap_handle_status(struct file *filp, | ||
238 | struct vm_area_struct *vma) | ||
239 | { | ||
240 | struct page *status = filp->private_data; | ||
241 | unsigned long size = vma->vm_end - vma->vm_start; | ||
242 | |||
243 | BUG_ON(!status); | ||
244 | |||
245 | /* only allows one page from the head */ | ||
246 | if (vma->vm_pgoff > 0 || size != PAGE_SIZE) | ||
247 | return -EIO; | ||
248 | /* disallow writable mapping */ | ||
249 | if (vma->vm_flags & VM_WRITE) | ||
250 | return -EPERM; | ||
251 | /* disallow mprotect() turns it into writable */ | ||
252 | vma->vm_flags &= ~VM_MAYWRITE; | ||
253 | |||
254 | return remap_pfn_range(vma, vma->vm_start, | ||
255 | page_to_pfn(status), | ||
256 | size, vma->vm_page_prot); | ||
257 | } | ||
258 | |||
259 | static const struct file_operations sel_handle_status_ops = { | ||
260 | .open = sel_open_handle_status, | ||
261 | .read = sel_read_handle_status, | ||
262 | .mmap = sel_mmap_handle_status, | ||
263 | .llseek = generic_file_llseek, | ||
264 | }; | ||
265 | |||
208 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 266 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
209 | static ssize_t sel_write_disable(struct file *file, const char __user *buf, | 267 | static ssize_t sel_write_disable(struct file *file, const char __user *buf, |
210 | size_t count, loff_t *ppos) | 268 | size_t count, loff_t *ppos) |
@@ -296,6 +354,141 @@ static const struct file_operations sel_mls_ops = { | |||
296 | .llseek = generic_file_llseek, | 354 | .llseek = generic_file_llseek, |
297 | }; | 355 | }; |
298 | 356 | ||
357 | struct policy_load_memory { | ||
358 | size_t len; | ||
359 | void *data; | ||
360 | }; | ||
361 | |||
362 | static int sel_open_policy(struct inode *inode, struct file *filp) | ||
363 | { | ||
364 | struct policy_load_memory *plm = NULL; | ||
365 | int rc; | ||
366 | |||
367 | BUG_ON(filp->private_data); | ||
368 | |||
369 | mutex_lock(&sel_mutex); | ||
370 | |||
371 | rc = task_has_security(current, SECURITY__READ_POLICY); | ||
372 | if (rc) | ||
373 | goto err; | ||
374 | |||
375 | rc = -EBUSY; | ||
376 | if (policy_opened) | ||
377 | goto err; | ||
378 | |||
379 | rc = -ENOMEM; | ||
380 | plm = kzalloc(sizeof(*plm), GFP_KERNEL); | ||
381 | if (!plm) | ||
382 | goto err; | ||
383 | |||
384 | if (i_size_read(inode) != security_policydb_len()) { | ||
385 | mutex_lock(&inode->i_mutex); | ||
386 | i_size_write(inode, security_policydb_len()); | ||
387 | mutex_unlock(&inode->i_mutex); | ||
388 | } | ||
389 | |||
390 | rc = security_read_policy(&plm->data, &plm->len); | ||
391 | if (rc) | ||
392 | goto err; | ||
393 | |||
394 | policy_opened = 1; | ||
395 | |||
396 | filp->private_data = plm; | ||
397 | |||
398 | mutex_unlock(&sel_mutex); | ||
399 | |||
400 | return 0; | ||
401 | err: | ||
402 | mutex_unlock(&sel_mutex); | ||
403 | |||
404 | if (plm) | ||
405 | vfree(plm->data); | ||
406 | kfree(plm); | ||
407 | return rc; | ||
408 | } | ||
409 | |||
410 | static int sel_release_policy(struct inode *inode, struct file *filp) | ||
411 | { | ||
412 | struct policy_load_memory *plm = filp->private_data; | ||
413 | |||
414 | BUG_ON(!plm); | ||
415 | |||
416 | policy_opened = 0; | ||
417 | |||
418 | vfree(plm->data); | ||
419 | kfree(plm); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static ssize_t sel_read_policy(struct file *filp, char __user *buf, | ||
425 | size_t count, loff_t *ppos) | ||
426 | { | ||
427 | struct policy_load_memory *plm = filp->private_data; | ||
428 | int ret; | ||
429 | |||
430 | mutex_lock(&sel_mutex); | ||
431 | |||
432 | ret = task_has_security(current, SECURITY__READ_POLICY); | ||
433 | if (ret) | ||
434 | goto out; | ||
435 | |||
436 | ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len); | ||
437 | out: | ||
438 | mutex_unlock(&sel_mutex); | ||
439 | return ret; | ||
440 | } | ||
441 | |||
442 | static int sel_mmap_policy_fault(struct vm_area_struct *vma, | ||
443 | struct vm_fault *vmf) | ||
444 | { | ||
445 | struct policy_load_memory *plm = vma->vm_file->private_data; | ||
446 | unsigned long offset; | ||
447 | struct page *page; | ||
448 | |||
449 | if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE)) | ||
450 | return VM_FAULT_SIGBUS; | ||
451 | |||
452 | offset = vmf->pgoff << PAGE_SHIFT; | ||
453 | if (offset >= roundup(plm->len, PAGE_SIZE)) | ||
454 | return VM_FAULT_SIGBUS; | ||
455 | |||
456 | page = vmalloc_to_page(plm->data + offset); | ||
457 | get_page(page); | ||
458 | |||
459 | vmf->page = page; | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static struct vm_operations_struct sel_mmap_policy_ops = { | ||
465 | .fault = sel_mmap_policy_fault, | ||
466 | .page_mkwrite = sel_mmap_policy_fault, | ||
467 | }; | ||
468 | |||
469 | int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma) | ||
470 | { | ||
471 | if (vma->vm_flags & VM_SHARED) { | ||
472 | /* do not allow mprotect to make mapping writable */ | ||
473 | vma->vm_flags &= ~VM_MAYWRITE; | ||
474 | |||
475 | if (vma->vm_flags & VM_WRITE) | ||
476 | return -EACCES; | ||
477 | } | ||
478 | |||
479 | vma->vm_flags |= VM_RESERVED; | ||
480 | vma->vm_ops = &sel_mmap_policy_ops; | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static const struct file_operations sel_policy_ops = { | ||
486 | .open = sel_open_policy, | ||
487 | .read = sel_read_policy, | ||
488 | .mmap = sel_mmap_policy, | ||
489 | .release = sel_release_policy, | ||
490 | }; | ||
491 | |||
299 | static ssize_t sel_write_load(struct file *file, const char __user *buf, | 492 | static ssize_t sel_write_load(struct file *file, const char __user *buf, |
300 | size_t count, loff_t *ppos) | 493 | size_t count, loff_t *ppos) |
301 | 494 | ||
@@ -1612,6 +1805,8 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1612 | [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, | 1805 | [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, |
1613 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1806 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1614 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1807 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1808 | [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, | ||
1809 | [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR}, | ||
1615 | /* last one */ {""} | 1810 | /* last one */ {""} |
1616 | }; | 1811 | }; |
1617 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 1812 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); |
diff --git a/security/selinux/ss/Makefile b/security/selinux/ss/Makefile deleted file mode 100644 index 15d4e62917de..000000000000 --- a/security/selinux/ss/Makefile +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for building the SELinux security server as part of the kernel tree. | ||
3 | # | ||
4 | |||
5 | EXTRA_CFLAGS += -Isecurity/selinux -Isecurity/selinux/include | ||
6 | obj-y := ss.o | ||
7 | |||
8 | ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o | ||
9 | |||
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 929480c6c430..a3dd9faa19c0 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
@@ -266,8 +266,8 @@ int avtab_alloc(struct avtab *h, u32 nrules) | |||
266 | if (shift > 2) | 266 | if (shift > 2) |
267 | shift = shift - 2; | 267 | shift = shift - 2; |
268 | nslot = 1 << shift; | 268 | nslot = 1 << shift; |
269 | if (nslot > MAX_AVTAB_SIZE) | 269 | if (nslot > MAX_AVTAB_HASH_BUCKETS) |
270 | nslot = MAX_AVTAB_SIZE; | 270 | nslot = MAX_AVTAB_HASH_BUCKETS; |
271 | mask = nslot - 1; | 271 | mask = nslot - 1; |
272 | 272 | ||
273 | h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL); | 273 | h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL); |
@@ -501,6 +501,48 @@ bad: | |||
501 | goto out; | 501 | goto out; |
502 | } | 502 | } |
503 | 503 | ||
504 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) | ||
505 | { | ||
506 | __le16 buf16[4]; | ||
507 | __le32 buf32[1]; | ||
508 | int rc; | ||
509 | |||
510 | buf16[0] = cpu_to_le16(cur->key.source_type); | ||
511 | buf16[1] = cpu_to_le16(cur->key.target_type); | ||
512 | buf16[2] = cpu_to_le16(cur->key.target_class); | ||
513 | buf16[3] = cpu_to_le16(cur->key.specified); | ||
514 | rc = put_entry(buf16, sizeof(u16), 4, fp); | ||
515 | if (rc) | ||
516 | return rc; | ||
517 | buf32[0] = cpu_to_le32(cur->datum.data); | ||
518 | rc = put_entry(buf32, sizeof(u32), 1, fp); | ||
519 | if (rc) | ||
520 | return rc; | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | int avtab_write(struct policydb *p, struct avtab *a, void *fp) | ||
525 | { | ||
526 | unsigned int i; | ||
527 | int rc = 0; | ||
528 | struct avtab_node *cur; | ||
529 | __le32 buf[1]; | ||
530 | |||
531 | buf[0] = cpu_to_le32(a->nel); | ||
532 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
533 | if (rc) | ||
534 | return rc; | ||
535 | |||
536 | for (i = 0; i < a->nslot; i++) { | ||
537 | for (cur = a->htable[i]; cur; cur = cur->next) { | ||
538 | rc = avtab_write_item(p, cur, fp); | ||
539 | if (rc) | ||
540 | return rc; | ||
541 | } | ||
542 | } | ||
543 | |||
544 | return rc; | ||
545 | } | ||
504 | void avtab_cache_init(void) | 546 | void avtab_cache_init(void) |
505 | { | 547 | { |
506 | avtab_node_cachep = kmem_cache_create("avtab_node", | 548 | avtab_node_cachep = kmem_cache_create("avtab_node", |
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index cd4f734e2749..dff0c75345c1 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h | |||
@@ -71,6 +71,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
71 | void *p); | 71 | void *p); |
72 | 72 | ||
73 | int avtab_read(struct avtab *a, void *fp, struct policydb *pol); | 73 | int avtab_read(struct avtab *a, void *fp, struct policydb *pol); |
74 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp); | ||
75 | int avtab_write(struct policydb *p, struct avtab *a, void *fp); | ||
74 | 76 | ||
75 | struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, | 77 | struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, |
76 | struct avtab_datum *datum); | 78 | struct avtab_datum *datum); |
@@ -85,7 +87,6 @@ void avtab_cache_destroy(void); | |||
85 | #define MAX_AVTAB_HASH_BITS 11 | 87 | #define MAX_AVTAB_HASH_BITS 11 |
86 | #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) | 88 | #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) |
87 | #define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) | 89 | #define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) |
88 | #define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS | ||
89 | 90 | ||
90 | #endif /* _SS_AVTAB_H_ */ | 91 | #endif /* _SS_AVTAB_H_ */ |
91 | 92 | ||
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index c91e150c3087..655fe1c6cc69 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
@@ -490,6 +490,129 @@ err: | |||
490 | return rc; | 490 | return rc; |
491 | } | 491 | } |
492 | 492 | ||
493 | int cond_write_bool(void *vkey, void *datum, void *ptr) | ||
494 | { | ||
495 | char *key = vkey; | ||
496 | struct cond_bool_datum *booldatum = datum; | ||
497 | struct policy_data *pd = ptr; | ||
498 | void *fp = pd->fp; | ||
499 | __le32 buf[3]; | ||
500 | u32 len; | ||
501 | int rc; | ||
502 | |||
503 | len = strlen(key); | ||
504 | buf[0] = cpu_to_le32(booldatum->value); | ||
505 | buf[1] = cpu_to_le32(booldatum->state); | ||
506 | buf[2] = cpu_to_le32(len); | ||
507 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
508 | if (rc) | ||
509 | return rc; | ||
510 | rc = put_entry(key, 1, len, fp); | ||
511 | if (rc) | ||
512 | return rc; | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | /* | ||
517 | * cond_write_cond_av_list doesn't write out the av_list nodes. | ||
518 | * Instead it writes out the key/value pairs from the avtab. This | ||
519 | * is necessary because there is no way to uniquely identifying rules | ||
520 | * in the avtab so it is not possible to associate individual rules | ||
521 | * in the avtab with a conditional without saving them as part of | ||
522 | * the conditional. This means that the avtab with the conditional | ||
523 | * rules will not be saved but will be rebuilt on policy load. | ||
524 | */ | ||
525 | static int cond_write_av_list(struct policydb *p, | ||
526 | struct cond_av_list *list, struct policy_file *fp) | ||
527 | { | ||
528 | __le32 buf[1]; | ||
529 | struct cond_av_list *cur_list; | ||
530 | u32 len; | ||
531 | int rc; | ||
532 | |||
533 | len = 0; | ||
534 | for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) | ||
535 | len++; | ||
536 | |||
537 | buf[0] = cpu_to_le32(len); | ||
538 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
539 | if (rc) | ||
540 | return rc; | ||
541 | |||
542 | if (len == 0) | ||
543 | return 0; | ||
544 | |||
545 | for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) { | ||
546 | rc = avtab_write_item(p, cur_list->node, fp); | ||
547 | if (rc) | ||
548 | return rc; | ||
549 | } | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | int cond_write_node(struct policydb *p, struct cond_node *node, | ||
555 | struct policy_file *fp) | ||
556 | { | ||
557 | struct cond_expr *cur_expr; | ||
558 | __le32 buf[2]; | ||
559 | int rc; | ||
560 | u32 len = 0; | ||
561 | |||
562 | buf[0] = cpu_to_le32(node->cur_state); | ||
563 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
564 | if (rc) | ||
565 | return rc; | ||
566 | |||
567 | for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) | ||
568 | len++; | ||
569 | |||
570 | buf[0] = cpu_to_le32(len); | ||
571 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
572 | if (rc) | ||
573 | return rc; | ||
574 | |||
575 | for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) { | ||
576 | buf[0] = cpu_to_le32(cur_expr->expr_type); | ||
577 | buf[1] = cpu_to_le32(cur_expr->bool); | ||
578 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
579 | if (rc) | ||
580 | return rc; | ||
581 | } | ||
582 | |||
583 | rc = cond_write_av_list(p, node->true_list, fp); | ||
584 | if (rc) | ||
585 | return rc; | ||
586 | rc = cond_write_av_list(p, node->false_list, fp); | ||
587 | if (rc) | ||
588 | return rc; | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp) | ||
594 | { | ||
595 | struct cond_node *cur; | ||
596 | u32 len; | ||
597 | __le32 buf[1]; | ||
598 | int rc; | ||
599 | |||
600 | len = 0; | ||
601 | for (cur = list; cur != NULL; cur = cur->next) | ||
602 | len++; | ||
603 | buf[0] = cpu_to_le32(len); | ||
604 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
605 | if (rc) | ||
606 | return rc; | ||
607 | |||
608 | for (cur = list; cur != NULL; cur = cur->next) { | ||
609 | rc = cond_write_node(p, cur, fp); | ||
610 | if (rc) | ||
611 | return rc; | ||
612 | } | ||
613 | |||
614 | return 0; | ||
615 | } | ||
493 | /* Determine whether additional permissions are granted by the conditional | 616 | /* Determine whether additional permissions are granted by the conditional |
494 | * av table, and if so, add them to the result | 617 | * av table, and if so, add them to the result |
495 | */ | 618 | */ |
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 53ddb013ae57..3f209c635295 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h | |||
@@ -69,6 +69,8 @@ int cond_index_bool(void *key, void *datum, void *datap); | |||
69 | 69 | ||
70 | int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp); | 70 | int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp); |
71 | int cond_read_list(struct policydb *p, void *fp); | 71 | int cond_read_list(struct policydb *p, void *fp); |
72 | int cond_write_bool(void *key, void *datum, void *ptr); | ||
73 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); | ||
72 | 74 | ||
73 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); | 75 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); |
74 | 76 | ||
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 04b6145d767f..d42951fcbe87 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include "ebitmap.h" | 22 | #include "ebitmap.h" |
23 | #include "policydb.h" | 23 | #include "policydb.h" |
24 | 24 | ||
25 | #define BITS_PER_U64 (sizeof(u64) * 8) | ||
26 | |||
25 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) | 27 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) |
26 | { | 28 | { |
27 | struct ebitmap_node *n1, *n2; | 29 | struct ebitmap_node *n1, *n2; |
@@ -363,10 +365,10 @@ int ebitmap_read(struct ebitmap *e, void *fp) | |||
363 | e->highbit = le32_to_cpu(buf[1]); | 365 | e->highbit = le32_to_cpu(buf[1]); |
364 | count = le32_to_cpu(buf[2]); | 366 | count = le32_to_cpu(buf[2]); |
365 | 367 | ||
366 | if (mapunit != sizeof(u64) * 8) { | 368 | if (mapunit != BITS_PER_U64) { |
367 | printk(KERN_ERR "SELinux: ebitmap: map size %u does not " | 369 | printk(KERN_ERR "SELinux: ebitmap: map size %u does not " |
368 | "match my size %Zd (high bit was %d)\n", | 370 | "match my size %Zd (high bit was %d)\n", |
369 | mapunit, sizeof(u64) * 8, e->highbit); | 371 | mapunit, BITS_PER_U64, e->highbit); |
370 | goto bad; | 372 | goto bad; |
371 | } | 373 | } |
372 | 374 | ||
@@ -446,3 +448,78 @@ bad: | |||
446 | ebitmap_destroy(e); | 448 | ebitmap_destroy(e); |
447 | goto out; | 449 | goto out; |
448 | } | 450 | } |
451 | |||
452 | int ebitmap_write(struct ebitmap *e, void *fp) | ||
453 | { | ||
454 | struct ebitmap_node *n; | ||
455 | u32 count; | ||
456 | __le32 buf[3]; | ||
457 | u64 map; | ||
458 | int bit, last_bit, last_startbit, rc; | ||
459 | |||
460 | buf[0] = cpu_to_le32(BITS_PER_U64); | ||
461 | |||
462 | count = 0; | ||
463 | last_bit = 0; | ||
464 | last_startbit = -1; | ||
465 | ebitmap_for_each_positive_bit(e, n, bit) { | ||
466 | if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) { | ||
467 | count++; | ||
468 | last_startbit = rounddown(bit, BITS_PER_U64); | ||
469 | } | ||
470 | last_bit = roundup(bit + 1, BITS_PER_U64); | ||
471 | } | ||
472 | buf[1] = cpu_to_le32(last_bit); | ||
473 | buf[2] = cpu_to_le32(count); | ||
474 | |||
475 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
476 | if (rc) | ||
477 | return rc; | ||
478 | |||
479 | map = 0; | ||
480 | last_startbit = INT_MIN; | ||
481 | ebitmap_for_each_positive_bit(e, n, bit) { | ||
482 | if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) { | ||
483 | __le64 buf64[1]; | ||
484 | |||
485 | /* this is the very first bit */ | ||
486 | if (!map) { | ||
487 | last_startbit = rounddown(bit, BITS_PER_U64); | ||
488 | map = (u64)1 << (bit - last_startbit); | ||
489 | continue; | ||
490 | } | ||
491 | |||
492 | /* write the last node */ | ||
493 | buf[0] = cpu_to_le32(last_startbit); | ||
494 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
495 | if (rc) | ||
496 | return rc; | ||
497 | |||
498 | buf64[0] = cpu_to_le64(map); | ||
499 | rc = put_entry(buf64, sizeof(u64), 1, fp); | ||
500 | if (rc) | ||
501 | return rc; | ||
502 | |||
503 | /* set up for the next node */ | ||
504 | map = 0; | ||
505 | last_startbit = rounddown(bit, BITS_PER_U64); | ||
506 | } | ||
507 | map |= (u64)1 << (bit - last_startbit); | ||
508 | } | ||
509 | /* write the last node */ | ||
510 | if (map) { | ||
511 | __le64 buf64[1]; | ||
512 | |||
513 | /* write the last node */ | ||
514 | buf[0] = cpu_to_le32(last_startbit); | ||
515 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
516 | if (rc) | ||
517 | return rc; | ||
518 | |||
519 | buf64[0] = cpu_to_le64(map); | ||
520 | rc = put_entry(buf64, sizeof(u64), 1, fp); | ||
521 | if (rc) | ||
522 | return rc; | ||
523 | } | ||
524 | return 0; | ||
525 | } | ||
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index f283b4367f54..1f4e93c2ae86 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h | |||
@@ -123,6 +123,7 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit); | |||
123 | int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); | 123 | int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); |
124 | void ebitmap_destroy(struct ebitmap *e); | 124 | void ebitmap_destroy(struct ebitmap *e); |
125 | int ebitmap_read(struct ebitmap *e, void *fp); | 125 | int ebitmap_read(struct ebitmap *e, void *fp); |
126 | int ebitmap_write(struct ebitmap *e, void *fp); | ||
126 | 127 | ||
127 | #ifdef CONFIG_NETLABEL | 128 | #ifdef CONFIG_NETLABEL |
128 | int ebitmap_netlbl_export(struct ebitmap *ebmap, | 129 | int ebitmap_netlbl_export(struct ebitmap *ebmap, |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 3a29704be8ce..94f630d93a5c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include "policydb.h" | 37 | #include "policydb.h" |
38 | #include "conditional.h" | 38 | #include "conditional.h" |
39 | #include "mls.h" | 39 | #include "mls.h" |
40 | #include "services.h" | ||
40 | 41 | ||
41 | #define _DEBUG_HASHES | 42 | #define _DEBUG_HASHES |
42 | 43 | ||
@@ -185,9 +186,19 @@ static u32 rangetr_hash(struct hashtab *h, const void *k) | |||
185 | static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) | 186 | static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) |
186 | { | 187 | { |
187 | const struct range_trans *key1 = k1, *key2 = k2; | 188 | const struct range_trans *key1 = k1, *key2 = k2; |
188 | return (key1->source_type != key2->source_type || | 189 | int v; |
189 | key1->target_type != key2->target_type || | 190 | |
190 | key1->target_class != key2->target_class); | 191 | v = key1->source_type - key2->source_type; |
192 | if (v) | ||
193 | return v; | ||
194 | |||
195 | v = key1->target_type - key2->target_type; | ||
196 | if (v) | ||
197 | return v; | ||
198 | |||
199 | v = key1->target_class - key2->target_class; | ||
200 | |||
201 | return v; | ||
191 | } | 202 | } |
192 | 203 | ||
193 | /* | 204 | /* |
@@ -1624,11 +1635,11 @@ static int role_bounds_sanity_check(void *key, void *datum, void *datap) | |||
1624 | 1635 | ||
1625 | static int type_bounds_sanity_check(void *key, void *datum, void *datap) | 1636 | static int type_bounds_sanity_check(void *key, void *datum, void *datap) |
1626 | { | 1637 | { |
1627 | struct type_datum *upper, *type; | 1638 | struct type_datum *upper; |
1628 | struct policydb *p = datap; | 1639 | struct policydb *p = datap; |
1629 | int depth = 0; | 1640 | int depth = 0; |
1630 | 1641 | ||
1631 | upper = type = datum; | 1642 | upper = datum; |
1632 | while (upper->bounds) { | 1643 | while (upper->bounds) { |
1633 | if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { | 1644 | if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { |
1634 | printk(KERN_ERR "SELinux: type %s: " | 1645 | printk(KERN_ERR "SELinux: type %s: " |
@@ -2306,3 +2317,843 @@ bad: | |||
2306 | policydb_destroy(p); | 2317 | policydb_destroy(p); |
2307 | goto out; | 2318 | goto out; |
2308 | } | 2319 | } |
2320 | |||
2321 | /* | ||
2322 | * Write a MLS level structure to a policydb binary | ||
2323 | * representation file. | ||
2324 | */ | ||
2325 | static int mls_write_level(struct mls_level *l, void *fp) | ||
2326 | { | ||
2327 | __le32 buf[1]; | ||
2328 | int rc; | ||
2329 | |||
2330 | buf[0] = cpu_to_le32(l->sens); | ||
2331 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2332 | if (rc) | ||
2333 | return rc; | ||
2334 | |||
2335 | rc = ebitmap_write(&l->cat, fp); | ||
2336 | if (rc) | ||
2337 | return rc; | ||
2338 | |||
2339 | return 0; | ||
2340 | } | ||
2341 | |||
2342 | /* | ||
2343 | * Write a MLS range structure to a policydb binary | ||
2344 | * representation file. | ||
2345 | */ | ||
2346 | static int mls_write_range_helper(struct mls_range *r, void *fp) | ||
2347 | { | ||
2348 | __le32 buf[3]; | ||
2349 | size_t items; | ||
2350 | int rc, eq; | ||
2351 | |||
2352 | eq = mls_level_eq(&r->level[1], &r->level[0]); | ||
2353 | |||
2354 | if (eq) | ||
2355 | items = 2; | ||
2356 | else | ||
2357 | items = 3; | ||
2358 | buf[0] = cpu_to_le32(items-1); | ||
2359 | buf[1] = cpu_to_le32(r->level[0].sens); | ||
2360 | if (!eq) | ||
2361 | buf[2] = cpu_to_le32(r->level[1].sens); | ||
2362 | |||
2363 | BUG_ON(items > (sizeof(buf)/sizeof(buf[0]))); | ||
2364 | |||
2365 | rc = put_entry(buf, sizeof(u32), items, fp); | ||
2366 | if (rc) | ||
2367 | return rc; | ||
2368 | |||
2369 | rc = ebitmap_write(&r->level[0].cat, fp); | ||
2370 | if (rc) | ||
2371 | return rc; | ||
2372 | if (!eq) { | ||
2373 | rc = ebitmap_write(&r->level[1].cat, fp); | ||
2374 | if (rc) | ||
2375 | return rc; | ||
2376 | } | ||
2377 | |||
2378 | return 0; | ||
2379 | } | ||
2380 | |||
2381 | static int sens_write(void *vkey, void *datum, void *ptr) | ||
2382 | { | ||
2383 | char *key = vkey; | ||
2384 | struct level_datum *levdatum = datum; | ||
2385 | struct policy_data *pd = ptr; | ||
2386 | void *fp = pd->fp; | ||
2387 | __le32 buf[2]; | ||
2388 | size_t len; | ||
2389 | int rc; | ||
2390 | |||
2391 | len = strlen(key); | ||
2392 | buf[0] = cpu_to_le32(len); | ||
2393 | buf[1] = cpu_to_le32(levdatum->isalias); | ||
2394 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2395 | if (rc) | ||
2396 | return rc; | ||
2397 | |||
2398 | rc = put_entry(key, 1, len, fp); | ||
2399 | if (rc) | ||
2400 | return rc; | ||
2401 | |||
2402 | rc = mls_write_level(levdatum->level, fp); | ||
2403 | if (rc) | ||
2404 | return rc; | ||
2405 | |||
2406 | return 0; | ||
2407 | } | ||
2408 | |||
2409 | static int cat_write(void *vkey, void *datum, void *ptr) | ||
2410 | { | ||
2411 | char *key = vkey; | ||
2412 | struct cat_datum *catdatum = datum; | ||
2413 | struct policy_data *pd = ptr; | ||
2414 | void *fp = pd->fp; | ||
2415 | __le32 buf[3]; | ||
2416 | size_t len; | ||
2417 | int rc; | ||
2418 | |||
2419 | len = strlen(key); | ||
2420 | buf[0] = cpu_to_le32(len); | ||
2421 | buf[1] = cpu_to_le32(catdatum->value); | ||
2422 | buf[2] = cpu_to_le32(catdatum->isalias); | ||
2423 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
2424 | if (rc) | ||
2425 | return rc; | ||
2426 | |||
2427 | rc = put_entry(key, 1, len, fp); | ||
2428 | if (rc) | ||
2429 | return rc; | ||
2430 | |||
2431 | return 0; | ||
2432 | } | ||
2433 | |||
2434 | static int role_trans_write(struct role_trans *r, void *fp) | ||
2435 | { | ||
2436 | struct role_trans *tr; | ||
2437 | u32 buf[3]; | ||
2438 | size_t nel; | ||
2439 | int rc; | ||
2440 | |||
2441 | nel = 0; | ||
2442 | for (tr = r; tr; tr = tr->next) | ||
2443 | nel++; | ||
2444 | buf[0] = cpu_to_le32(nel); | ||
2445 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2446 | if (rc) | ||
2447 | return rc; | ||
2448 | for (tr = r; tr; tr = tr->next) { | ||
2449 | buf[0] = cpu_to_le32(tr->role); | ||
2450 | buf[1] = cpu_to_le32(tr->type); | ||
2451 | buf[2] = cpu_to_le32(tr->new_role); | ||
2452 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
2453 | if (rc) | ||
2454 | return rc; | ||
2455 | } | ||
2456 | |||
2457 | return 0; | ||
2458 | } | ||
2459 | |||
2460 | static int role_allow_write(struct role_allow *r, void *fp) | ||
2461 | { | ||
2462 | struct role_allow *ra; | ||
2463 | u32 buf[2]; | ||
2464 | size_t nel; | ||
2465 | int rc; | ||
2466 | |||
2467 | nel = 0; | ||
2468 | for (ra = r; ra; ra = ra->next) | ||
2469 | nel++; | ||
2470 | buf[0] = cpu_to_le32(nel); | ||
2471 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2472 | if (rc) | ||
2473 | return rc; | ||
2474 | for (ra = r; ra; ra = ra->next) { | ||
2475 | buf[0] = cpu_to_le32(ra->role); | ||
2476 | buf[1] = cpu_to_le32(ra->new_role); | ||
2477 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2478 | if (rc) | ||
2479 | return rc; | ||
2480 | } | ||
2481 | return 0; | ||
2482 | } | ||
2483 | |||
2484 | /* | ||
2485 | * Write a security context structure | ||
2486 | * to a policydb binary representation file. | ||
2487 | */ | ||
2488 | static int context_write(struct policydb *p, struct context *c, | ||
2489 | void *fp) | ||
2490 | { | ||
2491 | int rc; | ||
2492 | __le32 buf[3]; | ||
2493 | |||
2494 | buf[0] = cpu_to_le32(c->user); | ||
2495 | buf[1] = cpu_to_le32(c->role); | ||
2496 | buf[2] = cpu_to_le32(c->type); | ||
2497 | |||
2498 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
2499 | if (rc) | ||
2500 | return rc; | ||
2501 | |||
2502 | rc = mls_write_range_helper(&c->range, fp); | ||
2503 | if (rc) | ||
2504 | return rc; | ||
2505 | |||
2506 | return 0; | ||
2507 | } | ||
2508 | |||
2509 | /* | ||
2510 | * The following *_write functions are used to | ||
2511 | * write the symbol data to a policy database | ||
2512 | * binary representation file. | ||
2513 | */ | ||
2514 | |||
2515 | static int perm_write(void *vkey, void *datum, void *fp) | ||
2516 | { | ||
2517 | char *key = vkey; | ||
2518 | struct perm_datum *perdatum = datum; | ||
2519 | __le32 buf[2]; | ||
2520 | size_t len; | ||
2521 | int rc; | ||
2522 | |||
2523 | len = strlen(key); | ||
2524 | buf[0] = cpu_to_le32(len); | ||
2525 | buf[1] = cpu_to_le32(perdatum->value); | ||
2526 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2527 | if (rc) | ||
2528 | return rc; | ||
2529 | |||
2530 | rc = put_entry(key, 1, len, fp); | ||
2531 | if (rc) | ||
2532 | return rc; | ||
2533 | |||
2534 | return 0; | ||
2535 | } | ||
2536 | |||
2537 | static int common_write(void *vkey, void *datum, void *ptr) | ||
2538 | { | ||
2539 | char *key = vkey; | ||
2540 | struct common_datum *comdatum = datum; | ||
2541 | struct policy_data *pd = ptr; | ||
2542 | void *fp = pd->fp; | ||
2543 | __le32 buf[4]; | ||
2544 | size_t len; | ||
2545 | int rc; | ||
2546 | |||
2547 | len = strlen(key); | ||
2548 | buf[0] = cpu_to_le32(len); | ||
2549 | buf[1] = cpu_to_le32(comdatum->value); | ||
2550 | buf[2] = cpu_to_le32(comdatum->permissions.nprim); | ||
2551 | buf[3] = cpu_to_le32(comdatum->permissions.table->nel); | ||
2552 | rc = put_entry(buf, sizeof(u32), 4, fp); | ||
2553 | if (rc) | ||
2554 | return rc; | ||
2555 | |||
2556 | rc = put_entry(key, 1, len, fp); | ||
2557 | if (rc) | ||
2558 | return rc; | ||
2559 | |||
2560 | rc = hashtab_map(comdatum->permissions.table, perm_write, fp); | ||
2561 | if (rc) | ||
2562 | return rc; | ||
2563 | |||
2564 | return 0; | ||
2565 | } | ||
2566 | |||
2567 | static int write_cons_helper(struct policydb *p, struct constraint_node *node, | ||
2568 | void *fp) | ||
2569 | { | ||
2570 | struct constraint_node *c; | ||
2571 | struct constraint_expr *e; | ||
2572 | __le32 buf[3]; | ||
2573 | u32 nel; | ||
2574 | int rc; | ||
2575 | |||
2576 | for (c = node; c; c = c->next) { | ||
2577 | nel = 0; | ||
2578 | for (e = c->expr; e; e = e->next) | ||
2579 | nel++; | ||
2580 | buf[0] = cpu_to_le32(c->permissions); | ||
2581 | buf[1] = cpu_to_le32(nel); | ||
2582 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2583 | if (rc) | ||
2584 | return rc; | ||
2585 | for (e = c->expr; e; e = e->next) { | ||
2586 | buf[0] = cpu_to_le32(e->expr_type); | ||
2587 | buf[1] = cpu_to_le32(e->attr); | ||
2588 | buf[2] = cpu_to_le32(e->op); | ||
2589 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
2590 | if (rc) | ||
2591 | return rc; | ||
2592 | |||
2593 | switch (e->expr_type) { | ||
2594 | case CEXPR_NAMES: | ||
2595 | rc = ebitmap_write(&e->names, fp); | ||
2596 | if (rc) | ||
2597 | return rc; | ||
2598 | break; | ||
2599 | default: | ||
2600 | break; | ||
2601 | } | ||
2602 | } | ||
2603 | } | ||
2604 | |||
2605 | return 0; | ||
2606 | } | ||
2607 | |||
2608 | static int class_write(void *vkey, void *datum, void *ptr) | ||
2609 | { | ||
2610 | char *key = vkey; | ||
2611 | struct class_datum *cladatum = datum; | ||
2612 | struct policy_data *pd = ptr; | ||
2613 | void *fp = pd->fp; | ||
2614 | struct policydb *p = pd->p; | ||
2615 | struct constraint_node *c; | ||
2616 | __le32 buf[6]; | ||
2617 | u32 ncons; | ||
2618 | size_t len, len2; | ||
2619 | int rc; | ||
2620 | |||
2621 | len = strlen(key); | ||
2622 | if (cladatum->comkey) | ||
2623 | len2 = strlen(cladatum->comkey); | ||
2624 | else | ||
2625 | len2 = 0; | ||
2626 | |||
2627 | ncons = 0; | ||
2628 | for (c = cladatum->constraints; c; c = c->next) | ||
2629 | ncons++; | ||
2630 | |||
2631 | buf[0] = cpu_to_le32(len); | ||
2632 | buf[1] = cpu_to_le32(len2); | ||
2633 | buf[2] = cpu_to_le32(cladatum->value); | ||
2634 | buf[3] = cpu_to_le32(cladatum->permissions.nprim); | ||
2635 | if (cladatum->permissions.table) | ||
2636 | buf[4] = cpu_to_le32(cladatum->permissions.table->nel); | ||
2637 | else | ||
2638 | buf[4] = 0; | ||
2639 | buf[5] = cpu_to_le32(ncons); | ||
2640 | rc = put_entry(buf, sizeof(u32), 6, fp); | ||
2641 | if (rc) | ||
2642 | return rc; | ||
2643 | |||
2644 | rc = put_entry(key, 1, len, fp); | ||
2645 | if (rc) | ||
2646 | return rc; | ||
2647 | |||
2648 | if (cladatum->comkey) { | ||
2649 | rc = put_entry(cladatum->comkey, 1, len2, fp); | ||
2650 | if (rc) | ||
2651 | return rc; | ||
2652 | } | ||
2653 | |||
2654 | rc = hashtab_map(cladatum->permissions.table, perm_write, fp); | ||
2655 | if (rc) | ||
2656 | return rc; | ||
2657 | |||
2658 | rc = write_cons_helper(p, cladatum->constraints, fp); | ||
2659 | if (rc) | ||
2660 | return rc; | ||
2661 | |||
2662 | /* write out the validatetrans rule */ | ||
2663 | ncons = 0; | ||
2664 | for (c = cladatum->validatetrans; c; c = c->next) | ||
2665 | ncons++; | ||
2666 | |||
2667 | buf[0] = cpu_to_le32(ncons); | ||
2668 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2669 | if (rc) | ||
2670 | return rc; | ||
2671 | |||
2672 | rc = write_cons_helper(p, cladatum->validatetrans, fp); | ||
2673 | if (rc) | ||
2674 | return rc; | ||
2675 | |||
2676 | return 0; | ||
2677 | } | ||
2678 | |||
2679 | static int role_write(void *vkey, void *datum, void *ptr) | ||
2680 | { | ||
2681 | char *key = vkey; | ||
2682 | struct role_datum *role = datum; | ||
2683 | struct policy_data *pd = ptr; | ||
2684 | void *fp = pd->fp; | ||
2685 | struct policydb *p = pd->p; | ||
2686 | __le32 buf[3]; | ||
2687 | size_t items, len; | ||
2688 | int rc; | ||
2689 | |||
2690 | len = strlen(key); | ||
2691 | items = 0; | ||
2692 | buf[items++] = cpu_to_le32(len); | ||
2693 | buf[items++] = cpu_to_le32(role->value); | ||
2694 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | ||
2695 | buf[items++] = cpu_to_le32(role->bounds); | ||
2696 | |||
2697 | BUG_ON(items > (sizeof(buf)/sizeof(buf[0]))); | ||
2698 | |||
2699 | rc = put_entry(buf, sizeof(u32), items, fp); | ||
2700 | if (rc) | ||
2701 | return rc; | ||
2702 | |||
2703 | rc = put_entry(key, 1, len, fp); | ||
2704 | if (rc) | ||
2705 | return rc; | ||
2706 | |||
2707 | rc = ebitmap_write(&role->dominates, fp); | ||
2708 | if (rc) | ||
2709 | return rc; | ||
2710 | |||
2711 | rc = ebitmap_write(&role->types, fp); | ||
2712 | if (rc) | ||
2713 | return rc; | ||
2714 | |||
2715 | return 0; | ||
2716 | } | ||
2717 | |||
2718 | static int type_write(void *vkey, void *datum, void *ptr) | ||
2719 | { | ||
2720 | char *key = vkey; | ||
2721 | struct type_datum *typdatum = datum; | ||
2722 | struct policy_data *pd = ptr; | ||
2723 | struct policydb *p = pd->p; | ||
2724 | void *fp = pd->fp; | ||
2725 | __le32 buf[4]; | ||
2726 | int rc; | ||
2727 | size_t items, len; | ||
2728 | |||
2729 | len = strlen(key); | ||
2730 | items = 0; | ||
2731 | buf[items++] = cpu_to_le32(len); | ||
2732 | buf[items++] = cpu_to_le32(typdatum->value); | ||
2733 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) { | ||
2734 | u32 properties = 0; | ||
2735 | |||
2736 | if (typdatum->primary) | ||
2737 | properties |= TYPEDATUM_PROPERTY_PRIMARY; | ||
2738 | |||
2739 | if (typdatum->attribute) | ||
2740 | properties |= TYPEDATUM_PROPERTY_ATTRIBUTE; | ||
2741 | |||
2742 | buf[items++] = cpu_to_le32(properties); | ||
2743 | buf[items++] = cpu_to_le32(typdatum->bounds); | ||
2744 | } else { | ||
2745 | buf[items++] = cpu_to_le32(typdatum->primary); | ||
2746 | } | ||
2747 | BUG_ON(items > (sizeof(buf) / sizeof(buf[0]))); | ||
2748 | rc = put_entry(buf, sizeof(u32), items, fp); | ||
2749 | if (rc) | ||
2750 | return rc; | ||
2751 | |||
2752 | rc = put_entry(key, 1, len, fp); | ||
2753 | if (rc) | ||
2754 | return rc; | ||
2755 | |||
2756 | return 0; | ||
2757 | } | ||
2758 | |||
2759 | static int user_write(void *vkey, void *datum, void *ptr) | ||
2760 | { | ||
2761 | char *key = vkey; | ||
2762 | struct user_datum *usrdatum = datum; | ||
2763 | struct policy_data *pd = ptr; | ||
2764 | struct policydb *p = pd->p; | ||
2765 | void *fp = pd->fp; | ||
2766 | __le32 buf[3]; | ||
2767 | size_t items, len; | ||
2768 | int rc; | ||
2769 | |||
2770 | len = strlen(key); | ||
2771 | items = 0; | ||
2772 | buf[items++] = cpu_to_le32(len); | ||
2773 | buf[items++] = cpu_to_le32(usrdatum->value); | ||
2774 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | ||
2775 | buf[items++] = cpu_to_le32(usrdatum->bounds); | ||
2776 | BUG_ON(items > (sizeof(buf) / sizeof(buf[0]))); | ||
2777 | rc = put_entry(buf, sizeof(u32), items, fp); | ||
2778 | if (rc) | ||
2779 | return rc; | ||
2780 | |||
2781 | rc = put_entry(key, 1, len, fp); | ||
2782 | if (rc) | ||
2783 | return rc; | ||
2784 | |||
2785 | rc = ebitmap_write(&usrdatum->roles, fp); | ||
2786 | if (rc) | ||
2787 | return rc; | ||
2788 | |||
2789 | rc = mls_write_range_helper(&usrdatum->range, fp); | ||
2790 | if (rc) | ||
2791 | return rc; | ||
2792 | |||
2793 | rc = mls_write_level(&usrdatum->dfltlevel, fp); | ||
2794 | if (rc) | ||
2795 | return rc; | ||
2796 | |||
2797 | return 0; | ||
2798 | } | ||
2799 | |||
2800 | static int (*write_f[SYM_NUM]) (void *key, void *datum, | ||
2801 | void *datap) = | ||
2802 | { | ||
2803 | common_write, | ||
2804 | class_write, | ||
2805 | role_write, | ||
2806 | type_write, | ||
2807 | user_write, | ||
2808 | cond_write_bool, | ||
2809 | sens_write, | ||
2810 | cat_write, | ||
2811 | }; | ||
2812 | |||
2813 | static int ocontext_write(struct policydb *p, struct policydb_compat_info *info, | ||
2814 | void *fp) | ||
2815 | { | ||
2816 | unsigned int i, j, rc; | ||
2817 | size_t nel, len; | ||
2818 | __le32 buf[3]; | ||
2819 | u32 nodebuf[8]; | ||
2820 | struct ocontext *c; | ||
2821 | for (i = 0; i < info->ocon_num; i++) { | ||
2822 | nel = 0; | ||
2823 | for (c = p->ocontexts[i]; c; c = c->next) | ||
2824 | nel++; | ||
2825 | buf[0] = cpu_to_le32(nel); | ||
2826 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2827 | if (rc) | ||
2828 | return rc; | ||
2829 | for (c = p->ocontexts[i]; c; c = c->next) { | ||
2830 | switch (i) { | ||
2831 | case OCON_ISID: | ||
2832 | buf[0] = cpu_to_le32(c->sid[0]); | ||
2833 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2834 | if (rc) | ||
2835 | return rc; | ||
2836 | rc = context_write(p, &c->context[0], fp); | ||
2837 | if (rc) | ||
2838 | return rc; | ||
2839 | break; | ||
2840 | case OCON_FS: | ||
2841 | case OCON_NETIF: | ||
2842 | len = strlen(c->u.name); | ||
2843 | buf[0] = cpu_to_le32(len); | ||
2844 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2845 | if (rc) | ||
2846 | return rc; | ||
2847 | rc = put_entry(c->u.name, 1, len, fp); | ||
2848 | if (rc) | ||
2849 | return rc; | ||
2850 | rc = context_write(p, &c->context[0], fp); | ||
2851 | if (rc) | ||
2852 | return rc; | ||
2853 | rc = context_write(p, &c->context[1], fp); | ||
2854 | if (rc) | ||
2855 | return rc; | ||
2856 | break; | ||
2857 | case OCON_PORT: | ||
2858 | buf[0] = cpu_to_le32(c->u.port.protocol); | ||
2859 | buf[1] = cpu_to_le32(c->u.port.low_port); | ||
2860 | buf[2] = cpu_to_le32(c->u.port.high_port); | ||
2861 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
2862 | if (rc) | ||
2863 | return rc; | ||
2864 | rc = context_write(p, &c->context[0], fp); | ||
2865 | if (rc) | ||
2866 | return rc; | ||
2867 | break; | ||
2868 | case OCON_NODE: | ||
2869 | nodebuf[0] = c->u.node.addr; /* network order */ | ||
2870 | nodebuf[1] = c->u.node.mask; /* network order */ | ||
2871 | rc = put_entry(nodebuf, sizeof(u32), 2, fp); | ||
2872 | if (rc) | ||
2873 | return rc; | ||
2874 | rc = context_write(p, &c->context[0], fp); | ||
2875 | if (rc) | ||
2876 | return rc; | ||
2877 | break; | ||
2878 | case OCON_FSUSE: | ||
2879 | buf[0] = cpu_to_le32(c->v.behavior); | ||
2880 | len = strlen(c->u.name); | ||
2881 | buf[1] = cpu_to_le32(len); | ||
2882 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2883 | if (rc) | ||
2884 | return rc; | ||
2885 | rc = put_entry(c->u.name, 1, len, fp); | ||
2886 | if (rc) | ||
2887 | return rc; | ||
2888 | rc = context_write(p, &c->context[0], fp); | ||
2889 | if (rc) | ||
2890 | return rc; | ||
2891 | break; | ||
2892 | case OCON_NODE6: | ||
2893 | for (j = 0; j < 4; j++) | ||
2894 | nodebuf[j] = c->u.node6.addr[j]; /* network order */ | ||
2895 | for (j = 0; j < 4; j++) | ||
2896 | nodebuf[j + 4] = c->u.node6.mask[j]; /* network order */ | ||
2897 | rc = put_entry(nodebuf, sizeof(u32), 8, fp); | ||
2898 | if (rc) | ||
2899 | return rc; | ||
2900 | rc = context_write(p, &c->context[0], fp); | ||
2901 | if (rc) | ||
2902 | return rc; | ||
2903 | break; | ||
2904 | } | ||
2905 | } | ||
2906 | } | ||
2907 | return 0; | ||
2908 | } | ||
2909 | |||
2910 | static int genfs_write(struct policydb *p, void *fp) | ||
2911 | { | ||
2912 | struct genfs *genfs; | ||
2913 | struct ocontext *c; | ||
2914 | size_t len; | ||
2915 | __le32 buf[1]; | ||
2916 | int rc; | ||
2917 | |||
2918 | len = 0; | ||
2919 | for (genfs = p->genfs; genfs; genfs = genfs->next) | ||
2920 | len++; | ||
2921 | buf[0] = cpu_to_le32(len); | ||
2922 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2923 | if (rc) | ||
2924 | return rc; | ||
2925 | for (genfs = p->genfs; genfs; genfs = genfs->next) { | ||
2926 | len = strlen(genfs->fstype); | ||
2927 | buf[0] = cpu_to_le32(len); | ||
2928 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2929 | if (rc) | ||
2930 | return rc; | ||
2931 | rc = put_entry(genfs->fstype, 1, len, fp); | ||
2932 | if (rc) | ||
2933 | return rc; | ||
2934 | len = 0; | ||
2935 | for (c = genfs->head; c; c = c->next) | ||
2936 | len++; | ||
2937 | buf[0] = cpu_to_le32(len); | ||
2938 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2939 | if (rc) | ||
2940 | return rc; | ||
2941 | for (c = genfs->head; c; c = c->next) { | ||
2942 | len = strlen(c->u.name); | ||
2943 | buf[0] = cpu_to_le32(len); | ||
2944 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2945 | if (rc) | ||
2946 | return rc; | ||
2947 | rc = put_entry(c->u.name, 1, len, fp); | ||
2948 | if (rc) | ||
2949 | return rc; | ||
2950 | buf[0] = cpu_to_le32(c->v.sclass); | ||
2951 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2952 | if (rc) | ||
2953 | return rc; | ||
2954 | rc = context_write(p, &c->context[0], fp); | ||
2955 | if (rc) | ||
2956 | return rc; | ||
2957 | } | ||
2958 | } | ||
2959 | return 0; | ||
2960 | } | ||
2961 | |||
2962 | static int range_count(void *key, void *data, void *ptr) | ||
2963 | { | ||
2964 | int *cnt = ptr; | ||
2965 | *cnt = *cnt + 1; | ||
2966 | |||
2967 | return 0; | ||
2968 | } | ||
2969 | |||
2970 | static int range_write_helper(void *key, void *data, void *ptr) | ||
2971 | { | ||
2972 | __le32 buf[2]; | ||
2973 | struct range_trans *rt = key; | ||
2974 | struct mls_range *r = data; | ||
2975 | struct policy_data *pd = ptr; | ||
2976 | void *fp = pd->fp; | ||
2977 | struct policydb *p = pd->p; | ||
2978 | int rc; | ||
2979 | |||
2980 | buf[0] = cpu_to_le32(rt->source_type); | ||
2981 | buf[1] = cpu_to_le32(rt->target_type); | ||
2982 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2983 | if (rc) | ||
2984 | return rc; | ||
2985 | if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) { | ||
2986 | buf[0] = cpu_to_le32(rt->target_class); | ||
2987 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2988 | if (rc) | ||
2989 | return rc; | ||
2990 | } | ||
2991 | rc = mls_write_range_helper(r, fp); | ||
2992 | if (rc) | ||
2993 | return rc; | ||
2994 | |||
2995 | return 0; | ||
2996 | } | ||
2997 | |||
2998 | static int range_write(struct policydb *p, void *fp) | ||
2999 | { | ||
3000 | size_t nel; | ||
3001 | __le32 buf[1]; | ||
3002 | int rc; | ||
3003 | struct policy_data pd; | ||
3004 | |||
3005 | pd.p = p; | ||
3006 | pd.fp = fp; | ||
3007 | |||
3008 | /* count the number of entries in the hashtab */ | ||
3009 | nel = 0; | ||
3010 | rc = hashtab_map(p->range_tr, range_count, &nel); | ||
3011 | if (rc) | ||
3012 | return rc; | ||
3013 | |||
3014 | buf[0] = cpu_to_le32(nel); | ||
3015 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
3016 | if (rc) | ||
3017 | return rc; | ||
3018 | |||
3019 | /* actually write all of the entries */ | ||
3020 | rc = hashtab_map(p->range_tr, range_write_helper, &pd); | ||
3021 | if (rc) | ||
3022 | return rc; | ||
3023 | |||
3024 | return 0; | ||
3025 | } | ||
3026 | |||
3027 | /* | ||
3028 | * Write the configuration data in a policy database | ||
3029 | * structure to a policy database binary representation | ||
3030 | * file. | ||
3031 | */ | ||
3032 | int policydb_write(struct policydb *p, void *fp) | ||
3033 | { | ||
3034 | unsigned int i, num_syms; | ||
3035 | int rc; | ||
3036 | __le32 buf[4]; | ||
3037 | u32 config; | ||
3038 | size_t len; | ||
3039 | struct policydb_compat_info *info; | ||
3040 | |||
3041 | /* | ||
3042 | * refuse to write policy older than compressed avtab | ||
3043 | * to simplify the writer. There are other tests dropped | ||
3044 | * since we assume this throughout the writer code. Be | ||
3045 | * careful if you ever try to remove this restriction | ||
3046 | */ | ||
3047 | if (p->policyvers < POLICYDB_VERSION_AVTAB) { | ||
3048 | printk(KERN_ERR "SELinux: refusing to write policy version %d." | ||
3049 | " Because it is less than version %d\n", p->policyvers, | ||
3050 | POLICYDB_VERSION_AVTAB); | ||
3051 | return -EINVAL; | ||
3052 | } | ||
3053 | |||
3054 | config = 0; | ||
3055 | if (p->mls_enabled) | ||
3056 | config |= POLICYDB_CONFIG_MLS; | ||
3057 | |||
3058 | if (p->reject_unknown) | ||
3059 | config |= REJECT_UNKNOWN; | ||
3060 | if (p->allow_unknown) | ||
3061 | config |= ALLOW_UNKNOWN; | ||
3062 | |||
3063 | /* Write the magic number and string identifiers. */ | ||
3064 | buf[0] = cpu_to_le32(POLICYDB_MAGIC); | ||
3065 | len = strlen(POLICYDB_STRING); | ||
3066 | buf[1] = cpu_to_le32(len); | ||
3067 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
3068 | if (rc) | ||
3069 | return rc; | ||
3070 | rc = put_entry(POLICYDB_STRING, 1, len, fp); | ||
3071 | if (rc) | ||
3072 | return rc; | ||
3073 | |||
3074 | /* Write the version, config, and table sizes. */ | ||
3075 | info = policydb_lookup_compat(p->policyvers); | ||
3076 | if (!info) { | ||
3077 | printk(KERN_ERR "SELinux: compatibility lookup failed for policy " | ||
3078 | "version %d", p->policyvers); | ||
3079 | return rc; | ||
3080 | } | ||
3081 | |||
3082 | buf[0] = cpu_to_le32(p->policyvers); | ||
3083 | buf[1] = cpu_to_le32(config); | ||
3084 | buf[2] = cpu_to_le32(info->sym_num); | ||
3085 | buf[3] = cpu_to_le32(info->ocon_num); | ||
3086 | |||
3087 | rc = put_entry(buf, sizeof(u32), 4, fp); | ||
3088 | if (rc) | ||
3089 | return rc; | ||
3090 | |||
3091 | if (p->policyvers >= POLICYDB_VERSION_POLCAP) { | ||
3092 | rc = ebitmap_write(&p->policycaps, fp); | ||
3093 | if (rc) | ||
3094 | return rc; | ||
3095 | } | ||
3096 | |||
3097 | if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) { | ||
3098 | rc = ebitmap_write(&p->permissive_map, fp); | ||
3099 | if (rc) | ||
3100 | return rc; | ||
3101 | } | ||
3102 | |||
3103 | num_syms = info->sym_num; | ||
3104 | for (i = 0; i < num_syms; i++) { | ||
3105 | struct policy_data pd; | ||
3106 | |||
3107 | pd.fp = fp; | ||
3108 | pd.p = p; | ||
3109 | |||
3110 | buf[0] = cpu_to_le32(p->symtab[i].nprim); | ||
3111 | buf[1] = cpu_to_le32(p->symtab[i].table->nel); | ||
3112 | |||
3113 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
3114 | if (rc) | ||
3115 | return rc; | ||
3116 | rc = hashtab_map(p->symtab[i].table, write_f[i], &pd); | ||
3117 | if (rc) | ||
3118 | return rc; | ||
3119 | } | ||
3120 | |||
3121 | rc = avtab_write(p, &p->te_avtab, fp); | ||
3122 | if (rc) | ||
3123 | return rc; | ||
3124 | |||
3125 | rc = cond_write_list(p, p->cond_list, fp); | ||
3126 | if (rc) | ||
3127 | return rc; | ||
3128 | |||
3129 | rc = role_trans_write(p->role_tr, fp); | ||
3130 | if (rc) | ||
3131 | return rc; | ||
3132 | |||
3133 | rc = role_allow_write(p->role_allow, fp); | ||
3134 | if (rc) | ||
3135 | return rc; | ||
3136 | |||
3137 | rc = ocontext_write(p, info, fp); | ||
3138 | if (rc) | ||
3139 | return rc; | ||
3140 | |||
3141 | rc = genfs_write(p, fp); | ||
3142 | if (rc) | ||
3143 | return rc; | ||
3144 | |||
3145 | rc = range_write(p, fp); | ||
3146 | if (rc) | ||
3147 | return rc; | ||
3148 | |||
3149 | for (i = 0; i < p->p_types.nprim; i++) { | ||
3150 | struct ebitmap *e = flex_array_get(p->type_attr_map_array, i); | ||
3151 | |||
3152 | BUG_ON(!e); | ||
3153 | rc = ebitmap_write(e, fp); | ||
3154 | if (rc) | ||
3155 | return rc; | ||
3156 | } | ||
3157 | |||
3158 | return 0; | ||
3159 | } | ||
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 310e94442cb8..95d3d7de361e 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -254,6 +254,9 @@ struct policydb { | |||
254 | 254 | ||
255 | struct ebitmap permissive_map; | 255 | struct ebitmap permissive_map; |
256 | 256 | ||
257 | /* length of this policy when it was loaded */ | ||
258 | size_t len; | ||
259 | |||
257 | unsigned int policyvers; | 260 | unsigned int policyvers; |
258 | 261 | ||
259 | unsigned int reject_unknown : 1; | 262 | unsigned int reject_unknown : 1; |
@@ -270,6 +273,7 @@ extern int policydb_class_isvalid(struct policydb *p, unsigned int class); | |||
270 | extern int policydb_type_isvalid(struct policydb *p, unsigned int type); | 273 | extern int policydb_type_isvalid(struct policydb *p, unsigned int type); |
271 | extern int policydb_role_isvalid(struct policydb *p, unsigned int role); | 274 | extern int policydb_role_isvalid(struct policydb *p, unsigned int role); |
272 | extern int policydb_read(struct policydb *p, void *fp); | 275 | extern int policydb_read(struct policydb *p, void *fp); |
276 | extern int policydb_write(struct policydb *p, void *fp); | ||
273 | 277 | ||
274 | #define PERM_SYMTAB_SIZE 32 | 278 | #define PERM_SYMTAB_SIZE 32 |
275 | 279 | ||
@@ -290,6 +294,11 @@ struct policy_file { | |||
290 | size_t len; | 294 | size_t len; |
291 | }; | 295 | }; |
292 | 296 | ||
297 | struct policy_data { | ||
298 | struct policydb *p; | ||
299 | void *fp; | ||
300 | }; | ||
301 | |||
293 | static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) | 302 | static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) |
294 | { | 303 | { |
295 | if (bytes > fp->len) | 304 | if (bytes > fp->len) |
@@ -301,6 +310,17 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) | |||
301 | return 0; | 310 | return 0; |
302 | } | 311 | } |
303 | 312 | ||
313 | static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file *fp) | ||
314 | { | ||
315 | size_t len = bytes * num; | ||
316 | |||
317 | memcpy(fp->data, buf, len); | ||
318 | fp->data += len; | ||
319 | fp->len -= len; | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
304 | extern u16 string_to_security_class(struct policydb *p, const char *name); | 324 | extern u16 string_to_security_class(struct policydb *p, const char *name); |
305 | extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); | 325 | extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); |
306 | 326 | ||
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 9ea2feca3cd4..223c1ff6ef23 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/mutex.h> | 51 | #include <linux/mutex.h> |
52 | #include <linux/selinux.h> | 52 | #include <linux/selinux.h> |
53 | #include <linux/flex_array.h> | 53 | #include <linux/flex_array.h> |
54 | #include <linux/vmalloc.h> | ||
54 | #include <net/netlabel.h> | 55 | #include <net/netlabel.h> |
55 | 56 | ||
56 | #include "flask.h" | 57 | #include "flask.h" |
@@ -991,7 +992,8 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 | |||
991 | { | 992 | { |
992 | char *scontextp; | 993 | char *scontextp; |
993 | 994 | ||
994 | *scontext = NULL; | 995 | if (scontext) |
996 | *scontext = NULL; | ||
995 | *scontext_len = 0; | 997 | *scontext_len = 0; |
996 | 998 | ||
997 | if (context->len) { | 999 | if (context->len) { |
@@ -1008,6 +1010,9 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 | |||
1008 | *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1; | 1010 | *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1; |
1009 | *scontext_len += mls_compute_context_len(context); | 1011 | *scontext_len += mls_compute_context_len(context); |
1010 | 1012 | ||
1013 | if (!scontext) | ||
1014 | return 0; | ||
1015 | |||
1011 | /* Allocate space for the context; caller must free this space. */ | 1016 | /* Allocate space for the context; caller must free this space. */ |
1012 | scontextp = kmalloc(*scontext_len, GFP_ATOMIC); | 1017 | scontextp = kmalloc(*scontext_len, GFP_ATOMIC); |
1013 | if (!scontextp) | 1018 | if (!scontextp) |
@@ -1047,7 +1052,8 @@ static int security_sid_to_context_core(u32 sid, char **scontext, | |||
1047 | struct context *context; | 1052 | struct context *context; |
1048 | int rc = 0; | 1053 | int rc = 0; |
1049 | 1054 | ||
1050 | *scontext = NULL; | 1055 | if (scontext) |
1056 | *scontext = NULL; | ||
1051 | *scontext_len = 0; | 1057 | *scontext_len = 0; |
1052 | 1058 | ||
1053 | if (!ss_initialized) { | 1059 | if (!ss_initialized) { |
@@ -1055,6 +1061,8 @@ static int security_sid_to_context_core(u32 sid, char **scontext, | |||
1055 | char *scontextp; | 1061 | char *scontextp; |
1056 | 1062 | ||
1057 | *scontext_len = strlen(initial_sid_to_string[sid]) + 1; | 1063 | *scontext_len = strlen(initial_sid_to_string[sid]) + 1; |
1064 | if (!scontext) | ||
1065 | goto out; | ||
1058 | scontextp = kmalloc(*scontext_len, GFP_ATOMIC); | 1066 | scontextp = kmalloc(*scontext_len, GFP_ATOMIC); |
1059 | if (!scontextp) { | 1067 | if (!scontextp) { |
1060 | rc = -ENOMEM; | 1068 | rc = -ENOMEM; |
@@ -1769,6 +1777,7 @@ int security_load_policy(void *data, size_t len) | |||
1769 | return rc; | 1777 | return rc; |
1770 | } | 1778 | } |
1771 | 1779 | ||
1780 | policydb.len = len; | ||
1772 | rc = selinux_set_mapping(&policydb, secclass_map, | 1781 | rc = selinux_set_mapping(&policydb, secclass_map, |
1773 | ¤t_mapping, | 1782 | ¤t_mapping, |
1774 | ¤t_mapping_size); | 1783 | ¤t_mapping_size); |
@@ -1791,6 +1800,7 @@ int security_load_policy(void *data, size_t len) | |||
1791 | selinux_complete_init(); | 1800 | selinux_complete_init(); |
1792 | avc_ss_reset(seqno); | 1801 | avc_ss_reset(seqno); |
1793 | selnl_notify_policyload(seqno); | 1802 | selnl_notify_policyload(seqno); |
1803 | selinux_status_update_policyload(seqno); | ||
1794 | selinux_netlbl_cache_invalidate(); | 1804 | selinux_netlbl_cache_invalidate(); |
1795 | selinux_xfrm_notify_policyload(); | 1805 | selinux_xfrm_notify_policyload(); |
1796 | return 0; | 1806 | return 0; |
@@ -1804,6 +1814,7 @@ int security_load_policy(void *data, size_t len) | |||
1804 | if (rc) | 1814 | if (rc) |
1805 | return rc; | 1815 | return rc; |
1806 | 1816 | ||
1817 | newpolicydb.len = len; | ||
1807 | /* If switching between different policy types, log MLS status */ | 1818 | /* If switching between different policy types, log MLS status */ |
1808 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) | 1819 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) |
1809 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); | 1820 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); |
@@ -1870,6 +1881,7 @@ int security_load_policy(void *data, size_t len) | |||
1870 | 1881 | ||
1871 | avc_ss_reset(seqno); | 1882 | avc_ss_reset(seqno); |
1872 | selnl_notify_policyload(seqno); | 1883 | selnl_notify_policyload(seqno); |
1884 | selinux_status_update_policyload(seqno); | ||
1873 | selinux_netlbl_cache_invalidate(); | 1885 | selinux_netlbl_cache_invalidate(); |
1874 | selinux_xfrm_notify_policyload(); | 1886 | selinux_xfrm_notify_policyload(); |
1875 | 1887 | ||
@@ -1883,6 +1895,17 @@ err: | |||
1883 | 1895 | ||
1884 | } | 1896 | } |
1885 | 1897 | ||
1898 | size_t security_policydb_len(void) | ||
1899 | { | ||
1900 | size_t len; | ||
1901 | |||
1902 | read_lock(&policy_rwlock); | ||
1903 | len = policydb.len; | ||
1904 | read_unlock(&policy_rwlock); | ||
1905 | |||
1906 | return len; | ||
1907 | } | ||
1908 | |||
1886 | /** | 1909 | /** |
1887 | * security_port_sid - Obtain the SID for a port. | 1910 | * security_port_sid - Obtain the SID for a port. |
1888 | * @protocol: protocol number | 1911 | * @protocol: protocol number |
@@ -2374,6 +2397,7 @@ out: | |||
2374 | if (!rc) { | 2397 | if (!rc) { |
2375 | avc_ss_reset(seqno); | 2398 | avc_ss_reset(seqno); |
2376 | selnl_notify_policyload(seqno); | 2399 | selnl_notify_policyload(seqno); |
2400 | selinux_status_update_policyload(seqno); | ||
2377 | selinux_xfrm_notify_policyload(); | 2401 | selinux_xfrm_notify_policyload(); |
2378 | } | 2402 | } |
2379 | return rc; | 2403 | return rc; |
@@ -3129,3 +3153,38 @@ netlbl_sid_to_secattr_failure: | |||
3129 | return rc; | 3153 | return rc; |
3130 | } | 3154 | } |
3131 | #endif /* CONFIG_NETLABEL */ | 3155 | #endif /* CONFIG_NETLABEL */ |
3156 | |||
3157 | /** | ||
3158 | * security_read_policy - read the policy. | ||
3159 | * @data: binary policy data | ||
3160 | * @len: length of data in bytes | ||
3161 | * | ||
3162 | */ | ||
3163 | int security_read_policy(void **data, ssize_t *len) | ||
3164 | { | ||
3165 | int rc; | ||
3166 | struct policy_file fp; | ||
3167 | |||
3168 | if (!ss_initialized) | ||
3169 | return -EINVAL; | ||
3170 | |||
3171 | *len = security_policydb_len(); | ||
3172 | |||
3173 | *data = vmalloc_user(*len); | ||
3174 | if (!*data) | ||
3175 | return -ENOMEM; | ||
3176 | |||
3177 | fp.data = *data; | ||
3178 | fp.len = *len; | ||
3179 | |||
3180 | read_lock(&policy_rwlock); | ||
3181 | rc = policydb_write(&policydb, &fp); | ||
3182 | read_unlock(&policy_rwlock); | ||
3183 | |||
3184 | if (rc) | ||
3185 | return rc; | ||
3186 | |||
3187 | *len = (unsigned long)fp.data - (unsigned long)*data; | ||
3188 | return 0; | ||
3189 | |||
3190 | } | ||
diff --git a/security/selinux/ss/status.c b/security/selinux/ss/status.c new file mode 100644 index 000000000000..d982365f9d1a --- /dev/null +++ b/security/selinux/ss/status.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * mmap based event notifications for SELinux | ||
3 | * | ||
4 | * Author: KaiGai Kohei <kaigai@ak.jp.nec.com> | ||
5 | * | ||
6 | * Copyright (C) 2010 NEC corporation | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2, | ||
10 | * as published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/gfp.h> | ||
14 | #include <linux/mm.h> | ||
15 | #include <linux/mutex.h> | ||
16 | #include "avc.h" | ||
17 | #include "services.h" | ||
18 | |||
19 | /* | ||
20 | * The selinux_status_page shall be exposed to userspace applications | ||
21 | * using mmap interface on /selinux/status. | ||
22 | * It enables to notify applications a few events that will cause reset | ||
23 | * of userspace access vector without context switching. | ||
24 | * | ||
25 | * The selinux_kernel_status structure on the head of status page is | ||
26 | * protected from concurrent accesses using seqlock logic, so userspace | ||
27 | * application should reference the status page according to the seqlock | ||
28 | * logic. | ||
29 | * | ||
30 | * Typically, application checks status->sequence at the head of access | ||
31 | * control routine. If it is odd-number, kernel is updating the status, | ||
32 | * so please wait for a moment. If it is changed from the last sequence | ||
33 | * number, it means something happen, so application will reset userspace | ||
34 | * avc, if needed. | ||
35 | * In most cases, application shall confirm the kernel status is not | ||
36 | * changed without any system call invocations. | ||
37 | */ | ||
38 | static struct page *selinux_status_page; | ||
39 | static DEFINE_MUTEX(selinux_status_lock); | ||
40 | |||
41 | /* | ||
42 | * selinux_kernel_status_page | ||
43 | * | ||
44 | * It returns a reference to selinux_status_page. If the status page is | ||
45 | * not allocated yet, it also tries to allocate it at the first time. | ||
46 | */ | ||
47 | struct page *selinux_kernel_status_page(void) | ||
48 | { | ||
49 | struct selinux_kernel_status *status; | ||
50 | struct page *result = NULL; | ||
51 | |||
52 | mutex_lock(&selinux_status_lock); | ||
53 | if (!selinux_status_page) { | ||
54 | selinux_status_page = alloc_page(GFP_KERNEL|__GFP_ZERO); | ||
55 | |||
56 | if (selinux_status_page) { | ||
57 | status = page_address(selinux_status_page); | ||
58 | |||
59 | status->version = SELINUX_KERNEL_STATUS_VERSION; | ||
60 | status->sequence = 0; | ||
61 | status->enforcing = selinux_enforcing; | ||
62 | /* | ||
63 | * NOTE: the next policyload event shall set | ||
64 | * a positive value on the status->policyload, | ||
65 | * although it may not be 1, but never zero. | ||
66 | * So, application can know it was updated. | ||
67 | */ | ||
68 | status->policyload = 0; | ||
69 | status->deny_unknown = !security_get_allow_unknown(); | ||
70 | } | ||
71 | } | ||
72 | result = selinux_status_page; | ||
73 | mutex_unlock(&selinux_status_lock); | ||
74 | |||
75 | return result; | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * selinux_status_update_setenforce | ||
80 | * | ||
81 | * It updates status of the current enforcing/permissive mode. | ||
82 | */ | ||
83 | void selinux_status_update_setenforce(int enforcing) | ||
84 | { | ||
85 | struct selinux_kernel_status *status; | ||
86 | |||
87 | mutex_lock(&selinux_status_lock); | ||
88 | if (selinux_status_page) { | ||
89 | status = page_address(selinux_status_page); | ||
90 | |||
91 | status->sequence++; | ||
92 | smp_wmb(); | ||
93 | |||
94 | status->enforcing = enforcing; | ||
95 | |||
96 | smp_wmb(); | ||
97 | status->sequence++; | ||
98 | } | ||
99 | mutex_unlock(&selinux_status_lock); | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * selinux_status_update_policyload | ||
104 | * | ||
105 | * It updates status of the times of policy reloaded, and current | ||
106 | * setting of deny_unknown. | ||
107 | */ | ||
108 | void selinux_status_update_policyload(int seqno) | ||
109 | { | ||
110 | struct selinux_kernel_status *status; | ||
111 | |||
112 | mutex_lock(&selinux_status_lock); | ||
113 | if (selinux_status_page) { | ||
114 | status = page_address(selinux_status_page); | ||
115 | |||
116 | status->sequence++; | ||
117 | smp_wmb(); | ||
118 | |||
119 | status->policyload = seqno; | ||
120 | status->deny_unknown = !security_get_allow_unknown(); | ||
121 | |||
122 | smp_wmb(); | ||
123 | status->sequence++; | ||
124 | } | ||
125 | mutex_unlock(&selinux_status_lock); | ||
126 | } | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c448d57ae2b7..bc39f4067af6 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -1281,12 +1281,11 @@ static int smack_task_getioprio(struct task_struct *p) | |||
1281 | * | 1281 | * |
1282 | * Return 0 if read access is permitted | 1282 | * Return 0 if read access is permitted |
1283 | */ | 1283 | */ |
1284 | static int smack_task_setscheduler(struct task_struct *p, int policy, | 1284 | static int smack_task_setscheduler(struct task_struct *p) |
1285 | struct sched_param *lp) | ||
1286 | { | 1285 | { |
1287 | int rc; | 1286 | int rc; |
1288 | 1287 | ||
1289 | rc = cap_task_setscheduler(p, policy, lp); | 1288 | rc = cap_task_setscheduler(p); |
1290 | if (rc == 0) | 1289 | if (rc == 0) |
1291 | rc = smk_curacc_on_task(p, MAY_WRITE); | 1290 | rc = smk_curacc_on_task(p, MAY_WRITE); |
1292 | return rc; | 1291 | return rc; |
@@ -3005,7 +3004,8 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | |||
3005 | { | 3004 | { |
3006 | char *sp = smack_from_secid(secid); | 3005 | char *sp = smack_from_secid(secid); |
3007 | 3006 | ||
3008 | *secdata = sp; | 3007 | if (secdata) |
3008 | *secdata = sp; | ||
3009 | *seclen = strlen(sp); | 3009 | *seclen = strlen(sp); |
3010 | return 0; | 3010 | return 0; |
3011 | } | 3011 | } |
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index ef43995119a4..7556315c1978 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -768,8 +768,10 @@ static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data) | |||
768 | return true; /* Do nothing if open(O_WRONLY). */ | 768 | return true; /* Do nothing if open(O_WRONLY). */ |
769 | memset(&head->r, 0, sizeof(head->r)); | 769 | memset(&head->r, 0, sizeof(head->r)); |
770 | head->r.print_this_domain_only = true; | 770 | head->r.print_this_domain_only = true; |
771 | head->r.eof = !domain; | 771 | if (domain) |
772 | head->r.domain = &domain->list; | 772 | head->r.domain = &domain->list; |
773 | else | ||
774 | head->r.eof = 1; | ||
773 | tomoyo_io_printf(head, "# select %s\n", data); | 775 | tomoyo_io_printf(head, "# select %s\n", data); |
774 | if (domain && domain->is_deleted) | 776 | if (domain && domain->is_deleted) |
775 | tomoyo_io_printf(head, "# This is a deleted domain.\n"); | 777 | tomoyo_io_printf(head, "# This is a deleted domain.\n"); |
@@ -1416,15 +1418,19 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r) | |||
1416 | const pid_t gpid = task_pid_nr(current); | 1418 | const pid_t gpid = task_pid_nr(current); |
1417 | static const int tomoyo_buffer_len = 4096; | 1419 | static const int tomoyo_buffer_len = 4096; |
1418 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); | 1420 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); |
1421 | pid_t ppid; | ||
1419 | if (!buffer) | 1422 | if (!buffer) |
1420 | return NULL; | 1423 | return NULL; |
1421 | do_gettimeofday(&tv); | 1424 | do_gettimeofday(&tv); |
1425 | rcu_read_lock(); | ||
1426 | ppid = task_tgid_vnr(current->real_parent); | ||
1427 | rcu_read_unlock(); | ||
1422 | snprintf(buffer, tomoyo_buffer_len - 1, | 1428 | snprintf(buffer, tomoyo_buffer_len - 1, |
1423 | "#timestamp=%lu profile=%u mode=%s (global-pid=%u)" | 1429 | "#timestamp=%lu profile=%u mode=%s (global-pid=%u)" |
1424 | " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u" | 1430 | " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u" |
1425 | " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", | 1431 | " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", |
1426 | tv.tv_sec, r->profile, tomoyo_mode[r->mode], gpid, | 1432 | tv.tv_sec, r->profile, tomoyo_mode[r->mode], gpid, |
1427 | (pid_t) sys_getpid(), (pid_t) sys_getppid(), | 1433 | task_tgid_vnr(current), ppid, |
1428 | current_uid(), current_gid(), current_euid(), | 1434 | current_uid(), current_gid(), current_euid(), |
1429 | current_egid(), current_suid(), current_sgid(), | 1435 | current_egid(), current_suid(), current_sgid(), |
1430 | current_fsuid(), current_fsgid()); | 1436 | current_fsuid(), current_fsgid()); |
@@ -2047,13 +2053,22 @@ void tomoyo_check_profile(void) | |||
2047 | const u8 profile = domain->profile; | 2053 | const u8 profile = domain->profile; |
2048 | if (tomoyo_profile_ptr[profile]) | 2054 | if (tomoyo_profile_ptr[profile]) |
2049 | continue; | 2055 | continue; |
2056 | printk(KERN_ERR "You need to define profile %u before using it.\n", | ||
2057 | profile); | ||
2058 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " | ||
2059 | "for more information.\n"); | ||
2050 | panic("Profile %u (used by '%s') not defined.\n", | 2060 | panic("Profile %u (used by '%s') not defined.\n", |
2051 | profile, domain->domainname->name); | 2061 | profile, domain->domainname->name); |
2052 | } | 2062 | } |
2053 | tomoyo_read_unlock(idx); | 2063 | tomoyo_read_unlock(idx); |
2054 | if (tomoyo_profile_version != 20090903) | 2064 | if (tomoyo_profile_version != 20090903) { |
2065 | printk(KERN_ERR "You need to install userland programs for " | ||
2066 | "TOMOYO 2.3 and initialize policy configuration.\n"); | ||
2067 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " | ||
2068 | "for more information.\n"); | ||
2055 | panic("Profile version %u is not supported.\n", | 2069 | panic("Profile version %u is not supported.\n", |
2056 | tomoyo_profile_version); | 2070 | tomoyo_profile_version); |
2071 | } | ||
2057 | printk(KERN_INFO "TOMOYO: 2.3.0\n"); | 2072 | printk(KERN_INFO "TOMOYO: 2.3.0\n"); |
2058 | printk(KERN_INFO "Mandatory Access Control activated.\n"); | 2073 | printk(KERN_INFO "Mandatory Access Control activated.\n"); |
2059 | } | 2074 | } |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 04454cb7b24a..7c66bd898782 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -689,9 +689,6 @@ struct tomoyo_profile { | |||
689 | 689 | ||
690 | /********** Function prototypes. **********/ | 690 | /********** Function prototypes. **********/ |
691 | 691 | ||
692 | extern asmlinkage long sys_getpid(void); | ||
693 | extern asmlinkage long sys_getppid(void); | ||
694 | |||
695 | /* Check whether the given string starts with the given keyword. */ | 692 | /* Check whether the given string starts with the given keyword. */ |
696 | bool tomoyo_str_starts(char **src, const char *find); | 693 | bool tomoyo_str_starts(char **src, const char *find); |
697 | /* Get tomoyo_realpath() of current process. */ | 694 | /* Get tomoyo_realpath() of current process. */ |