diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-07 15:12:45 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-07 15:12:45 -0500 |
commit | 3ac96c30ccfa802501dd2f4941e4508ea54b0b8a (patch) | |
tree | df095a1ad94f30ec6127da7f6ff3d36e3bbab0fc /security/selinux | |
parent | ae5906ceee038ea29ff5162d1bcd18fb50af8b94 (diff) | |
parent | 45189a1998e00f6375ebd49d1e18161acddd73de (diff) |
Merge tag 'selinux-pr-20190305' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux
Pull SELinux updates from Paul Moore:
"Nine SELinux patches for v5.1, all bug fixes.
As far as I'm concerned, nothing really jumps out as risky or special
to me, but each commit has a decent description so you can judge for
yourself. As usual, everything passes the selinux-testsuite; please
merge for v5.1"
* tag 'selinux-pr-20190305' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
selinux: fix avc audit messages
selinux: replace BUG_ONs with WARN_ONs in avc.c
selinux: log invalid contexts in AVCs
selinux: replace some BUG_ON()s with a WARN_ON()
selinux: inline some AVC functions used only once
selinux: do not override context on context mounts
selinux: never allow relabeling on context mounts
selinux: stop passing MAY_NOT_BLOCK to the AVC upon follow_link
selinux: avoid silent denials in permissive mode under RCU walk
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/avc.c | 199 | ||||
-rw-r--r-- | security/selinux/hooks.c | 58 | ||||
-rw-r--r-- | security/selinux/include/avc.h | 6 | ||||
-rw-r--r-- | security/selinux/include/security.h | 3 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 37 |
5 files changed, 176 insertions, 127 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 635e5c1e3e48..8346a4f7c5d7 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -130,75 +130,6 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) | |||
130 | } | 130 | } |
131 | 131 | ||
132 | /** | 132 | /** |
133 | * avc_dump_av - Display an access vector in human-readable form. | ||
134 | * @tclass: target security class | ||
135 | * @av: access vector | ||
136 | */ | ||
137 | static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) | ||
138 | { | ||
139 | const char **perms; | ||
140 | int i, perm; | ||
141 | |||
142 | if (av == 0) { | ||
143 | audit_log_format(ab, " null"); | ||
144 | return; | ||
145 | } | ||
146 | |||
147 | BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); | ||
148 | perms = secclass_map[tclass-1].perms; | ||
149 | |||
150 | audit_log_format(ab, " {"); | ||
151 | i = 0; | ||
152 | perm = 1; | ||
153 | while (i < (sizeof(av) * 8)) { | ||
154 | if ((perm & av) && perms[i]) { | ||
155 | audit_log_format(ab, " %s", perms[i]); | ||
156 | av &= ~perm; | ||
157 | } | ||
158 | i++; | ||
159 | perm <<= 1; | ||
160 | } | ||
161 | |||
162 | if (av) | ||
163 | audit_log_format(ab, " 0x%x", av); | ||
164 | |||
165 | audit_log_format(ab, " }"); | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * avc_dump_query - Display a SID pair and a class in human-readable form. | ||
170 | * @ssid: source security identifier | ||
171 | * @tsid: target security identifier | ||
172 | * @tclass: target security class | ||
173 | */ | ||
174 | static void avc_dump_query(struct audit_buffer *ab, struct selinux_state *state, | ||
175 | u32 ssid, u32 tsid, u16 tclass) | ||
176 | { | ||
177 | int rc; | ||
178 | char *scontext; | ||
179 | u32 scontext_len; | ||
180 | |||
181 | rc = security_sid_to_context(state, ssid, &scontext, &scontext_len); | ||
182 | if (rc) | ||
183 | audit_log_format(ab, "ssid=%d", ssid); | ||
184 | else { | ||
185 | audit_log_format(ab, "scontext=%s", scontext); | ||
186 | kfree(scontext); | ||
187 | } | ||
188 | |||
189 | rc = security_sid_to_context(state, tsid, &scontext, &scontext_len); | ||
190 | if (rc) | ||
191 | audit_log_format(ab, " tsid=%d", tsid); | ||
192 | else { | ||
193 | audit_log_format(ab, " tcontext=%s", scontext); | ||
194 | kfree(scontext); | ||
195 | } | ||
196 | |||
197 | BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); | ||
198 | audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name); | ||
199 | } | ||
200 | |||
201 | /** | ||
202 | * avc_init - Initialize the AVC. | 133 | * avc_init - Initialize the AVC. |
203 | * | 134 | * |
204 | * Initialize the access vector cache. | 135 | * Initialize the access vector cache. |
@@ -735,11 +666,36 @@ out: | |||
735 | static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) | 666 | static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) |
736 | { | 667 | { |
737 | struct common_audit_data *ad = a; | 668 | struct common_audit_data *ad = a; |
738 | audit_log_format(ab, "avc: %s ", | 669 | struct selinux_audit_data *sad = ad->selinux_audit_data; |
739 | ad->selinux_audit_data->denied ? "denied" : "granted"); | 670 | u32 av = sad->audited; |
740 | avc_dump_av(ab, ad->selinux_audit_data->tclass, | 671 | const char **perms; |
741 | ad->selinux_audit_data->audited); | 672 | int i, perm; |
742 | audit_log_format(ab, " for "); | 673 | |
674 | audit_log_format(ab, "avc: %s ", sad->denied ? "denied" : "granted"); | ||
675 | |||
676 | if (av == 0) { | ||
677 | audit_log_format(ab, " null"); | ||
678 | return; | ||
679 | } | ||
680 | |||
681 | perms = secclass_map[sad->tclass-1].perms; | ||
682 | |||
683 | audit_log_format(ab, " {"); | ||
684 | i = 0; | ||
685 | perm = 1; | ||
686 | while (i < (sizeof(av) * 8)) { | ||
687 | if ((perm & av) && perms[i]) { | ||
688 | audit_log_format(ab, " %s", perms[i]); | ||
689 | av &= ~perm; | ||
690 | } | ||
691 | i++; | ||
692 | perm <<= 1; | ||
693 | } | ||
694 | |||
695 | if (av) | ||
696 | audit_log_format(ab, " 0x%x", av); | ||
697 | |||
698 | audit_log_format(ab, " } for "); | ||
743 | } | 699 | } |
744 | 700 | ||
745 | /** | 701 | /** |
@@ -751,14 +707,47 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) | |||
751 | static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | 707 | static void avc_audit_post_callback(struct audit_buffer *ab, void *a) |
752 | { | 708 | { |
753 | struct common_audit_data *ad = a; | 709 | struct common_audit_data *ad = a; |
754 | audit_log_format(ab, " "); | 710 | struct selinux_audit_data *sad = ad->selinux_audit_data; |
755 | avc_dump_query(ab, ad->selinux_audit_data->state, | 711 | char *scontext; |
756 | ad->selinux_audit_data->ssid, | 712 | u32 scontext_len; |
757 | ad->selinux_audit_data->tsid, | 713 | int rc; |
758 | ad->selinux_audit_data->tclass); | 714 | |
759 | if (ad->selinux_audit_data->denied) { | 715 | rc = security_sid_to_context(sad->state, sad->ssid, &scontext, |
760 | audit_log_format(ab, " permissive=%u", | 716 | &scontext_len); |
761 | ad->selinux_audit_data->result ? 0 : 1); | 717 | if (rc) |
718 | audit_log_format(ab, " ssid=%d", sad->ssid); | ||
719 | else { | ||
720 | audit_log_format(ab, " scontext=%s", scontext); | ||
721 | kfree(scontext); | ||
722 | } | ||
723 | |||
724 | rc = security_sid_to_context(sad->state, sad->tsid, &scontext, | ||
725 | &scontext_len); | ||
726 | if (rc) | ||
727 | audit_log_format(ab, " tsid=%d", sad->tsid); | ||
728 | else { | ||
729 | audit_log_format(ab, " tcontext=%s", scontext); | ||
730 | kfree(scontext); | ||
731 | } | ||
732 | |||
733 | audit_log_format(ab, " tclass=%s", secclass_map[sad->tclass-1].name); | ||
734 | |||
735 | if (sad->denied) | ||
736 | audit_log_format(ab, " permissive=%u", sad->result ? 0 : 1); | ||
737 | |||
738 | /* in case of invalid context report also the actual context string */ | ||
739 | rc = security_sid_to_context_inval(sad->state, sad->ssid, &scontext, | ||
740 | &scontext_len); | ||
741 | if (!rc && scontext) { | ||
742 | audit_log_format(ab, " srawcon=%s", scontext); | ||
743 | kfree(scontext); | ||
744 | } | ||
745 | |||
746 | rc = security_sid_to_context_inval(sad->state, sad->tsid, &scontext, | ||
747 | &scontext_len); | ||
748 | if (!rc && scontext) { | ||
749 | audit_log_format(ab, " trawcon=%s", scontext); | ||
750 | kfree(scontext); | ||
762 | } | 751 | } |
763 | } | 752 | } |
764 | 753 | ||
@@ -772,6 +761,9 @@ noinline int slow_avc_audit(struct selinux_state *state, | |||
772 | struct common_audit_data stack_data; | 761 | struct common_audit_data stack_data; |
773 | struct selinux_audit_data sad; | 762 | struct selinux_audit_data sad; |
774 | 763 | ||
764 | if (WARN_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map))) | ||
765 | return -EINVAL; | ||
766 | |||
775 | if (!a) { | 767 | if (!a) { |
776 | a = &stack_data; | 768 | a = &stack_data; |
777 | a->type = LSM_AUDIT_DATA_NONE; | 769 | a->type = LSM_AUDIT_DATA_NONE; |
@@ -838,6 +830,7 @@ out: | |||
838 | * @ssid,@tsid,@tclass : identifier of an AVC entry | 830 | * @ssid,@tsid,@tclass : identifier of an AVC entry |
839 | * @seqno : sequence number when decision was made | 831 | * @seqno : sequence number when decision was made |
840 | * @xpd: extended_perms_decision to be added to the node | 832 | * @xpd: extended_perms_decision to be added to the node |
833 | * @flags: the AVC_* flags, e.g. AVC_NONBLOCKING, AVC_EXTENDED_PERMS, or 0. | ||
841 | * | 834 | * |
842 | * if a valid AVC entry doesn't exist,this function returns -ENOENT. | 835 | * if a valid AVC entry doesn't exist,this function returns -ENOENT. |
843 | * if kmalloc() called internal returns NULL, this function returns -ENOMEM. | 836 | * if kmalloc() called internal returns NULL, this function returns -ENOMEM. |
@@ -856,6 +849,22 @@ static int avc_update_node(struct selinux_avc *avc, | |||
856 | struct hlist_head *head; | 849 | struct hlist_head *head; |
857 | spinlock_t *lock; | 850 | spinlock_t *lock; |
858 | 851 | ||
852 | /* | ||
853 | * If we are in a non-blocking code path, e.g. VFS RCU walk, | ||
854 | * then we must not add permissions to a cache entry | ||
855 | * because we cannot safely audit the denial. Otherwise, | ||
856 | * during the subsequent blocking retry (e.g. VFS ref walk), we | ||
857 | * will find the permissions already granted in the cache entry | ||
858 | * and won't audit anything at all, leading to silent denials in | ||
859 | * permissive mode that only appear when in enforcing mode. | ||
860 | * | ||
861 | * See the corresponding handling in slow_avc_audit(), and the | ||
862 | * logic in selinux_inode_permission for the MAY_NOT_BLOCK flag, | ||
863 | * which is transliterated into AVC_NONBLOCKING. | ||
864 | */ | ||
865 | if (flags & AVC_NONBLOCKING) | ||
866 | return 0; | ||
867 | |||
859 | node = avc_alloc_node(avc); | 868 | node = avc_alloc_node(avc); |
860 | if (!node) { | 869 | if (!node) { |
861 | rc = -ENOMEM; | 870 | rc = -ENOMEM; |
@@ -1050,7 +1059,8 @@ int avc_has_extended_perms(struct selinux_state *state, | |||
1050 | int rc = 0, rc2; | 1059 | int rc = 0, rc2; |
1051 | 1060 | ||
1052 | xp_node = &local_xp_node; | 1061 | xp_node = &local_xp_node; |
1053 | BUG_ON(!requested); | 1062 | if (WARN_ON(!requested)) |
1063 | return -EACCES; | ||
1054 | 1064 | ||
1055 | rcu_read_lock(); | 1065 | rcu_read_lock(); |
1056 | 1066 | ||
@@ -1115,7 +1125,7 @@ decision: | |||
1115 | * @tsid: target security identifier | 1125 | * @tsid: target security identifier |
1116 | * @tclass: target security class | 1126 | * @tclass: target security class |
1117 | * @requested: requested permissions, interpreted based on @tclass | 1127 | * @requested: requested permissions, interpreted based on @tclass |
1118 | * @flags: AVC_STRICT or 0 | 1128 | * @flags: AVC_STRICT, AVC_NONBLOCKING, or 0 |
1119 | * @avd: access vector decisions | 1129 | * @avd: access vector decisions |
1120 | * | 1130 | * |
1121 | * Check the AVC to determine whether the @requested permissions are granted | 1131 | * Check the AVC to determine whether the @requested permissions are granted |
@@ -1140,7 +1150,8 @@ inline int avc_has_perm_noaudit(struct selinux_state *state, | |||
1140 | int rc = 0; | 1150 | int rc = 0; |
1141 | u32 denied; | 1151 | u32 denied; |
1142 | 1152 | ||
1143 | BUG_ON(!requested); | 1153 | if (WARN_ON(!requested)) |
1154 | return -EACCES; | ||
1144 | 1155 | ||
1145 | rcu_read_lock(); | 1156 | rcu_read_lock(); |
1146 | 1157 | ||
@@ -1191,24 +1202,6 @@ int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass, | |||
1191 | return rc; | 1202 | return rc; |
1192 | } | 1203 | } |
1193 | 1204 | ||
1194 | int avc_has_perm_flags(struct selinux_state *state, | ||
1195 | u32 ssid, u32 tsid, u16 tclass, u32 requested, | ||
1196 | struct common_audit_data *auditdata, | ||
1197 | int flags) | ||
1198 | { | ||
1199 | struct av_decision avd; | ||
1200 | int rc, rc2; | ||
1201 | |||
1202 | rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0, | ||
1203 | &avd); | ||
1204 | |||
1205 | rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc, | ||
1206 | auditdata, flags); | ||
1207 | if (rc2) | ||
1208 | return rc2; | ||
1209 | return rc; | ||
1210 | } | ||
1211 | |||
1212 | u32 avc_policy_seqno(struct selinux_state *state) | 1205 | u32 avc_policy_seqno(struct selinux_state *state) |
1213 | { | 1206 | { |
1214 | return state->avc->avc_cache.latest_notif; | 1207 | return state->avc->avc_cache.latest_notif; |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5d92167dbe05..2f82a54f8703 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -490,16 +490,10 @@ static int may_context_mount_inode_relabel(u32 sid, | |||
490 | return rc; | 490 | return rc; |
491 | } | 491 | } |
492 | 492 | ||
493 | static int selinux_is_sblabel_mnt(struct super_block *sb) | 493 | static int selinux_is_genfs_special_handling(struct super_block *sb) |
494 | { | 494 | { |
495 | struct superblock_security_struct *sbsec = sb->s_security; | 495 | /* Special handling. Genfs but also in-core setxattr handler */ |
496 | 496 | return !strcmp(sb->s_type->name, "sysfs") || | |
497 | return sbsec->behavior == SECURITY_FS_USE_XATTR || | ||
498 | sbsec->behavior == SECURITY_FS_USE_TRANS || | ||
499 | sbsec->behavior == SECURITY_FS_USE_TASK || | ||
500 | sbsec->behavior == SECURITY_FS_USE_NATIVE || | ||
501 | /* Special handling. Genfs but also in-core setxattr handler */ | ||
502 | !strcmp(sb->s_type->name, "sysfs") || | ||
503 | !strcmp(sb->s_type->name, "pstore") || | 497 | !strcmp(sb->s_type->name, "pstore") || |
504 | !strcmp(sb->s_type->name, "debugfs") || | 498 | !strcmp(sb->s_type->name, "debugfs") || |
505 | !strcmp(sb->s_type->name, "tracefs") || | 499 | !strcmp(sb->s_type->name, "tracefs") || |
@@ -509,6 +503,34 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) | |||
509 | !strcmp(sb->s_type->name, "cgroup2"))); | 503 | !strcmp(sb->s_type->name, "cgroup2"))); |
510 | } | 504 | } |
511 | 505 | ||
506 | static int selinux_is_sblabel_mnt(struct super_block *sb) | ||
507 | { | ||
508 | struct superblock_security_struct *sbsec = sb->s_security; | ||
509 | |||
510 | /* | ||
511 | * IMPORTANT: Double-check logic in this function when adding a new | ||
512 | * SECURITY_FS_USE_* definition! | ||
513 | */ | ||
514 | BUILD_BUG_ON(SECURITY_FS_USE_MAX != 7); | ||
515 | |||
516 | switch (sbsec->behavior) { | ||
517 | case SECURITY_FS_USE_XATTR: | ||
518 | case SECURITY_FS_USE_TRANS: | ||
519 | case SECURITY_FS_USE_TASK: | ||
520 | case SECURITY_FS_USE_NATIVE: | ||
521 | return 1; | ||
522 | |||
523 | case SECURITY_FS_USE_GENFS: | ||
524 | return selinux_is_genfs_special_handling(sb); | ||
525 | |||
526 | /* Never allow relabeling on context mounts */ | ||
527 | case SECURITY_FS_USE_MNTPOINT: | ||
528 | case SECURITY_FS_USE_NONE: | ||
529 | default: | ||
530 | return 0; | ||
531 | } | ||
532 | } | ||
533 | |||
512 | static int sb_finish_set_opts(struct super_block *sb) | 534 | static int sb_finish_set_opts(struct super_block *sb) |
513 | { | 535 | { |
514 | struct superblock_security_struct *sbsec = sb->s_security; | 536 | struct superblock_security_struct *sbsec = sb->s_security; |
@@ -2881,9 +2903,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, | |||
2881 | if (IS_ERR(isec)) | 2903 | if (IS_ERR(isec)) |
2882 | return PTR_ERR(isec); | 2904 | return PTR_ERR(isec); |
2883 | 2905 | ||
2884 | return avc_has_perm_flags(&selinux_state, | 2906 | return avc_has_perm(&selinux_state, |
2885 | sid, isec->sid, isec->sclass, FILE__READ, &ad, | 2907 | sid, isec->sid, isec->sclass, FILE__READ, &ad); |
2886 | rcu ? MAY_NOT_BLOCK : 0); | ||
2887 | } | 2908 | } |
2888 | 2909 | ||
2889 | static noinline int audit_inode_permission(struct inode *inode, | 2910 | static noinline int audit_inode_permission(struct inode *inode, |
@@ -2938,7 +2959,9 @@ static int selinux_inode_permission(struct inode *inode, int mask) | |||
2938 | return PTR_ERR(isec); | 2959 | return PTR_ERR(isec); |
2939 | 2960 | ||
2940 | rc = avc_has_perm_noaudit(&selinux_state, | 2961 | rc = avc_has_perm_noaudit(&selinux_state, |
2941 | sid, isec->sid, isec->sclass, perms, 0, &avd); | 2962 | sid, isec->sid, isec->sclass, perms, |
2963 | (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0, | ||
2964 | &avd); | ||
2942 | audited = avc_audit_required(perms, &avd, rc, | 2965 | audited = avc_audit_required(perms, &avd, rc, |
2943 | from_access ? FILE__AUDIT_ACCESS : 0, | 2966 | from_access ? FILE__AUDIT_ACCESS : 0, |
2944 | &denied); | 2967 | &denied); |
@@ -3197,12 +3220,16 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, | |||
3197 | const void *value, size_t size, int flags) | 3220 | const void *value, size_t size, int flags) |
3198 | { | 3221 | { |
3199 | struct inode_security_struct *isec = inode_security_novalidate(inode); | 3222 | struct inode_security_struct *isec = inode_security_novalidate(inode); |
3223 | struct superblock_security_struct *sbsec = inode->i_sb->s_security; | ||
3200 | u32 newsid; | 3224 | u32 newsid; |
3201 | int rc; | 3225 | int rc; |
3202 | 3226 | ||
3203 | if (strcmp(name, XATTR_SELINUX_SUFFIX)) | 3227 | if (strcmp(name, XATTR_SELINUX_SUFFIX)) |
3204 | return -EOPNOTSUPP; | 3228 | return -EOPNOTSUPP; |
3205 | 3229 | ||
3230 | if (!(sbsec->flags & SBLABEL_MNT)) | ||
3231 | return -EOPNOTSUPP; | ||
3232 | |||
3206 | if (!value || !size) | 3233 | if (!value || !size) |
3207 | return -EACCES; | 3234 | return -EACCES; |
3208 | 3235 | ||
@@ -6236,7 +6263,10 @@ static void selinux_inode_invalidate_secctx(struct inode *inode) | |||
6236 | */ | 6263 | */ |
6237 | static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) | 6264 | static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) |
6238 | { | 6265 | { |
6239 | return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0); | 6266 | int rc = selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, |
6267 | ctx, ctxlen, 0); | ||
6268 | /* Do not return error when suppressing label (SBLABEL_MNT not set). */ | ||
6269 | return rc == -EOPNOTSUPP ? 0 : rc; | ||
6240 | } | 6270 | } |
6241 | 6271 | ||
6242 | /* | 6272 | /* |
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index ef899bcfd2cb..7be0e1e90e8b 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
@@ -142,6 +142,7 @@ static inline int avc_audit(struct selinux_state *state, | |||
142 | 142 | ||
143 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | 143 | #define AVC_STRICT 1 /* Ignore permissive mode. */ |
144 | #define AVC_EXTENDED_PERMS 2 /* update extended permissions */ | 144 | #define AVC_EXTENDED_PERMS 2 /* update extended permissions */ |
145 | #define AVC_NONBLOCKING 4 /* non blocking */ | ||
145 | int avc_has_perm_noaudit(struct selinux_state *state, | 146 | int avc_has_perm_noaudit(struct selinux_state *state, |
146 | u32 ssid, u32 tsid, | 147 | u32 ssid, u32 tsid, |
147 | u16 tclass, u32 requested, | 148 | u16 tclass, u32 requested, |
@@ -152,11 +153,6 @@ int avc_has_perm(struct selinux_state *state, | |||
152 | u32 ssid, u32 tsid, | 153 | u32 ssid, u32 tsid, |
153 | u16 tclass, u32 requested, | 154 | u16 tclass, u32 requested, |
154 | struct common_audit_data *auditdata); | 155 | struct common_audit_data *auditdata); |
155 | int avc_has_perm_flags(struct selinux_state *state, | ||
156 | u32 ssid, u32 tsid, | ||
157 | u16 tclass, u32 requested, | ||
158 | struct common_audit_data *auditdata, | ||
159 | int flags); | ||
160 | 156 | ||
161 | int avc_has_extended_perms(struct selinux_state *state, | 157 | int avc_has_extended_perms(struct selinux_state *state, |
162 | u32 ssid, u32 tsid, u16 tclass, u32 requested, | 158 | u32 ssid, u32 tsid, u16 tclass, u32 requested, |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index ba8eedf42b90..f68fb25b5702 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -255,6 +255,9 @@ int security_sid_to_context(struct selinux_state *state, u32 sid, | |||
255 | int security_sid_to_context_force(struct selinux_state *state, | 255 | int security_sid_to_context_force(struct selinux_state *state, |
256 | u32 sid, char **scontext, u32 *scontext_len); | 256 | u32 sid, char **scontext, u32 *scontext_len); |
257 | 257 | ||
258 | int security_sid_to_context_inval(struct selinux_state *state, | ||
259 | u32 sid, char **scontext, u32 *scontext_len); | ||
260 | |||
258 | int security_context_to_sid(struct selinux_state *state, | 261 | int security_context_to_sid(struct selinux_state *state, |
259 | const char *scontext, u32 scontext_len, | 262 | const char *scontext, u32 scontext_len, |
260 | u32 *out_sid, gfp_t gfp); | 263 | u32 *out_sid, gfp_t gfp); |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d6e7b4856d93..a0a2aa964111 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -1280,7 +1280,8 @@ const char *security_get_initial_sid_context(u32 sid) | |||
1280 | 1280 | ||
1281 | static int security_sid_to_context_core(struct selinux_state *state, | 1281 | static int security_sid_to_context_core(struct selinux_state *state, |
1282 | u32 sid, char **scontext, | 1282 | u32 sid, char **scontext, |
1283 | u32 *scontext_len, int force) | 1283 | u32 *scontext_len, int force, |
1284 | int only_invalid) | ||
1284 | { | 1285 | { |
1285 | struct policydb *policydb; | 1286 | struct policydb *policydb; |
1286 | struct sidtab *sidtab; | 1287 | struct sidtab *sidtab; |
@@ -1325,8 +1326,14 @@ static int security_sid_to_context_core(struct selinux_state *state, | |||
1325 | rc = -EINVAL; | 1326 | rc = -EINVAL; |
1326 | goto out_unlock; | 1327 | goto out_unlock; |
1327 | } | 1328 | } |
1328 | rc = context_struct_to_string(policydb, context, scontext, | 1329 | if (only_invalid && !context->len) { |
1329 | scontext_len); | 1330 | scontext = NULL; |
1331 | scontext_len = 0; | ||
1332 | rc = 0; | ||
1333 | } else { | ||
1334 | rc = context_struct_to_string(policydb, context, scontext, | ||
1335 | scontext_len); | ||
1336 | } | ||
1330 | out_unlock: | 1337 | out_unlock: |
1331 | read_unlock(&state->ss->policy_rwlock); | 1338 | read_unlock(&state->ss->policy_rwlock); |
1332 | out: | 1339 | out: |
@@ -1348,14 +1355,34 @@ int security_sid_to_context(struct selinux_state *state, | |||
1348 | u32 sid, char **scontext, u32 *scontext_len) | 1355 | u32 sid, char **scontext, u32 *scontext_len) |
1349 | { | 1356 | { |
1350 | return security_sid_to_context_core(state, sid, scontext, | 1357 | return security_sid_to_context_core(state, sid, scontext, |
1351 | scontext_len, 0); | 1358 | scontext_len, 0, 0); |
1352 | } | 1359 | } |
1353 | 1360 | ||
1354 | int security_sid_to_context_force(struct selinux_state *state, u32 sid, | 1361 | int security_sid_to_context_force(struct selinux_state *state, u32 sid, |
1355 | char **scontext, u32 *scontext_len) | 1362 | char **scontext, u32 *scontext_len) |
1356 | { | 1363 | { |
1357 | return security_sid_to_context_core(state, sid, scontext, | 1364 | return security_sid_to_context_core(state, sid, scontext, |
1358 | scontext_len, 1); | 1365 | scontext_len, 1, 0); |
1366 | } | ||
1367 | |||
1368 | /** | ||
1369 | * security_sid_to_context_inval - Obtain a context for a given SID if it | ||
1370 | * is invalid. | ||
1371 | * @sid: security identifier, SID | ||
1372 | * @scontext: security context | ||
1373 | * @scontext_len: length in bytes | ||
1374 | * | ||
1375 | * Write the string representation of the context associated with @sid | ||
1376 | * into a dynamically allocated string of the correct size, but only if the | ||
1377 | * context is invalid in the current policy. Set @scontext to point to | ||
1378 | * this string (or NULL if the context is valid) and set @scontext_len to | ||
1379 | * the length of the string (or 0 if the context is valid). | ||
1380 | */ | ||
1381 | int security_sid_to_context_inval(struct selinux_state *state, u32 sid, | ||
1382 | char **scontext, u32 *scontext_len) | ||
1383 | { | ||
1384 | return security_sid_to_context_core(state, sid, scontext, | ||
1385 | scontext_len, 1, 1); | ||
1359 | } | 1386 | } |
1360 | 1387 | ||
1361 | /* | 1388 | /* |