diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/dummy.c | 6 | ||||
-rw-r--r-- | security/security.c | 1 | ||||
-rw-r--r-- | security/selinux/avc.c | 12 | ||||
-rw-r--r-- | security/selinux/hooks.c | 42 | ||||
-rw-r--r-- | security/selinux/include/av_perm_to_string.h | 1 | ||||
-rw-r--r-- | security/selinux/include/av_permissions.h | 1 | ||||
-rw-r--r-- | security/selinux/include/avc.h | 6 | ||||
-rw-r--r-- | security/selinux/include/class_to_string.h | 1 | ||||
-rw-r--r-- | security/selinux/include/flask.h | 1 | ||||
-rw-r--r-- | security/selinux/include/security.h | 4 | ||||
-rw-r--r-- | security/selinux/netlabel.c | 34 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 269 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 7 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 144 |
14 files changed, 453 insertions, 76 deletions
diff --git a/security/dummy.c b/security/dummy.c index 8ffd76405b5b..d6a112ce2975 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -420,8 +420,12 @@ static int dummy_file_ioctl (struct file *file, unsigned int command, | |||
420 | 420 | ||
421 | static int dummy_file_mmap (struct file *file, unsigned long reqprot, | 421 | static int dummy_file_mmap (struct file *file, unsigned long reqprot, |
422 | unsigned long prot, | 422 | unsigned long prot, |
423 | unsigned long flags) | 423 | unsigned long flags, |
424 | unsigned long addr, | ||
425 | unsigned long addr_only) | ||
424 | { | 426 | { |
427 | if (addr < mmap_min_addr) | ||
428 | return -EACCES; | ||
425 | return 0; | 429 | return 0; |
426 | } | 430 | } |
427 | 431 | ||
diff --git a/security/security.c b/security/security.c index fc8601b2b7ac..27e5863d30f1 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -24,6 +24,7 @@ extern struct security_operations dummy_security_ops; | |||
24 | extern void security_fixup_ops(struct security_operations *ops); | 24 | extern void security_fixup_ops(struct security_operations *ops); |
25 | 25 | ||
26 | struct security_operations *security_ops; /* Initialized to NULL */ | 26 | struct security_operations *security_ops; /* Initialized to NULL */ |
27 | unsigned long mmap_min_addr; /* 0 means no protection */ | ||
27 | 28 | ||
28 | static inline int verify(struct security_operations *ops) | 29 | static inline int verify(struct security_operations *ops) |
29 | { | 30 | { |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index e4396a89edc6..78c408fd2b02 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -586,7 +586,7 @@ void avc_audit(u32 ssid, u32 tsid, | |||
586 | } | 586 | } |
587 | } | 587 | } |
588 | if (inode) | 588 | if (inode) |
589 | audit_log_format(ab, " dev=%s ino=%ld", | 589 | audit_log_format(ab, " dev=%s ino=%lu", |
590 | inode->i_sb->s_id, | 590 | inode->i_sb->s_id, |
591 | inode->i_ino); | 591 | inode->i_ino); |
592 | break; | 592 | break; |
@@ -832,6 +832,7 @@ int avc_ss_reset(u32 seqno) | |||
832 | * @tsid: target security identifier | 832 | * @tsid: target security identifier |
833 | * @tclass: target security class | 833 | * @tclass: target security class |
834 | * @requested: requested permissions, interpreted based on @tclass | 834 | * @requested: requested permissions, interpreted based on @tclass |
835 | * @flags: AVC_STRICT or 0 | ||
835 | * @avd: access vector decisions | 836 | * @avd: access vector decisions |
836 | * | 837 | * |
837 | * Check the AVC to determine whether the @requested permissions are granted | 838 | * Check the AVC to determine whether the @requested permissions are granted |
@@ -846,8 +847,9 @@ int avc_ss_reset(u32 seqno) | |||
846 | * should be released for the auditing. | 847 | * should be released for the auditing. |
847 | */ | 848 | */ |
848 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 849 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
849 | u16 tclass, u32 requested, | 850 | u16 tclass, u32 requested, |
850 | struct av_decision *avd) | 851 | unsigned flags, |
852 | struct av_decision *avd) | ||
851 | { | 853 | { |
852 | struct avc_node *node; | 854 | struct avc_node *node; |
853 | struct avc_entry entry, *p_ae; | 855 | struct avc_entry entry, *p_ae; |
@@ -874,7 +876,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
874 | denied = requested & ~(p_ae->avd.allowed); | 876 | denied = requested & ~(p_ae->avd.allowed); |
875 | 877 | ||
876 | if (!requested || denied) { | 878 | if (!requested || denied) { |
877 | if (selinux_enforcing) | 879 | if (selinux_enforcing || (flags & AVC_STRICT)) |
878 | rc = -EACCES; | 880 | rc = -EACCES; |
879 | else | 881 | else |
880 | if (node) | 882 | if (node) |
@@ -909,7 +911,7 @@ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, | |||
909 | struct av_decision avd; | 911 | struct av_decision avd; |
910 | int rc; | 912 | int rc; |
911 | 913 | ||
912 | rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, &avd); | 914 | rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); |
913 | avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); | 915 | avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); |
914 | return rc; | 916 | return rc; |
915 | } | 917 | } |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ad8dd4e8657e..aff8f46c2aa2 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -1592,9 +1592,10 @@ static int selinux_vm_enough_memory(long pages) | |||
1592 | rc = secondary_ops->capable(current, CAP_SYS_ADMIN); | 1592 | rc = secondary_ops->capable(current, CAP_SYS_ADMIN); |
1593 | if (rc == 0) | 1593 | if (rc == 0) |
1594 | rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, | 1594 | rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, |
1595 | SECCLASS_CAPABILITY, | 1595 | SECCLASS_CAPABILITY, |
1596 | CAP_TO_MASK(CAP_SYS_ADMIN), | 1596 | CAP_TO_MASK(CAP_SYS_ADMIN), |
1597 | NULL); | 1597 | 0, |
1598 | NULL); | ||
1598 | 1599 | ||
1599 | if (rc == 0) | 1600 | if (rc == 0) |
1600 | cap_sys_admin = 1; | 1601 | cap_sys_admin = 1; |
@@ -2568,12 +2569,16 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared | |||
2568 | } | 2569 | } |
2569 | 2570 | ||
2570 | static int selinux_file_mmap(struct file *file, unsigned long reqprot, | 2571 | static int selinux_file_mmap(struct file *file, unsigned long reqprot, |
2571 | unsigned long prot, unsigned long flags) | 2572 | unsigned long prot, unsigned long flags, |
2573 | unsigned long addr, unsigned long addr_only) | ||
2572 | { | 2574 | { |
2573 | int rc; | 2575 | int rc = 0; |
2576 | u32 sid = ((struct task_security_struct*)(current->security))->sid; | ||
2574 | 2577 | ||
2575 | rc = secondary_ops->file_mmap(file, reqprot, prot, flags); | 2578 | if (addr < mmap_min_addr) |
2576 | if (rc) | 2579 | rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, |
2580 | MEMPROTECT__MMAP_ZERO, NULL); | ||
2581 | if (rc || addr_only) | ||
2577 | return rc; | 2582 | return rc; |
2578 | 2583 | ||
2579 | if (selinux_checkreqprot) | 2584 | if (selinux_checkreqprot) |
@@ -3124,17 +3129,19 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | |||
3124 | /** | 3129 | /** |
3125 | * selinux_skb_extlbl_sid - Determine the external label of a packet | 3130 | * selinux_skb_extlbl_sid - Determine the external label of a packet |
3126 | * @skb: the packet | 3131 | * @skb: the packet |
3127 | * @base_sid: the SELinux SID to use as a context for MLS only external labels | ||
3128 | * @sid: the packet's SID | 3132 | * @sid: the packet's SID |
3129 | * | 3133 | * |
3130 | * Description: | 3134 | * Description: |
3131 | * Check the various different forms of external packet labeling and determine | 3135 | * Check the various different forms of external packet labeling and determine |
3132 | * the external SID for the packet. | 3136 | * the external SID for the packet. If only one form of external labeling is |
3137 | * present then it is used, if both labeled IPsec and NetLabel labels are | ||
3138 | * present then the SELinux type information is taken from the labeled IPsec | ||
3139 | * SA and the MLS sensitivity label information is taken from the NetLabel | ||
3140 | * security attributes. This bit of "magic" is done in the call to | ||
3141 | * selinux_netlbl_skbuff_getsid(). | ||
3133 | * | 3142 | * |
3134 | */ | 3143 | */ |
3135 | static void selinux_skb_extlbl_sid(struct sk_buff *skb, | 3144 | static void selinux_skb_extlbl_sid(struct sk_buff *skb, u32 *sid) |
3136 | u32 base_sid, | ||
3137 | u32 *sid) | ||
3138 | { | 3145 | { |
3139 | u32 xfrm_sid; | 3146 | u32 xfrm_sid; |
3140 | u32 nlbl_sid; | 3147 | u32 nlbl_sid; |
@@ -3142,10 +3149,9 @@ static void selinux_skb_extlbl_sid(struct sk_buff *skb, | |||
3142 | selinux_skb_xfrm_sid(skb, &xfrm_sid); | 3149 | selinux_skb_xfrm_sid(skb, &xfrm_sid); |
3143 | if (selinux_netlbl_skbuff_getsid(skb, | 3150 | if (selinux_netlbl_skbuff_getsid(skb, |
3144 | (xfrm_sid == SECSID_NULL ? | 3151 | (xfrm_sid == SECSID_NULL ? |
3145 | base_sid : xfrm_sid), | 3152 | SECINITSID_NETMSG : xfrm_sid), |
3146 | &nlbl_sid) != 0) | 3153 | &nlbl_sid) != 0) |
3147 | nlbl_sid = SECSID_NULL; | 3154 | nlbl_sid = SECSID_NULL; |
3148 | |||
3149 | *sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid); | 3155 | *sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid); |
3150 | } | 3156 | } |
3151 | 3157 | ||
@@ -3690,7 +3696,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * | |||
3690 | if (sock && sock->sk->sk_family == PF_UNIX) | 3696 | if (sock && sock->sk->sk_family == PF_UNIX) |
3691 | selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); | 3697 | selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); |
3692 | else if (skb) | 3698 | else if (skb) |
3693 | selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &peer_secid); | 3699 | selinux_skb_extlbl_sid(skb, &peer_secid); |
3694 | 3700 | ||
3695 | if (peer_secid == SECSID_NULL) | 3701 | if (peer_secid == SECSID_NULL) |
3696 | err = -EINVAL; | 3702 | err = -EINVAL; |
@@ -3751,7 +3757,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
3751 | u32 newsid; | 3757 | u32 newsid; |
3752 | u32 peersid; | 3758 | u32 peersid; |
3753 | 3759 | ||
3754 | selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &peersid); | 3760 | selinux_skb_extlbl_sid(skb, &peersid); |
3755 | if (peersid == SECSID_NULL) { | 3761 | if (peersid == SECSID_NULL) { |
3756 | req->secid = sksec->sid; | 3762 | req->secid = sksec->sid; |
3757 | req->peer_secid = SECSID_NULL; | 3763 | req->peer_secid = SECSID_NULL; |
@@ -3789,7 +3795,7 @@ static void selinux_inet_conn_established(struct sock *sk, | |||
3789 | { | 3795 | { |
3790 | struct sk_security_struct *sksec = sk->sk_security; | 3796 | struct sk_security_struct *sksec = sk->sk_security; |
3791 | 3797 | ||
3792 | selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &sksec->peer_sid); | 3798 | selinux_skb_extlbl_sid(skb, &sksec->peer_sid); |
3793 | } | 3799 | } |
3794 | 3800 | ||
3795 | static void selinux_req_classify_flow(const struct request_sock *req, | 3801 | static void selinux_req_classify_flow(const struct request_sock *req, |
@@ -4626,7 +4632,7 @@ static int selinux_setprocattr(struct task_struct *p, | |||
4626 | if (p->ptrace & PT_PTRACED) { | 4632 | if (p->ptrace & PT_PTRACED) { |
4627 | error = avc_has_perm_noaudit(tsec->ptrace_sid, sid, | 4633 | error = avc_has_perm_noaudit(tsec->ptrace_sid, sid, |
4628 | SECCLASS_PROCESS, | 4634 | SECCLASS_PROCESS, |
4629 | PROCESS__PTRACE, &avd); | 4635 | PROCESS__PTRACE, 0, &avd); |
4630 | if (!error) | 4636 | if (!error) |
4631 | tsec->sid = sid; | 4637 | tsec->sid = sid; |
4632 | task_unlock(p); | 4638 | task_unlock(p); |
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index b83e74012a97..049bf69429b6 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h | |||
@@ -158,3 +158,4 @@ | |||
158 | S_(SECCLASS_KEY, KEY__CREATE, "create") | 158 | S_(SECCLASS_KEY, KEY__CREATE, "create") |
159 | S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind") | 159 | S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind") |
160 | S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect") | 160 | S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect") |
161 | S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero") | ||
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 5fee1735bffe..eda89a2ec635 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h | |||
@@ -823,3 +823,4 @@ | |||
823 | #define DCCP_SOCKET__NAME_BIND 0x00200000UL | 823 | #define DCCP_SOCKET__NAME_BIND 0x00200000UL |
824 | #define DCCP_SOCKET__NODE_BIND 0x00400000UL | 824 | #define DCCP_SOCKET__NODE_BIND 0x00400000UL |
825 | #define DCCP_SOCKET__NAME_CONNECT 0x00800000UL | 825 | #define DCCP_SOCKET__NAME_CONNECT 0x00800000UL |
826 | #define MEMPROTECT__MMAP_ZERO 0x00000001UL | ||
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 6ed10c3d3339..e145f6e13b0b 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
@@ -102,9 +102,11 @@ void avc_audit(u32 ssid, u32 tsid, | |||
102 | u16 tclass, u32 requested, | 102 | u16 tclass, u32 requested, |
103 | struct av_decision *avd, int result, struct avc_audit_data *auditdata); | 103 | struct av_decision *avd, int result, struct avc_audit_data *auditdata); |
104 | 104 | ||
105 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | ||
105 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 106 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
106 | u16 tclass, u32 requested, | 107 | u16 tclass, u32 requested, |
107 | struct av_decision *avd); | 108 | unsigned flags, |
109 | struct av_decision *avd); | ||
108 | 110 | ||
109 | int avc_has_perm(u32 ssid, u32 tsid, | 111 | int avc_has_perm(u32 ssid, u32 tsid, |
110 | u16 tclass, u32 requested, | 112 | u16 tclass, u32 requested, |
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h index 378799068441..e77de0e62ea0 100644 --- a/security/selinux/include/class_to_string.h +++ b/security/selinux/include/class_to_string.h | |||
@@ -63,3 +63,4 @@ | |||
63 | S_("key") | 63 | S_("key") |
64 | S_(NULL) | 64 | S_(NULL) |
65 | S_("dccp_socket") | 65 | S_("dccp_socket") |
66 | S_("memprotect") | ||
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h index 35f309f47873..a9c2b20f14b5 100644 --- a/security/selinux/include/flask.h +++ b/security/selinux/include/flask.h | |||
@@ -49,6 +49,7 @@ | |||
49 | #define SECCLASS_PACKET 57 | 49 | #define SECCLASS_PACKET 57 |
50 | #define SECCLASS_KEY 58 | 50 | #define SECCLASS_KEY 58 |
51 | #define SECCLASS_DCCP_SOCKET 60 | 51 | #define SECCLASS_DCCP_SOCKET 60 |
52 | #define SECCLASS_MEMPROTECT 61 | ||
52 | 53 | ||
53 | /* | 54 | /* |
54 | * Security identifier indices for initial entities | 55 | * Security identifier indices for initial entities |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index b94378afea25..83bdd4d2a29e 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -41,6 +41,7 @@ extern int selinux_mls_enabled; | |||
41 | 41 | ||
42 | int security_load_policy(void * data, size_t len); | 42 | int security_load_policy(void * data, size_t len); |
43 | 43 | ||
44 | #define SEL_VEC_MAX 32 | ||
44 | struct av_decision { | 45 | struct av_decision { |
45 | u32 allowed; | 46 | u32 allowed; |
46 | u32 decided; | 47 | u32 decided; |
@@ -87,6 +88,9 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, | |||
87 | 88 | ||
88 | int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); | 89 | int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); |
89 | 90 | ||
91 | int security_get_classes(char ***classes, int *nclasses); | ||
92 | int security_get_permissions(char *class, char ***perms, int *nperms); | ||
93 | |||
90 | #define SECURITY_FS_USE_XATTR 1 /* use xattr */ | 94 | #define SECURITY_FS_USE_XATTR 1 /* use xattr */ |
91 | #define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ | 95 | #define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ |
92 | #define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */ | 96 | #define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */ |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index e64eca246f1a..8192e8bc9f5a 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -158,9 +158,7 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid) | |||
158 | netlbl_secattr_init(&secattr); | 158 | netlbl_secattr_init(&secattr); |
159 | rc = netlbl_skbuff_getattr(skb, &secattr); | 159 | rc = netlbl_skbuff_getattr(skb, &secattr); |
160 | if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) | 160 | if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) |
161 | rc = security_netlbl_secattr_to_sid(&secattr, | 161 | rc = security_netlbl_secattr_to_sid(&secattr, base_sid, sid); |
162 | base_sid, | ||
163 | sid); | ||
164 | else | 162 | else |
165 | *sid = SECSID_NULL; | 163 | *sid = SECSID_NULL; |
166 | netlbl_secattr_destroy(&secattr); | 164 | netlbl_secattr_destroy(&secattr); |
@@ -198,7 +196,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | |||
198 | if (netlbl_sock_getattr(sk, &secattr) == 0 && | 196 | if (netlbl_sock_getattr(sk, &secattr) == 0 && |
199 | secattr.flags != NETLBL_SECATTR_NONE && | 197 | secattr.flags != NETLBL_SECATTR_NONE && |
200 | security_netlbl_secattr_to_sid(&secattr, | 198 | security_netlbl_secattr_to_sid(&secattr, |
201 | SECINITSID_UNLABELED, | 199 | SECINITSID_NETMSG, |
202 | &nlbl_peer_sid) == 0) | 200 | &nlbl_peer_sid) == 0) |
203 | sksec->peer_sid = nlbl_peer_sid; | 201 | sksec->peer_sid = nlbl_peer_sid; |
204 | netlbl_secattr_destroy(&secattr); | 202 | netlbl_secattr_destroy(&secattr); |
@@ -295,38 +293,32 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
295 | struct avc_audit_data *ad) | 293 | struct avc_audit_data *ad) |
296 | { | 294 | { |
297 | int rc; | 295 | int rc; |
298 | u32 netlbl_sid; | 296 | u32 nlbl_sid; |
299 | u32 recv_perm; | 297 | u32 perm; |
300 | 298 | ||
301 | rc = selinux_netlbl_skbuff_getsid(skb, | 299 | rc = selinux_netlbl_skbuff_getsid(skb, SECINITSID_NETMSG, &nlbl_sid); |
302 | SECINITSID_UNLABELED, | ||
303 | &netlbl_sid); | ||
304 | if (rc != 0) | 300 | if (rc != 0) |
305 | return rc; | 301 | return rc; |
306 | 302 | if (nlbl_sid == SECSID_NULL) | |
307 | if (netlbl_sid == SECSID_NULL) | 303 | nlbl_sid = SECINITSID_UNLABELED; |
308 | return 0; | ||
309 | 304 | ||
310 | switch (sksec->sclass) { | 305 | switch (sksec->sclass) { |
311 | case SECCLASS_UDP_SOCKET: | 306 | case SECCLASS_UDP_SOCKET: |
312 | recv_perm = UDP_SOCKET__RECVFROM; | 307 | perm = UDP_SOCKET__RECVFROM; |
313 | break; | 308 | break; |
314 | case SECCLASS_TCP_SOCKET: | 309 | case SECCLASS_TCP_SOCKET: |
315 | recv_perm = TCP_SOCKET__RECVFROM; | 310 | perm = TCP_SOCKET__RECVFROM; |
316 | break; | 311 | break; |
317 | default: | 312 | default: |
318 | recv_perm = RAWIP_SOCKET__RECVFROM; | 313 | perm = RAWIP_SOCKET__RECVFROM; |
319 | } | 314 | } |
320 | 315 | ||
321 | rc = avc_has_perm(sksec->sid, | 316 | rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad); |
322 | netlbl_sid, | ||
323 | sksec->sclass, | ||
324 | recv_perm, | ||
325 | ad); | ||
326 | if (rc == 0) | 317 | if (rc == 0) |
327 | return 0; | 318 | return 0; |
328 | 319 | ||
329 | netlbl_skbuff_err(skb, rc); | 320 | if (nlbl_sid != SECINITSID_UNLABELED) |
321 | netlbl_skbuff_err(skb, rc); | ||
330 | return rc; | 322 | return rc; |
331 | } | 323 | } |
332 | 324 | ||
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index aca099aa2ed3..c9e92daedee2 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -67,6 +67,10 @@ static struct dentry *bool_dir = NULL; | |||
67 | static int bool_num = 0; | 67 | static int bool_num = 0; |
68 | static int *bool_pending_values = NULL; | 68 | static int *bool_pending_values = NULL; |
69 | 69 | ||
70 | /* global data for classes */ | ||
71 | static struct dentry *class_dir = NULL; | ||
72 | static unsigned long last_class_ino; | ||
73 | |||
70 | extern void selnl_notify_setenforce(int val); | 74 | extern void selnl_notify_setenforce(int val); |
71 | 75 | ||
72 | /* Check whether a task is allowed to use a security operation. */ | 76 | /* Check whether a task is allowed to use a security operation. */ |
@@ -106,6 +110,7 @@ static unsigned long sel_last_ino = SEL_INO_NEXT - 1; | |||
106 | 110 | ||
107 | #define SEL_INITCON_INO_OFFSET 0x01000000 | 111 | #define SEL_INITCON_INO_OFFSET 0x01000000 |
108 | #define SEL_BOOL_INO_OFFSET 0x02000000 | 112 | #define SEL_BOOL_INO_OFFSET 0x02000000 |
113 | #define SEL_CLASS_INO_OFFSET 0x04000000 | ||
109 | #define SEL_INO_MASK 0x00ffffff | 114 | #define SEL_INO_MASK 0x00ffffff |
110 | 115 | ||
111 | #define TMPBUFLEN 12 | 116 | #define TMPBUFLEN 12 |
@@ -237,6 +242,11 @@ static const struct file_operations sel_policyvers_ops = { | |||
237 | 242 | ||
238 | /* declaration for sel_write_load */ | 243 | /* declaration for sel_write_load */ |
239 | static int sel_make_bools(void); | 244 | static int sel_make_bools(void); |
245 | static int sel_make_classes(void); | ||
246 | |||
247 | /* declaration for sel_make_class_dirs */ | ||
248 | static int sel_make_dir(struct inode *dir, struct dentry *dentry, | ||
249 | unsigned long *ino); | ||
240 | 250 | ||
241 | static ssize_t sel_read_mls(struct file *filp, char __user *buf, | 251 | static ssize_t sel_read_mls(struct file *filp, char __user *buf, |
242 | size_t count, loff_t *ppos) | 252 | size_t count, loff_t *ppos) |
@@ -287,10 +297,18 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf, | |||
287 | goto out; | 297 | goto out; |
288 | 298 | ||
289 | ret = sel_make_bools(); | 299 | ret = sel_make_bools(); |
300 | if (ret) { | ||
301 | length = ret; | ||
302 | goto out1; | ||
303 | } | ||
304 | |||
305 | ret = sel_make_classes(); | ||
290 | if (ret) | 306 | if (ret) |
291 | length = ret; | 307 | length = ret; |
292 | else | 308 | else |
293 | length = count; | 309 | length = count; |
310 | |||
311 | out1: | ||
294 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, | 312 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, |
295 | "policy loaded auid=%u", | 313 | "policy loaded auid=%u", |
296 | audit_get_loginuid(current->audit_context)); | 314 | audit_get_loginuid(current->audit_context)); |
@@ -940,9 +958,8 @@ static const struct file_operations sel_commit_bools_ops = { | |||
940 | .write = sel_commit_bools_write, | 958 | .write = sel_commit_bools_write, |
941 | }; | 959 | }; |
942 | 960 | ||
943 | /* delete booleans - partial revoke() from | 961 | /* partial revoke() from fs/proc/generic.c proc_kill_inodes */ |
944 | * fs/proc/generic.c proc_kill_inodes */ | 962 | static void sel_remove_entries(struct dentry *de) |
945 | static void sel_remove_bools(struct dentry *de) | ||
946 | { | 963 | { |
947 | struct list_head *p, *node; | 964 | struct list_head *p, *node; |
948 | struct super_block *sb = de->d_sb; | 965 | struct super_block *sb = de->d_sb; |
@@ -998,7 +1015,7 @@ static int sel_make_bools(void) | |||
998 | kfree(bool_pending_values); | 1015 | kfree(bool_pending_values); |
999 | bool_pending_values = NULL; | 1016 | bool_pending_values = NULL; |
1000 | 1017 | ||
1001 | sel_remove_bools(dir); | 1018 | sel_remove_entries(dir); |
1002 | 1019 | ||
1003 | if (!(page = (char*)get_zeroed_page(GFP_KERNEL))) | 1020 | if (!(page = (char*)get_zeroed_page(GFP_KERNEL))) |
1004 | return -ENOMEM; | 1021 | return -ENOMEM; |
@@ -1048,7 +1065,7 @@ out: | |||
1048 | return ret; | 1065 | return ret; |
1049 | err: | 1066 | err: |
1050 | kfree(values); | 1067 | kfree(values); |
1051 | sel_remove_bools(dir); | 1068 | sel_remove_entries(dir); |
1052 | ret = -ENOMEM; | 1069 | ret = -ENOMEM; |
1053 | goto out; | 1070 | goto out; |
1054 | } | 1071 | } |
@@ -1294,7 +1311,227 @@ out: | |||
1294 | return ret; | 1311 | return ret; |
1295 | } | 1312 | } |
1296 | 1313 | ||
1297 | static int sel_make_dir(struct inode *dir, struct dentry *dentry) | 1314 | static inline unsigned int sel_div(unsigned long a, unsigned long b) |
1315 | { | ||
1316 | return a / b - (a % b < 0); | ||
1317 | } | ||
1318 | |||
1319 | static inline unsigned long sel_class_to_ino(u16 class) | ||
1320 | { | ||
1321 | return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET; | ||
1322 | } | ||
1323 | |||
1324 | static inline u16 sel_ino_to_class(unsigned long ino) | ||
1325 | { | ||
1326 | return sel_div(ino & SEL_INO_MASK, SEL_VEC_MAX + 1); | ||
1327 | } | ||
1328 | |||
1329 | static inline unsigned long sel_perm_to_ino(u16 class, u32 perm) | ||
1330 | { | ||
1331 | return (class * (SEL_VEC_MAX + 1) + perm) | SEL_CLASS_INO_OFFSET; | ||
1332 | } | ||
1333 | |||
1334 | static inline u32 sel_ino_to_perm(unsigned long ino) | ||
1335 | { | ||
1336 | return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1); | ||
1337 | } | ||
1338 | |||
1339 | static ssize_t sel_read_class(struct file * file, char __user *buf, | ||
1340 | size_t count, loff_t *ppos) | ||
1341 | { | ||
1342 | ssize_t rc, len; | ||
1343 | char *page; | ||
1344 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; | ||
1345 | |||
1346 | page = (char *)__get_free_page(GFP_KERNEL); | ||
1347 | if (!page) { | ||
1348 | rc = -ENOMEM; | ||
1349 | goto out; | ||
1350 | } | ||
1351 | |||
1352 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino)); | ||
1353 | rc = simple_read_from_buffer(buf, count, ppos, page, len); | ||
1354 | free_page((unsigned long)page); | ||
1355 | out: | ||
1356 | return rc; | ||
1357 | } | ||
1358 | |||
1359 | static const struct file_operations sel_class_ops = { | ||
1360 | .read = sel_read_class, | ||
1361 | }; | ||
1362 | |||
1363 | static ssize_t sel_read_perm(struct file * file, char __user *buf, | ||
1364 | size_t count, loff_t *ppos) | ||
1365 | { | ||
1366 | ssize_t rc, len; | ||
1367 | char *page; | ||
1368 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; | ||
1369 | |||
1370 | page = (char *)__get_free_page(GFP_KERNEL); | ||
1371 | if (!page) { | ||
1372 | rc = -ENOMEM; | ||
1373 | goto out; | ||
1374 | } | ||
1375 | |||
1376 | len = snprintf(page, PAGE_SIZE,"%d", sel_ino_to_perm(ino)); | ||
1377 | rc = simple_read_from_buffer(buf, count, ppos, page, len); | ||
1378 | free_page((unsigned long)page); | ||
1379 | out: | ||
1380 | return rc; | ||
1381 | } | ||
1382 | |||
1383 | static const struct file_operations sel_perm_ops = { | ||
1384 | .read = sel_read_perm, | ||
1385 | }; | ||
1386 | |||
1387 | static int sel_make_perm_files(char *objclass, int classvalue, | ||
1388 | struct dentry *dir) | ||
1389 | { | ||
1390 | int i, rc = 0, nperms; | ||
1391 | char **perms; | ||
1392 | |||
1393 | rc = security_get_permissions(objclass, &perms, &nperms); | ||
1394 | if (rc) | ||
1395 | goto out; | ||
1396 | |||
1397 | for (i = 0; i < nperms; i++) { | ||
1398 | struct inode *inode; | ||
1399 | struct dentry *dentry; | ||
1400 | |||
1401 | dentry = d_alloc_name(dir, perms[i]); | ||
1402 | if (!dentry) { | ||
1403 | rc = -ENOMEM; | ||
1404 | goto out1; | ||
1405 | } | ||
1406 | |||
1407 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); | ||
1408 | if (!inode) { | ||
1409 | rc = -ENOMEM; | ||
1410 | goto out1; | ||
1411 | } | ||
1412 | inode->i_fop = &sel_perm_ops; | ||
1413 | /* i+1 since perm values are 1-indexed */ | ||
1414 | inode->i_ino = sel_perm_to_ino(classvalue, i+1); | ||
1415 | d_add(dentry, inode); | ||
1416 | } | ||
1417 | |||
1418 | out1: | ||
1419 | for (i = 0; i < nperms; i++) | ||
1420 | kfree(perms[i]); | ||
1421 | kfree(perms); | ||
1422 | out: | ||
1423 | return rc; | ||
1424 | } | ||
1425 | |||
1426 | static int sel_make_class_dir_entries(char *classname, int index, | ||
1427 | struct dentry *dir) | ||
1428 | { | ||
1429 | struct dentry *dentry = NULL; | ||
1430 | struct inode *inode = NULL; | ||
1431 | int rc; | ||
1432 | |||
1433 | dentry = d_alloc_name(dir, "index"); | ||
1434 | if (!dentry) { | ||
1435 | rc = -ENOMEM; | ||
1436 | goto out; | ||
1437 | } | ||
1438 | |||
1439 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); | ||
1440 | if (!inode) { | ||
1441 | rc = -ENOMEM; | ||
1442 | goto out; | ||
1443 | } | ||
1444 | |||
1445 | inode->i_fop = &sel_class_ops; | ||
1446 | inode->i_ino = sel_class_to_ino(index); | ||
1447 | d_add(dentry, inode); | ||
1448 | |||
1449 | dentry = d_alloc_name(dir, "perms"); | ||
1450 | if (!dentry) { | ||
1451 | rc = -ENOMEM; | ||
1452 | goto out; | ||
1453 | } | ||
1454 | |||
1455 | rc = sel_make_dir(dir->d_inode, dentry, &last_class_ino); | ||
1456 | if (rc) | ||
1457 | goto out; | ||
1458 | |||
1459 | rc = sel_make_perm_files(classname, index, dentry); | ||
1460 | |||
1461 | out: | ||
1462 | return rc; | ||
1463 | } | ||
1464 | |||
1465 | static void sel_remove_classes(void) | ||
1466 | { | ||
1467 | struct list_head *class_node; | ||
1468 | |||
1469 | list_for_each(class_node, &class_dir->d_subdirs) { | ||
1470 | struct dentry *class_subdir = list_entry(class_node, | ||
1471 | struct dentry, d_u.d_child); | ||
1472 | struct list_head *class_subdir_node; | ||
1473 | |||
1474 | list_for_each(class_subdir_node, &class_subdir->d_subdirs) { | ||
1475 | struct dentry *d = list_entry(class_subdir_node, | ||
1476 | struct dentry, d_u.d_child); | ||
1477 | |||
1478 | if (d->d_inode) | ||
1479 | if (d->d_inode->i_mode & S_IFDIR) | ||
1480 | sel_remove_entries(d); | ||
1481 | } | ||
1482 | |||
1483 | sel_remove_entries(class_subdir); | ||
1484 | } | ||
1485 | |||
1486 | sel_remove_entries(class_dir); | ||
1487 | } | ||
1488 | |||
1489 | static int sel_make_classes(void) | ||
1490 | { | ||
1491 | int rc = 0, nclasses, i; | ||
1492 | char **classes; | ||
1493 | |||
1494 | /* delete any existing entries */ | ||
1495 | sel_remove_classes(); | ||
1496 | |||
1497 | rc = security_get_classes(&classes, &nclasses); | ||
1498 | if (rc < 0) | ||
1499 | goto out; | ||
1500 | |||
1501 | /* +2 since classes are 1-indexed */ | ||
1502 | last_class_ino = sel_class_to_ino(nclasses+2); | ||
1503 | |||
1504 | for (i = 0; i < nclasses; i++) { | ||
1505 | struct dentry *class_name_dir; | ||
1506 | |||
1507 | class_name_dir = d_alloc_name(class_dir, classes[i]); | ||
1508 | if (!class_name_dir) { | ||
1509 | rc = -ENOMEM; | ||
1510 | goto out1; | ||
1511 | } | ||
1512 | |||
1513 | rc = sel_make_dir(class_dir->d_inode, class_name_dir, | ||
1514 | &last_class_ino); | ||
1515 | if (rc) | ||
1516 | goto out1; | ||
1517 | |||
1518 | /* i+1 since class values are 1-indexed */ | ||
1519 | rc = sel_make_class_dir_entries(classes[i], i+1, | ||
1520 | class_name_dir); | ||
1521 | if (rc) | ||
1522 | goto out1; | ||
1523 | } | ||
1524 | |||
1525 | out1: | ||
1526 | for (i = 0; i < nclasses; i++) | ||
1527 | kfree(classes[i]); | ||
1528 | kfree(classes); | ||
1529 | out: | ||
1530 | return rc; | ||
1531 | } | ||
1532 | |||
1533 | static int sel_make_dir(struct inode *dir, struct dentry *dentry, | ||
1534 | unsigned long *ino) | ||
1298 | { | 1535 | { |
1299 | int ret = 0; | 1536 | int ret = 0; |
1300 | struct inode *inode; | 1537 | struct inode *inode; |
@@ -1306,7 +1543,7 @@ static int sel_make_dir(struct inode *dir, struct dentry *dentry) | |||
1306 | } | 1543 | } |
1307 | inode->i_op = &simple_dir_inode_operations; | 1544 | inode->i_op = &simple_dir_inode_operations; |
1308 | inode->i_fop = &simple_dir_operations; | 1545 | inode->i_fop = &simple_dir_operations; |
1309 | inode->i_ino = ++sel_last_ino; | 1546 | inode->i_ino = ++(*ino); |
1310 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | 1547 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ |
1311 | inc_nlink(inode); | 1548 | inc_nlink(inode); |
1312 | d_add(dentry, inode); | 1549 | d_add(dentry, inode); |
@@ -1352,7 +1589,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
1352 | goto err; | 1589 | goto err; |
1353 | } | 1590 | } |
1354 | 1591 | ||
1355 | ret = sel_make_dir(root_inode, dentry); | 1592 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1356 | if (ret) | 1593 | if (ret) |
1357 | goto err; | 1594 | goto err; |
1358 | 1595 | ||
@@ -1385,7 +1622,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
1385 | goto err; | 1622 | goto err; |
1386 | } | 1623 | } |
1387 | 1624 | ||
1388 | ret = sel_make_dir(root_inode, dentry); | 1625 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1389 | if (ret) | 1626 | if (ret) |
1390 | goto err; | 1627 | goto err; |
1391 | 1628 | ||
@@ -1399,7 +1636,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
1399 | goto err; | 1636 | goto err; |
1400 | } | 1637 | } |
1401 | 1638 | ||
1402 | ret = sel_make_dir(root_inode, dentry); | 1639 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1403 | if (ret) | 1640 | if (ret) |
1404 | goto err; | 1641 | goto err; |
1405 | 1642 | ||
@@ -1407,6 +1644,18 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
1407 | if (ret) | 1644 | if (ret) |
1408 | goto err; | 1645 | goto err; |
1409 | 1646 | ||
1647 | dentry = d_alloc_name(sb->s_root, "class"); | ||
1648 | if (!dentry) { | ||
1649 | ret = -ENOMEM; | ||
1650 | goto err; | ||
1651 | } | ||
1652 | |||
1653 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | ||
1654 | if (ret) | ||
1655 | goto err; | ||
1656 | |||
1657 | class_dir = dentry; | ||
1658 | |||
1410 | out: | 1659 | out: |
1411 | return ret; | 1660 | return ret; |
1412 | err: | 1661 | err: |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 0ac1021734c0..f05f97a2bc3a 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -21,6 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/sched.h> | ||
24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
25 | #include <linux/string.h> | 26 | #include <linux/string.h> |
26 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
@@ -598,6 +599,7 @@ void policydb_destroy(struct policydb *p) | |||
598 | struct range_trans *rt, *lrt = NULL; | 599 | struct range_trans *rt, *lrt = NULL; |
599 | 600 | ||
600 | for (i = 0; i < SYM_NUM; i++) { | 601 | for (i = 0; i < SYM_NUM; i++) { |
602 | cond_resched(); | ||
601 | hashtab_map(p->symtab[i].table, destroy_f[i], NULL); | 603 | hashtab_map(p->symtab[i].table, destroy_f[i], NULL); |
602 | hashtab_destroy(p->symtab[i].table); | 604 | hashtab_destroy(p->symtab[i].table); |
603 | } | 605 | } |
@@ -612,6 +614,7 @@ void policydb_destroy(struct policydb *p) | |||
612 | avtab_destroy(&p->te_avtab); | 614 | avtab_destroy(&p->te_avtab); |
613 | 615 | ||
614 | for (i = 0; i < OCON_NUM; i++) { | 616 | for (i = 0; i < OCON_NUM; i++) { |
617 | cond_resched(); | ||
615 | c = p->ocontexts[i]; | 618 | c = p->ocontexts[i]; |
616 | while (c) { | 619 | while (c) { |
617 | ctmp = c; | 620 | ctmp = c; |
@@ -623,6 +626,7 @@ void policydb_destroy(struct policydb *p) | |||
623 | 626 | ||
624 | g = p->genfs; | 627 | g = p->genfs; |
625 | while (g) { | 628 | while (g) { |
629 | cond_resched(); | ||
626 | kfree(g->fstype); | 630 | kfree(g->fstype); |
627 | c = g->head; | 631 | c = g->head; |
628 | while (c) { | 632 | while (c) { |
@@ -639,18 +643,21 @@ void policydb_destroy(struct policydb *p) | |||
639 | cond_policydb_destroy(p); | 643 | cond_policydb_destroy(p); |
640 | 644 | ||
641 | for (tr = p->role_tr; tr; tr = tr->next) { | 645 | for (tr = p->role_tr; tr; tr = tr->next) { |
646 | cond_resched(); | ||
642 | kfree(ltr); | 647 | kfree(ltr); |
643 | ltr = tr; | 648 | ltr = tr; |
644 | } | 649 | } |
645 | kfree(ltr); | 650 | kfree(ltr); |
646 | 651 | ||
647 | for (ra = p->role_allow; ra; ra = ra -> next) { | 652 | for (ra = p->role_allow; ra; ra = ra -> next) { |
653 | cond_resched(); | ||
648 | kfree(lra); | 654 | kfree(lra); |
649 | lra = ra; | 655 | lra = ra; |
650 | } | 656 | } |
651 | kfree(lra); | 657 | kfree(lra); |
652 | 658 | ||
653 | for (rt = p->range_tr; rt; rt = rt -> next) { | 659 | for (rt = p->range_tr; rt; rt = rt -> next) { |
660 | cond_resched(); | ||
654 | if (lrt) { | 661 | if (lrt) { |
655 | ebitmap_destroy(&lrt->target_range.level[0].cat); | 662 | ebitmap_destroy(&lrt->target_range.level[0].cat); |
656 | ebitmap_destroy(&lrt->target_range.level[1].cat); | 663 | ebitmap_destroy(&lrt->target_range.level[1].cat); |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 40660ffd49b6..b5f017f07a75 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -1587,19 +1587,18 @@ int security_get_user_sids(u32 fromsid, | |||
1587 | u32 *nel) | 1587 | u32 *nel) |
1588 | { | 1588 | { |
1589 | struct context *fromcon, usercon; | 1589 | struct context *fromcon, usercon; |
1590 | u32 *mysids, *mysids2, sid; | 1590 | u32 *mysids = NULL, *mysids2, sid; |
1591 | u32 mynel = 0, maxnel = SIDS_NEL; | 1591 | u32 mynel = 0, maxnel = SIDS_NEL; |
1592 | struct user_datum *user; | 1592 | struct user_datum *user; |
1593 | struct role_datum *role; | 1593 | struct role_datum *role; |
1594 | struct av_decision avd; | ||
1595 | struct ebitmap_node *rnode, *tnode; | 1594 | struct ebitmap_node *rnode, *tnode; |
1596 | int rc = 0, i, j; | 1595 | int rc = 0, i, j; |
1597 | 1596 | ||
1598 | if (!ss_initialized) { | 1597 | *sids = NULL; |
1599 | *sids = NULL; | 1598 | *nel = 0; |
1600 | *nel = 0; | 1599 | |
1600 | if (!ss_initialized) | ||
1601 | goto out; | 1601 | goto out; |
1602 | } | ||
1603 | 1602 | ||
1604 | POLICY_RDLOCK; | 1603 | POLICY_RDLOCK; |
1605 | 1604 | ||
@@ -1635,17 +1634,9 @@ int security_get_user_sids(u32 fromsid, | |||
1635 | if (mls_setup_user_range(fromcon, user, &usercon)) | 1634 | if (mls_setup_user_range(fromcon, user, &usercon)) |
1636 | continue; | 1635 | continue; |
1637 | 1636 | ||
1638 | rc = context_struct_compute_av(fromcon, &usercon, | ||
1639 | SECCLASS_PROCESS, | ||
1640 | PROCESS__TRANSITION, | ||
1641 | &avd); | ||
1642 | if (rc || !(avd.allowed & PROCESS__TRANSITION)) | ||
1643 | continue; | ||
1644 | rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); | 1637 | rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); |
1645 | if (rc) { | 1638 | if (rc) |
1646 | kfree(mysids); | ||
1647 | goto out_unlock; | 1639 | goto out_unlock; |
1648 | } | ||
1649 | if (mynel < maxnel) { | 1640 | if (mynel < maxnel) { |
1650 | mysids[mynel++] = sid; | 1641 | mysids[mynel++] = sid; |
1651 | } else { | 1642 | } else { |
@@ -1653,7 +1644,6 @@ int security_get_user_sids(u32 fromsid, | |||
1653 | mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); | 1644 | mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); |
1654 | if (!mysids2) { | 1645 | if (!mysids2) { |
1655 | rc = -ENOMEM; | 1646 | rc = -ENOMEM; |
1656 | kfree(mysids); | ||
1657 | goto out_unlock; | 1647 | goto out_unlock; |
1658 | } | 1648 | } |
1659 | memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); | 1649 | memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); |
@@ -1664,11 +1654,32 @@ int security_get_user_sids(u32 fromsid, | |||
1664 | } | 1654 | } |
1665 | } | 1655 | } |
1666 | 1656 | ||
1667 | *sids = mysids; | ||
1668 | *nel = mynel; | ||
1669 | |||
1670 | out_unlock: | 1657 | out_unlock: |
1671 | POLICY_RDUNLOCK; | 1658 | POLICY_RDUNLOCK; |
1659 | if (rc || !mynel) { | ||
1660 | kfree(mysids); | ||
1661 | goto out; | ||
1662 | } | ||
1663 | |||
1664 | mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL); | ||
1665 | if (!mysids2) { | ||
1666 | rc = -ENOMEM; | ||
1667 | kfree(mysids); | ||
1668 | goto out; | ||
1669 | } | ||
1670 | for (i = 0, j = 0; i < mynel; i++) { | ||
1671 | rc = avc_has_perm_noaudit(fromsid, mysids[i], | ||
1672 | SECCLASS_PROCESS, | ||
1673 | PROCESS__TRANSITION, AVC_STRICT, | ||
1674 | NULL); | ||
1675 | if (!rc) | ||
1676 | mysids2[j++] = mysids[i]; | ||
1677 | cond_resched(); | ||
1678 | } | ||
1679 | rc = 0; | ||
1680 | kfree(mysids); | ||
1681 | *sids = mysids2; | ||
1682 | *nel = j; | ||
1672 | out: | 1683 | out: |
1673 | return rc; | 1684 | return rc; |
1674 | } | 1685 | } |
@@ -1996,6 +2007,101 @@ out: | |||
1996 | return rc; | 2007 | return rc; |
1997 | } | 2008 | } |
1998 | 2009 | ||
2010 | static int get_classes_callback(void *k, void *d, void *args) | ||
2011 | { | ||
2012 | struct class_datum *datum = d; | ||
2013 | char *name = k, **classes = args; | ||
2014 | int value = datum->value - 1; | ||
2015 | |||
2016 | classes[value] = kstrdup(name, GFP_ATOMIC); | ||
2017 | if (!classes[value]) | ||
2018 | return -ENOMEM; | ||
2019 | |||
2020 | return 0; | ||
2021 | } | ||
2022 | |||
2023 | int security_get_classes(char ***classes, int *nclasses) | ||
2024 | { | ||
2025 | int rc = -ENOMEM; | ||
2026 | |||
2027 | POLICY_RDLOCK; | ||
2028 | |||
2029 | *nclasses = policydb.p_classes.nprim; | ||
2030 | *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC); | ||
2031 | if (!*classes) | ||
2032 | goto out; | ||
2033 | |||
2034 | rc = hashtab_map(policydb.p_classes.table, get_classes_callback, | ||
2035 | *classes); | ||
2036 | if (rc < 0) { | ||
2037 | int i; | ||
2038 | for (i = 0; i < *nclasses; i++) | ||
2039 | kfree((*classes)[i]); | ||
2040 | kfree(*classes); | ||
2041 | } | ||
2042 | |||
2043 | out: | ||
2044 | POLICY_RDUNLOCK; | ||
2045 | return rc; | ||
2046 | } | ||
2047 | |||
2048 | static int get_permissions_callback(void *k, void *d, void *args) | ||
2049 | { | ||
2050 | struct perm_datum *datum = d; | ||
2051 | char *name = k, **perms = args; | ||
2052 | int value = datum->value - 1; | ||
2053 | |||
2054 | perms[value] = kstrdup(name, GFP_ATOMIC); | ||
2055 | if (!perms[value]) | ||
2056 | return -ENOMEM; | ||
2057 | |||
2058 | return 0; | ||
2059 | } | ||
2060 | |||
2061 | int security_get_permissions(char *class, char ***perms, int *nperms) | ||
2062 | { | ||
2063 | int rc = -ENOMEM, i; | ||
2064 | struct class_datum *match; | ||
2065 | |||
2066 | POLICY_RDLOCK; | ||
2067 | |||
2068 | match = hashtab_search(policydb.p_classes.table, class); | ||
2069 | if (!match) { | ||
2070 | printk(KERN_ERR "%s: unrecognized class %s\n", | ||
2071 | __FUNCTION__, class); | ||
2072 | rc = -EINVAL; | ||
2073 | goto out; | ||
2074 | } | ||
2075 | |||
2076 | *nperms = match->permissions.nprim; | ||
2077 | *perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC); | ||
2078 | if (!*perms) | ||
2079 | goto out; | ||
2080 | |||
2081 | if (match->comdatum) { | ||
2082 | rc = hashtab_map(match->comdatum->permissions.table, | ||
2083 | get_permissions_callback, *perms); | ||
2084 | if (rc < 0) | ||
2085 | goto err; | ||
2086 | } | ||
2087 | |||
2088 | rc = hashtab_map(match->permissions.table, get_permissions_callback, | ||
2089 | *perms); | ||
2090 | if (rc < 0) | ||
2091 | goto err; | ||
2092 | |||
2093 | out: | ||
2094 | POLICY_RDUNLOCK; | ||
2095 | return rc; | ||
2096 | |||
2097 | err: | ||
2098 | POLICY_RDUNLOCK; | ||
2099 | for (i = 0; i < *nperms; i++) | ||
2100 | kfree((*perms)[i]); | ||
2101 | kfree(*perms); | ||
2102 | return rc; | ||
2103 | } | ||
2104 | |||
1999 | struct selinux_audit_rule { | 2105 | struct selinux_audit_rule { |
2000 | u32 au_seqno; | 2106 | u32 au_seqno; |
2001 | struct context au_ctxt; | 2107 | struct context au_ctxt; |