summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-09-23 14:21:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-23 14:21:04 -0400
commit5825a95fe92566ada2292a65de030850b5cff1da (patch)
tree8e210a297844f6e07e0acb6ee793036a2c692976
parent3c6a6910a81eae3566bb5fef6ea0f624382595e6 (diff)
parent15322a0d90b6fd62ae8f22e5b87f735c3fdfeff7 (diff)
Merge tag 'selinux-pr-20190917' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux
Pull selinux updates from Paul Moore: - Add LSM hooks, and SELinux access control hooks, for dnotify, fanotify, and inotify watches. This has been discussed with both the LSM and fs/notify folks and everybody is good with these new hooks. - The LSM stacking changes missed a few calls to current_security() in the SELinux code; we fix those and remove current_security() for good. - Improve our network object labeling cache so that we always return the object's label, even when under memory pressure. Previously we would return an error if we couldn't allocate a new cache entry, now we always return the label even if we can't create a new cache entry for it. - Convert the sidtab atomic_t counter to a normal u32 with READ/WRITE_ONCE() and memory barrier protection. - A few patches to policydb.c to clean things up (remove forward declarations, long lines, bad variable names, etc) * tag 'selinux-pr-20190917' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux: lsm: remove current_security() selinux: fix residual uses of current_security() for the SELinux blob selinux: avoid atomic_t usage in sidtab fanotify, inotify, dnotify, security: add security hook for fs notifications selinux: always return a secid from the network caches if we find one selinux: policydb - rename type_val_to_struct_array selinux: policydb - fix some checkpatch.pl warnings selinux: shuffle around policydb.c to get rid of forward declarations
-rw-r--r--fs/notify/dnotify/dnotify.c15
-rw-r--r--fs/notify/fanotify/fanotify_user.c19
-rw-r--r--fs/notify/inotify/inotify_user.c14
-rw-r--r--include/linux/cred.h1
-rw-r--r--include/linux/lsm_hooks.h9
-rw-r--r--include/linux/security.h10
-rw-r--r--security/security.c6
-rw-r--r--security/selinux/hooks.c49
-rw-r--r--security/selinux/include/classmap.h5
-rw-r--r--security/selinux/include/objsec.h20
-rw-r--r--security/selinux/netif.c31
-rw-r--r--security/selinux/netnode.c30
-rw-r--r--security/selinux/netport.c24
-rw-r--r--security/selinux/ss/policydb.c402
-rw-r--r--security/selinux/ss/policydb.h2
-rw-r--r--security/selinux/ss/services.c6
-rw-r--r--security/selinux/ss/sidtab.c48
-rw-r--r--security/selinux/ss/sidtab.h19
18 files changed, 403 insertions, 307 deletions
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index c03758c91481..7a42c2ebe28d 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -13,6 +13,7 @@
13#include <linux/sched/signal.h> 13#include <linux/sched/signal.h>
14#include <linux/dnotify.h> 14#include <linux/dnotify.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/security.h>
16#include <linux/spinlock.h> 17#include <linux/spinlock.h>
17#include <linux/slab.h> 18#include <linux/slab.h>
18#include <linux/fdtable.h> 19#include <linux/fdtable.h>
@@ -279,6 +280,17 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
279 goto out_err; 280 goto out_err;
280 } 281 }
281 282
283 /*
284 * convert the userspace DN_* "arg" to the internal FS_*
285 * defined in fsnotify
286 */
287 mask = convert_arg(arg);
288
289 error = security_path_notify(&filp->f_path, mask,
290 FSNOTIFY_OBJ_TYPE_INODE);
291 if (error)
292 goto out_err;
293
282 /* expect most fcntl to add new rather than augment old */ 294 /* expect most fcntl to add new rather than augment old */
283 dn = kmem_cache_alloc(dnotify_struct_cache, GFP_KERNEL); 295 dn = kmem_cache_alloc(dnotify_struct_cache, GFP_KERNEL);
284 if (!dn) { 296 if (!dn) {
@@ -293,9 +305,6 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
293 goto out_err; 305 goto out_err;
294 } 306 }
295 307
296 /* convert the userspace DN_* "arg" to the internal FS_* defines in fsnotify */
297 mask = convert_arg(arg);
298
299 /* set up the new_fsn_mark and new_dn_mark */ 308 /* set up the new_fsn_mark and new_dn_mark */
300 new_fsn_mark = &new_dn_mark->fsn_mark; 309 new_fsn_mark = &new_dn_mark->fsn_mark;
301 fsnotify_init_mark(new_fsn_mark, dnotify_group); 310 fsnotify_init_mark(new_fsn_mark, dnotify_group);
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 91006f47e420..8508ab575017 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -528,7 +528,8 @@ static const struct file_operations fanotify_fops = {
528}; 528};
529 529
530static int fanotify_find_path(int dfd, const char __user *filename, 530static int fanotify_find_path(int dfd, const char __user *filename,
531 struct path *path, unsigned int flags) 531 struct path *path, unsigned int flags, __u64 mask,
532 unsigned int obj_type)
532{ 533{
533 int ret; 534 int ret;
534 535
@@ -567,8 +568,15 @@ static int fanotify_find_path(int dfd, const char __user *filename,
567 568
568 /* you can only watch an inode if you have read permissions on it */ 569 /* you can only watch an inode if you have read permissions on it */
569 ret = inode_permission(path->dentry->d_inode, MAY_READ); 570 ret = inode_permission(path->dentry->d_inode, MAY_READ);
571 if (ret) {
572 path_put(path);
573 goto out;
574 }
575
576 ret = security_path_notify(path, mask, obj_type);
570 if (ret) 577 if (ret)
571 path_put(path); 578 path_put(path);
579
572out: 580out:
573 return ret; 581 return ret;
574} 582}
@@ -947,6 +955,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
947 __kernel_fsid_t __fsid, *fsid = NULL; 955 __kernel_fsid_t __fsid, *fsid = NULL;
948 u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; 956 u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
949 unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; 957 unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
958 unsigned int obj_type;
950 int ret; 959 int ret;
951 960
952 pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n", 961 pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n",
@@ -961,8 +970,13 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
961 970
962 switch (mark_type) { 971 switch (mark_type) {
963 case FAN_MARK_INODE: 972 case FAN_MARK_INODE:
973 obj_type = FSNOTIFY_OBJ_TYPE_INODE;
974 break;
964 case FAN_MARK_MOUNT: 975 case FAN_MARK_MOUNT:
976 obj_type = FSNOTIFY_OBJ_TYPE_VFSMOUNT;
977 break;
965 case FAN_MARK_FILESYSTEM: 978 case FAN_MARK_FILESYSTEM:
979 obj_type = FSNOTIFY_OBJ_TYPE_SB;
966 break; 980 break;
967 default: 981 default:
968 return -EINVAL; 982 return -EINVAL;
@@ -1030,7 +1044,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
1030 goto fput_and_out; 1044 goto fput_and_out;
1031 } 1045 }
1032 1046
1033 ret = fanotify_find_path(dfd, pathname, &path, flags); 1047 ret = fanotify_find_path(dfd, pathname, &path, flags,
1048 (mask & ALL_FSNOTIFY_EVENTS), obj_type);
1034 if (ret) 1049 if (ret)
1035 goto fput_and_out; 1050 goto fput_and_out;
1036 1051
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 0b815178126e..107537a543fd 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -30,6 +30,7 @@
30#include <linux/poll.h> 30#include <linux/poll.h>
31#include <linux/wait.h> 31#include <linux/wait.h>
32#include <linux/memcontrol.h> 32#include <linux/memcontrol.h>
33#include <linux/security.h>
33 34
34#include "inotify.h" 35#include "inotify.h"
35#include "../fdinfo.h" 36#include "../fdinfo.h"
@@ -331,7 +332,8 @@ static const struct file_operations inotify_fops = {
331/* 332/*
332 * find_inode - resolve a user-given path to a specific inode 333 * find_inode - resolve a user-given path to a specific inode
333 */ 334 */
334static int inotify_find_inode(const char __user *dirname, struct path *path, unsigned flags) 335static int inotify_find_inode(const char __user *dirname, struct path *path,
336 unsigned int flags, __u64 mask)
335{ 337{
336 int error; 338 int error;
337 339
@@ -340,8 +342,15 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
340 return error; 342 return error;
341 /* you can only watch an inode if you have read permissions on it */ 343 /* you can only watch an inode if you have read permissions on it */
342 error = inode_permission(path->dentry->d_inode, MAY_READ); 344 error = inode_permission(path->dentry->d_inode, MAY_READ);
345 if (error) {
346 path_put(path);
347 return error;
348 }
349 error = security_path_notify(path, mask,
350 FSNOTIFY_OBJ_TYPE_INODE);
343 if (error) 351 if (error)
344 path_put(path); 352 path_put(path);
353
345 return error; 354 return error;
346} 355}
347 356
@@ -733,7 +742,8 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
733 if (mask & IN_ONLYDIR) 742 if (mask & IN_ONLYDIR)
734 flags |= LOOKUP_DIRECTORY; 743 flags |= LOOKUP_DIRECTORY;
735 744
736 ret = inotify_find_inode(pathname, &path, flags); 745 ret = inotify_find_inode(pathname, &path, flags,
746 (mask & IN_ALL_EVENTS));
737 if (ret) 747 if (ret)
738 goto fput_and_out; 748 goto fput_and_out;
739 749
diff --git a/include/linux/cred.h b/include/linux/cred.h
index f7a30e0099be..18639c069263 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -386,7 +386,6 @@ static inline void put_cred(const struct cred *_cred)
386#define current_fsgid() (current_cred_xxx(fsgid)) 386#define current_fsgid() (current_cred_xxx(fsgid))
387#define current_cap() (current_cred_xxx(cap_effective)) 387#define current_cap() (current_cred_xxx(cap_effective))
388#define current_user() (current_cred_xxx(user)) 388#define current_user() (current_cred_xxx(user))
389#define current_security() (current_cred_xxx(security))
390 389
391extern struct user_namespace init_user_ns; 390extern struct user_namespace init_user_ns;
392#ifdef CONFIG_USER_NS 391#ifdef CONFIG_USER_NS
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index df1318d85f7d..3fced5824aee 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -339,6 +339,9 @@
339 * Check for permission to change root directory. 339 * Check for permission to change root directory.
340 * @path contains the path structure. 340 * @path contains the path structure.
341 * Return 0 if permission is granted. 341 * Return 0 if permission is granted.
342 * @path_notify:
343 * Check permissions before setting a watch on events as defined by @mask,
344 * on an object at @path, whose type is defined by @obj_type.
342 * @inode_readlink: 345 * @inode_readlink:
343 * Check the permission to read the symbolic link. 346 * Check the permission to read the symbolic link.
344 * @dentry contains the dentry structure for the file link. 347 * @dentry contains the dentry structure for the file link.
@@ -1535,7 +1538,9 @@ union security_list_options {
1535 int (*path_chown)(const struct path *path, kuid_t uid, kgid_t gid); 1538 int (*path_chown)(const struct path *path, kuid_t uid, kgid_t gid);
1536 int (*path_chroot)(const struct path *path); 1539 int (*path_chroot)(const struct path *path);
1537#endif 1540#endif
1538 1541 /* Needed for inode based security check */
1542 int (*path_notify)(const struct path *path, u64 mask,
1543 unsigned int obj_type);
1539 int (*inode_alloc_security)(struct inode *inode); 1544 int (*inode_alloc_security)(struct inode *inode);
1540 void (*inode_free_security)(struct inode *inode); 1545 void (*inode_free_security)(struct inode *inode);
1541 int (*inode_init_security)(struct inode *inode, struct inode *dir, 1546 int (*inode_init_security)(struct inode *inode, struct inode *dir,
@@ -1860,6 +1865,8 @@ struct security_hook_heads {
1860 struct hlist_head path_chown; 1865 struct hlist_head path_chown;
1861 struct hlist_head path_chroot; 1866 struct hlist_head path_chroot;
1862#endif 1867#endif
1868 /* Needed for inode based modules as well */
1869 struct hlist_head path_notify;
1863 struct hlist_head inode_alloc_security; 1870 struct hlist_head inode_alloc_security;
1864 struct hlist_head inode_free_security; 1871 struct hlist_head inode_free_security;
1865 struct hlist_head inode_init_security; 1872 struct hlist_head inode_init_security;
diff --git a/include/linux/security.h b/include/linux/security.h
index 5f7441abbf42..ace6fdb604f9 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -259,7 +259,8 @@ int security_dentry_create_files_as(struct dentry *dentry, int mode,
259 struct qstr *name, 259 struct qstr *name,
260 const struct cred *old, 260 const struct cred *old,
261 struct cred *new); 261 struct cred *new);
262 262int security_path_notify(const struct path *path, u64 mask,
263 unsigned int obj_type);
263int security_inode_alloc(struct inode *inode); 264int security_inode_alloc(struct inode *inode);
264void security_inode_free(struct inode *inode); 265void security_inode_free(struct inode *inode);
265int security_inode_init_security(struct inode *inode, struct inode *dir, 266int security_inode_init_security(struct inode *inode, struct inode *dir,
@@ -387,7 +388,6 @@ int security_ismaclabel(const char *name);
387int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); 388int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
388int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); 389int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
389void security_release_secctx(char *secdata, u32 seclen); 390void security_release_secctx(char *secdata, u32 seclen);
390
391void security_inode_invalidate_secctx(struct inode *inode); 391void security_inode_invalidate_secctx(struct inode *inode);
392int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); 392int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
393int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); 393int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
@@ -621,6 +621,12 @@ static inline int security_move_mount(const struct path *from_path,
621 return 0; 621 return 0;
622} 622}
623 623
624static inline int security_path_notify(const struct path *path, u64 mask,
625 unsigned int obj_type)
626{
627 return 0;
628}
629
624static inline int security_inode_alloc(struct inode *inode) 630static inline int security_inode_alloc(struct inode *inode)
625{ 631{
626 return 0; 632 return 0;
diff --git a/security/security.c b/security/security.c
index 250ee2d76406..25ee5c75551f 100644
--- a/security/security.c
+++ b/security/security.c
@@ -870,6 +870,12 @@ int security_move_mount(const struct path *from_path, const struct path *to_path
870 return call_int_hook(move_mount, 0, from_path, to_path); 870 return call_int_hook(move_mount, 0, from_path, to_path);
871} 871}
872 872
873int security_path_notify(const struct path *path, u64 mask,
874 unsigned int obj_type)
875{
876 return call_int_hook(path_notify, 0, path, mask, obj_type);
877}
878
873int security_inode_alloc(struct inode *inode) 879int security_inode_alloc(struct inode *inode)
874{ 880{
875 int rc = lsm_inode_alloc(inode); 881 int rc = lsm_inode_alloc(inode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 74dd46de01b6..9625b99e677f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -89,6 +89,8 @@
89#include <linux/kernfs.h> 89#include <linux/kernfs.h>
90#include <linux/stringhash.h> /* for hashlen_string() */ 90#include <linux/stringhash.h> /* for hashlen_string() */
91#include <uapi/linux/mount.h> 91#include <uapi/linux/mount.h>
92#include <linux/fsnotify.h>
93#include <linux/fanotify.h>
92 94
93#include "avc.h" 95#include "avc.h"
94#include "objsec.h" 96#include "objsec.h"
@@ -3275,6 +3277,50 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
3275 return -EACCES; 3277 return -EACCES;
3276} 3278}
3277 3279
3280static int selinux_path_notify(const struct path *path, u64 mask,
3281 unsigned int obj_type)
3282{
3283 int ret;
3284 u32 perm;
3285
3286 struct common_audit_data ad;
3287
3288 ad.type = LSM_AUDIT_DATA_PATH;
3289 ad.u.path = *path;
3290
3291 /*
3292 * Set permission needed based on the type of mark being set.
3293 * Performs an additional check for sb watches.
3294 */
3295 switch (obj_type) {
3296 case FSNOTIFY_OBJ_TYPE_VFSMOUNT:
3297 perm = FILE__WATCH_MOUNT;
3298 break;
3299 case FSNOTIFY_OBJ_TYPE_SB:
3300 perm = FILE__WATCH_SB;
3301 ret = superblock_has_perm(current_cred(), path->dentry->d_sb,
3302 FILESYSTEM__WATCH, &ad);
3303 if (ret)
3304 return ret;
3305 break;
3306 case FSNOTIFY_OBJ_TYPE_INODE:
3307 perm = FILE__WATCH;
3308 break;
3309 default:
3310 return -EINVAL;
3311 }
3312
3313 /* blocking watches require the file:watch_with_perm permission */
3314 if (mask & (ALL_FSNOTIFY_PERM_EVENTS))
3315 perm |= FILE__WATCH_WITH_PERM;
3316
3317 /* watches on read-like events need the file:watch_reads permission */
3318 if (mask & (FS_ACCESS | FS_ACCESS_PERM | FS_CLOSE_NOWRITE))
3319 perm |= FILE__WATCH_READS;
3320
3321 return path_has_perm(current_cred(), path, perm);
3322}
3323
3278/* 3324/*
3279 * Copy the inode security context value to the user. 3325 * Copy the inode security context value to the user.
3280 * 3326 *
@@ -3403,7 +3449,7 @@ static int selinux_inode_copy_up_xattr(const char *name)
3403static int selinux_kernfs_init_security(struct kernfs_node *kn_dir, 3449static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
3404 struct kernfs_node *kn) 3450 struct kernfs_node *kn)
3405{ 3451{
3406 const struct task_security_struct *tsec = current_security(); 3452 const struct task_security_struct *tsec = selinux_cred(current_cred());
3407 u32 parent_sid, newsid, clen; 3453 u32 parent_sid, newsid, clen;
3408 int rc; 3454 int rc;
3409 char *context; 3455 char *context;
@@ -6818,6 +6864,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
6818 LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid), 6864 LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
6819 LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), 6865 LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
6820 LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), 6866 LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
6867 LSM_HOOK_INIT(path_notify, selinux_path_notify),
6821 6868
6822 LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security), 6869 LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security),
6823 6870
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 201f7e588a29..32e9b03be3dd 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -7,7 +7,8 @@
7 7
8#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \ 8#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
9 "rename", "execute", "quotaon", "mounton", "audit_access", \ 9 "rename", "execute", "quotaon", "mounton", "audit_access", \
10 "open", "execmod" 10 "open", "execmod", "watch", "watch_mount", "watch_sb", \
11 "watch_with_perm", "watch_reads"
11 12
12#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \ 13#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
13 "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \ 14 "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \
@@ -60,7 +61,7 @@ struct security_class_mapping secclass_map[] = {
60 { "filesystem", 61 { "filesystem",
61 { "mount", "remount", "unmount", "getattr", 62 { "mount", "remount", "unmount", "getattr",
62 "relabelfrom", "relabelto", "associate", "quotamod", 63 "relabelfrom", "relabelto", "associate", "quotamod",
63 "quotaget", NULL } }, 64 "quotaget", "watch", NULL } },
64 { "file", 65 { "file",
65 { COMMON_FILE_PERMS, 66 { COMMON_FILE_PERMS,
66 "execute_no_trans", "entrypoint", NULL } }, 67 "execute_no_trans", "entrypoint", NULL } },
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 91c5395dd20c..586b7abd0aa7 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -37,16 +37,6 @@ struct task_security_struct {
37 u32 sockcreate_sid; /* fscreate SID */ 37 u32 sockcreate_sid; /* fscreate SID */
38}; 38};
39 39
40/*
41 * get the subjective security ID of the current task
42 */
43static inline u32 current_sid(void)
44{
45 const struct task_security_struct *tsec = current_security();
46
47 return tsec->sid;
48}
49
50enum label_initialized { 40enum label_initialized {
51 LABEL_INVALID, /* invalid or not initialized */ 41 LABEL_INVALID, /* invalid or not initialized */
52 LABEL_INITIALIZED, /* initialized */ 42 LABEL_INITIALIZED, /* initialized */
@@ -185,4 +175,14 @@ static inline struct ipc_security_struct *selinux_ipc(
185 return ipc->security + selinux_blob_sizes.lbs_ipc; 175 return ipc->security + selinux_blob_sizes.lbs_ipc;
186} 176}
187 177
178/*
179 * get the subjective security ID of the current task
180 */
181static inline u32 current_sid(void)
182{
183 const struct task_security_struct *tsec = selinux_cred(current_cred());
184
185 return tsec->sid;
186}
187
188#endif /* _SELINUX_OBJSEC_H_ */ 188#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/netif.c b/security/selinux/netif.c
index 9cb83eeee1d9..e40fecd73752 100644
--- a/security/selinux/netif.c
+++ b/security/selinux/netif.c
@@ -132,9 +132,9 @@ static void sel_netif_destroy(struct sel_netif *netif)
132 */ 132 */
133static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) 133static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
134{ 134{
135 int ret; 135 int ret = 0;
136 struct sel_netif *netif; 136 struct sel_netif *netif;
137 struct sel_netif *new = NULL; 137 struct sel_netif *new;
138 struct net_device *dev; 138 struct net_device *dev;
139 139
140 /* NOTE: we always use init's network namespace since we don't 140 /* NOTE: we always use init's network namespace since we don't
@@ -151,32 +151,27 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
151 netif = sel_netif_find(ns, ifindex); 151 netif = sel_netif_find(ns, ifindex);
152 if (netif != NULL) { 152 if (netif != NULL) {
153 *sid = netif->nsec.sid; 153 *sid = netif->nsec.sid;
154 ret = 0;
155 goto out; 154 goto out;
156 } 155 }
157 new = kzalloc(sizeof(*new), GFP_ATOMIC); 156
158 if (new == NULL) { 157 ret = security_netif_sid(&selinux_state, dev->name, sid);
159 ret = -ENOMEM;
160 goto out;
161 }
162 ret = security_netif_sid(&selinux_state, dev->name, &new->nsec.sid);
163 if (ret != 0)
164 goto out;
165 new->nsec.ns = ns;
166 new->nsec.ifindex = ifindex;
167 ret = sel_netif_insert(new);
168 if (ret != 0) 158 if (ret != 0)
169 goto out; 159 goto out;
170 *sid = new->nsec.sid; 160 new = kzalloc(sizeof(*new), GFP_ATOMIC);
161 if (new) {
162 new->nsec.ns = ns;
163 new->nsec.ifindex = ifindex;
164 new->nsec.sid = *sid;
165 if (sel_netif_insert(new))
166 kfree(new);
167 }
171 168
172out: 169out:
173 spin_unlock_bh(&sel_netif_lock); 170 spin_unlock_bh(&sel_netif_lock);
174 dev_put(dev); 171 dev_put(dev);
175 if (unlikely(ret)) { 172 if (unlikely(ret))
176 pr_warn("SELinux: failure in %s(), unable to determine network interface label (%d)\n", 173 pr_warn("SELinux: failure in %s(), unable to determine network interface label (%d)\n",
177 __func__, ifindex); 174 __func__, ifindex);
178 kfree(new);
179 }
180 return ret; 175 return ret;
181} 176}
182 177
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index cae1fcaffd1a..9ab84efa46c7 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -189,9 +189,9 @@ static void sel_netnode_insert(struct sel_netnode *node)
189 */ 189 */
190static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) 190static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
191{ 191{
192 int ret = -ENOMEM; 192 int ret;
193 struct sel_netnode *node; 193 struct sel_netnode *node;
194 struct sel_netnode *new = NULL; 194 struct sel_netnode *new;
195 195
196 spin_lock_bh(&sel_netnode_lock); 196 spin_lock_bh(&sel_netnode_lock);
197 node = sel_netnode_find(addr, family); 197 node = sel_netnode_find(addr, family);
@@ -200,38 +200,36 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
200 spin_unlock_bh(&sel_netnode_lock); 200 spin_unlock_bh(&sel_netnode_lock);
201 return 0; 201 return 0;
202 } 202 }
203
203 new = kzalloc(sizeof(*new), GFP_ATOMIC); 204 new = kzalloc(sizeof(*new), GFP_ATOMIC);
204 if (new == NULL)
205 goto out;
206 switch (family) { 205 switch (family) {
207 case PF_INET: 206 case PF_INET:
208 ret = security_node_sid(&selinux_state, PF_INET, 207 ret = security_node_sid(&selinux_state, PF_INET,
209 addr, sizeof(struct in_addr), sid); 208 addr, sizeof(struct in_addr), sid);
210 new->nsec.addr.ipv4 = *(__be32 *)addr; 209 if (new)
210 new->nsec.addr.ipv4 = *(__be32 *)addr;
211 break; 211 break;
212 case PF_INET6: 212 case PF_INET6:
213 ret = security_node_sid(&selinux_state, PF_INET6, 213 ret = security_node_sid(&selinux_state, PF_INET6,
214 addr, sizeof(struct in6_addr), sid); 214 addr, sizeof(struct in6_addr), sid);
215 new->nsec.addr.ipv6 = *(struct in6_addr *)addr; 215 if (new)
216 new->nsec.addr.ipv6 = *(struct in6_addr *)addr;
216 break; 217 break;
217 default: 218 default:
218 BUG(); 219 BUG();
219 ret = -EINVAL; 220 ret = -EINVAL;
220 } 221 }
221 if (ret != 0) 222 if (ret == 0 && new) {
222 goto out; 223 new->nsec.family = family;
223 224 new->nsec.sid = *sid;
224 new->nsec.family = family; 225 sel_netnode_insert(new);
225 new->nsec.sid = *sid; 226 } else
226 sel_netnode_insert(new); 227 kfree(new);
227 228
228out:
229 spin_unlock_bh(&sel_netnode_lock); 229 spin_unlock_bh(&sel_netnode_lock);
230 if (unlikely(ret)) { 230 if (unlikely(ret))
231 pr_warn("SELinux: failure in %s(), unable to determine network node label\n", 231 pr_warn("SELinux: failure in %s(), unable to determine network node label\n",
232 __func__); 232 __func__);
233 kfree(new);
234 }
235 return ret; 233 return ret;
236} 234}
237 235
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 364b6d5b8968..3f8b2c0458c8 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -137,9 +137,9 @@ static void sel_netport_insert(struct sel_netport *port)
137 */ 137 */
138static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) 138static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
139{ 139{
140 int ret = -ENOMEM; 140 int ret;
141 struct sel_netport *port; 141 struct sel_netport *port;
142 struct sel_netport *new = NULL; 142 struct sel_netport *new;
143 143
144 spin_lock_bh(&sel_netport_lock); 144 spin_lock_bh(&sel_netport_lock);
145 port = sel_netport_find(protocol, pnum); 145 port = sel_netport_find(protocol, pnum);
@@ -148,25 +148,23 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
148 spin_unlock_bh(&sel_netport_lock); 148 spin_unlock_bh(&sel_netport_lock);
149 return 0; 149 return 0;
150 } 150 }
151 new = kzalloc(sizeof(*new), GFP_ATOMIC); 151
152 if (new == NULL)
153 goto out;
154 ret = security_port_sid(&selinux_state, protocol, pnum, sid); 152 ret = security_port_sid(&selinux_state, protocol, pnum, sid);
155 if (ret != 0) 153 if (ret != 0)
156 goto out; 154 goto out;
157 155 new = kzalloc(sizeof(*new), GFP_ATOMIC);
158 new->psec.port = pnum; 156 if (new) {
159 new->psec.protocol = protocol; 157 new->psec.port = pnum;
160 new->psec.sid = *sid; 158 new->psec.protocol = protocol;
161 sel_netport_insert(new); 159 new->psec.sid = *sid;
160 sel_netport_insert(new);
161 }
162 162
163out: 163out:
164 spin_unlock_bh(&sel_netport_lock); 164 spin_unlock_bh(&sel_netport_lock);
165 if (unlikely(ret)) { 165 if (unlikely(ret))
166 pr_warn("SELinux: failure in %s(), unable to determine network port label\n", 166 pr_warn("SELinux: failure in %s(), unable to determine network port label\n",
167 __func__); 167 __func__);
168 kfree(new);
169 }
170 return ret; 168 return ret;
171} 169}
172 170
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index f8efaa9f647c..1260f5fb766e 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -177,6 +177,195 @@ static struct policydb_compat_info *policydb_lookup_compat(int version)
177} 177}
178 178
179/* 179/*
180 * The following *_destroy functions are used to
181 * free any memory allocated for each kind of
182 * symbol data in the policy database.
183 */
184
185static int perm_destroy(void *key, void *datum, void *p)
186{
187 kfree(key);
188 kfree(datum);
189 return 0;
190}
191
192static int common_destroy(void *key, void *datum, void *p)
193{
194 struct common_datum *comdatum;
195
196 kfree(key);
197 if (datum) {
198 comdatum = datum;
199 hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
200 hashtab_destroy(comdatum->permissions.table);
201 }
202 kfree(datum);
203 return 0;
204}
205
206static void constraint_expr_destroy(struct constraint_expr *expr)
207{
208 if (expr) {
209 ebitmap_destroy(&expr->names);
210 if (expr->type_names) {
211 ebitmap_destroy(&expr->type_names->types);
212 ebitmap_destroy(&expr->type_names->negset);
213 kfree(expr->type_names);
214 }
215 kfree(expr);
216 }
217}
218
219static int cls_destroy(void *key, void *datum, void *p)
220{
221 struct class_datum *cladatum;
222 struct constraint_node *constraint, *ctemp;
223 struct constraint_expr *e, *etmp;
224
225 kfree(key);
226 if (datum) {
227 cladatum = datum;
228 hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
229 hashtab_destroy(cladatum->permissions.table);
230 constraint = cladatum->constraints;
231 while (constraint) {
232 e = constraint->expr;
233 while (e) {
234 etmp = e;
235 e = e->next;
236 constraint_expr_destroy(etmp);
237 }
238 ctemp = constraint;
239 constraint = constraint->next;
240 kfree(ctemp);
241 }
242
243 constraint = cladatum->validatetrans;
244 while (constraint) {
245 e = constraint->expr;
246 while (e) {
247 etmp = e;
248 e = e->next;
249 constraint_expr_destroy(etmp);
250 }
251 ctemp = constraint;
252 constraint = constraint->next;
253 kfree(ctemp);
254 }
255 kfree(cladatum->comkey);
256 }
257 kfree(datum);
258 return 0;
259}
260
261static int role_destroy(void *key, void *datum, void *p)
262{
263 struct role_datum *role;
264
265 kfree(key);
266 if (datum) {
267 role = datum;
268 ebitmap_destroy(&role->dominates);
269 ebitmap_destroy(&role->types);
270 }
271 kfree(datum);
272 return 0;
273}
274
275static int type_destroy(void *key, void *datum, void *p)
276{
277 kfree(key);
278 kfree(datum);
279 return 0;
280}
281
282static int user_destroy(void *key, void *datum, void *p)
283{
284 struct user_datum *usrdatum;
285
286 kfree(key);
287 if (datum) {
288 usrdatum = datum;
289 ebitmap_destroy(&usrdatum->roles);
290 ebitmap_destroy(&usrdatum->range.level[0].cat);
291 ebitmap_destroy(&usrdatum->range.level[1].cat);
292 ebitmap_destroy(&usrdatum->dfltlevel.cat);
293 }
294 kfree(datum);
295 return 0;
296}
297
298static int sens_destroy(void *key, void *datum, void *p)
299{
300 struct level_datum *levdatum;
301
302 kfree(key);
303 if (datum) {
304 levdatum = datum;
305 if (levdatum->level)
306 ebitmap_destroy(&levdatum->level->cat);
307 kfree(levdatum->level);
308 }
309 kfree(datum);
310 return 0;
311}
312
313static int cat_destroy(void *key, void *datum, void *p)
314{
315 kfree(key);
316 kfree(datum);
317 return 0;
318}
319
320static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
321{
322 common_destroy,
323 cls_destroy,
324 role_destroy,
325 type_destroy,
326 user_destroy,
327 cond_destroy_bool,
328 sens_destroy,
329 cat_destroy,
330};
331
332static int filenametr_destroy(void *key, void *datum, void *p)
333{
334 struct filename_trans *ft = key;
335
336 kfree(ft->name);
337 kfree(key);
338 kfree(datum);
339 cond_resched();
340 return 0;
341}
342
343static int range_tr_destroy(void *key, void *datum, void *p)
344{
345 struct mls_range *rt = datum;
346
347 kfree(key);
348 ebitmap_destroy(&rt->level[0].cat);
349 ebitmap_destroy(&rt->level[1].cat);
350 kfree(datum);
351 cond_resched();
352 return 0;
353}
354
355static void ocontext_destroy(struct ocontext *c, int i)
356{
357 if (!c)
358 return;
359
360 context_destroy(&c->context[0]);
361 context_destroy(&c->context[1]);
362 if (i == OCON_ISID || i == OCON_FS ||
363 i == OCON_NETIF || i == OCON_FSUSE)
364 kfree(c->u.name);
365 kfree(c);
366}
367
368/*
180 * Initialize the role table. 369 * Initialize the role table.
181 */ 370 */
182static int roles_init(struct policydb *p) 371static int roles_init(struct policydb *p)
@@ -250,6 +439,7 @@ static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
250static u32 rangetr_hash(struct hashtab *h, const void *k) 439static u32 rangetr_hash(struct hashtab *h, const void *k)
251{ 440{
252 const struct range_trans *key = k; 441 const struct range_trans *key = k;
442
253 return (key->source_type + (key->target_type << 3) + 443 return (key->source_type + (key->target_type << 3) +
254 (key->target_class << 5)) & (h->size - 1); 444 (key->target_class << 5)) & (h->size - 1);
255} 445}
@@ -272,8 +462,6 @@ static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
272 return v; 462 return v;
273} 463}
274 464
275static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap);
276
277/* 465/*
278 * Initialize a policy database structure. 466 * Initialize a policy database structure.
279 */ 467 */
@@ -301,7 +489,8 @@ static int policydb_init(struct policydb *p)
301 if (rc) 489 if (rc)
302 goto out; 490 goto out;
303 491
304 p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); 492 p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp,
493 (1 << 10));
305 if (!p->filename_trans) { 494 if (!p->filename_trans) {
306 rc = -ENOMEM; 495 rc = -ENOMEM;
307 goto out; 496 goto out;
@@ -399,7 +588,7 @@ static int type_index(void *key, void *datum, void *datap)
399 || typdatum->bounds > p->p_types.nprim) 588 || typdatum->bounds > p->p_types.nprim)
400 return -EINVAL; 589 return -EINVAL;
401 p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key; 590 p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key;
402 p->type_val_to_struct_array[typdatum->value - 1] = typdatum; 591 p->type_val_to_struct[typdatum->value - 1] = typdatum;
403 } 592 }
404 593
405 return 0; 594 return 0;
@@ -477,9 +666,9 @@ static void hash_eval(struct hashtab *h, const char *hash_name)
477 struct hashtab_info info; 666 struct hashtab_info info;
478 667
479 hashtab_stat(h, &info); 668 hashtab_stat(h, &info);
480 pr_debug("SELinux: %s: %d entries and %d/%d buckets used, " 669 pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d\n",
481 "longest chain length %d\n", hash_name, h->nel, 670 hash_name, h->nel, info.slots_used, h->size,
482 info.slots_used, h->size, info.max_chain_len); 671 info.max_chain_len);
483} 672}
484 673
485static void symtab_hash_eval(struct symtab *s) 674static void symtab_hash_eval(struct symtab *s)
@@ -541,10 +730,10 @@ static int policydb_index(struct policydb *p)
541 if (!p->user_val_to_struct) 730 if (!p->user_val_to_struct)
542 return -ENOMEM; 731 return -ENOMEM;
543 732
544 p->type_val_to_struct_array = kvcalloc(p->p_types.nprim, 733 p->type_val_to_struct = kvcalloc(p->p_types.nprim,
545 sizeof(*p->type_val_to_struct_array), 734 sizeof(*p->type_val_to_struct),
546 GFP_KERNEL); 735 GFP_KERNEL);
547 if (!p->type_val_to_struct_array) 736 if (!p->type_val_to_struct)
548 return -ENOMEM; 737 return -ENOMEM;
549 738
550 rc = cond_init_bool_indexes(p); 739 rc = cond_init_bool_indexes(p);
@@ -568,193 +757,6 @@ out:
568} 757}
569 758
570/* 759/*
571 * The following *_destroy functions are used to
572 * free any memory allocated for each kind of
573 * symbol data in the policy database.
574 */
575
576static int perm_destroy(void *key, void *datum, void *p)
577{
578 kfree(key);
579 kfree(datum);
580 return 0;
581}
582
583static int common_destroy(void *key, void *datum, void *p)
584{
585 struct common_datum *comdatum;
586
587 kfree(key);
588 if (datum) {
589 comdatum = datum;
590 hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
591 hashtab_destroy(comdatum->permissions.table);
592 }
593 kfree(datum);
594 return 0;
595}
596
597static void constraint_expr_destroy(struct constraint_expr *expr)
598{
599 if (expr) {
600 ebitmap_destroy(&expr->names);
601 if (expr->type_names) {
602 ebitmap_destroy(&expr->type_names->types);
603 ebitmap_destroy(&expr->type_names->negset);
604 kfree(expr->type_names);
605 }
606 kfree(expr);
607 }
608}
609
610static int cls_destroy(void *key, void *datum, void *p)
611{
612 struct class_datum *cladatum;
613 struct constraint_node *constraint, *ctemp;
614 struct constraint_expr *e, *etmp;
615
616 kfree(key);
617 if (datum) {
618 cladatum = datum;
619 hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
620 hashtab_destroy(cladatum->permissions.table);
621 constraint = cladatum->constraints;
622 while (constraint) {
623 e = constraint->expr;
624 while (e) {
625 etmp = e;
626 e = e->next;
627 constraint_expr_destroy(etmp);
628 }
629 ctemp = constraint;
630 constraint = constraint->next;
631 kfree(ctemp);
632 }
633
634 constraint = cladatum->validatetrans;
635 while (constraint) {
636 e = constraint->expr;
637 while (e) {
638 etmp = e;
639 e = e->next;
640 constraint_expr_destroy(etmp);
641 }
642 ctemp = constraint;
643 constraint = constraint->next;
644 kfree(ctemp);
645 }
646 kfree(cladatum->comkey);
647 }
648 kfree(datum);
649 return 0;
650}
651
652static int role_destroy(void *key, void *datum, void *p)
653{
654 struct role_datum *role;
655
656 kfree(key);
657 if (datum) {
658 role = datum;
659 ebitmap_destroy(&role->dominates);
660 ebitmap_destroy(&role->types);
661 }
662 kfree(datum);
663 return 0;
664}
665
666static int type_destroy(void *key, void *datum, void *p)
667{
668 kfree(key);
669 kfree(datum);
670 return 0;
671}
672
673static int user_destroy(void *key, void *datum, void *p)
674{
675 struct user_datum *usrdatum;
676
677 kfree(key);
678 if (datum) {
679 usrdatum = datum;
680 ebitmap_destroy(&usrdatum->roles);
681 ebitmap_destroy(&usrdatum->range.level[0].cat);
682 ebitmap_destroy(&usrdatum->range.level[1].cat);
683 ebitmap_destroy(&usrdatum->dfltlevel.cat);
684 }
685 kfree(datum);
686 return 0;
687}
688
689static int sens_destroy(void *key, void *datum, void *p)
690{
691 struct level_datum *levdatum;
692
693 kfree(key);
694 if (datum) {
695 levdatum = datum;
696 if (levdatum->level)
697 ebitmap_destroy(&levdatum->level->cat);
698 kfree(levdatum->level);
699 }
700 kfree(datum);
701 return 0;
702}
703
704static int cat_destroy(void *key, void *datum, void *p)
705{
706 kfree(key);
707 kfree(datum);
708 return 0;
709}
710
711static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
712{
713 common_destroy,
714 cls_destroy,
715 role_destroy,
716 type_destroy,
717 user_destroy,
718 cond_destroy_bool,
719 sens_destroy,
720 cat_destroy,
721};
722
723static int filenametr_destroy(void *key, void *datum, void *p)
724{
725 struct filename_trans *ft = key;
726 kfree(ft->name);
727 kfree(key);
728 kfree(datum);
729 cond_resched();
730 return 0;
731}
732
733static int range_tr_destroy(void *key, void *datum, void *p)
734{
735 struct mls_range *rt = datum;
736 kfree(key);
737 ebitmap_destroy(&rt->level[0].cat);
738 ebitmap_destroy(&rt->level[1].cat);
739 kfree(datum);
740 cond_resched();
741 return 0;
742}
743
744static void ocontext_destroy(struct ocontext *c, int i)
745{
746 if (!c)
747 return;
748
749 context_destroy(&c->context[0]);
750 context_destroy(&c->context[1]);
751 if (i == OCON_ISID || i == OCON_FS ||
752 i == OCON_NETIF || i == OCON_FSUSE)
753 kfree(c->u.name);
754 kfree(c);
755}
756
757/*
758 * Free any memory allocated by a policy database structure. 760 * Free any memory allocated by a policy database structure.
759 */ 761 */
760void policydb_destroy(struct policydb *p) 762void policydb_destroy(struct policydb *p)
@@ -777,7 +779,7 @@ void policydb_destroy(struct policydb *p)
777 kfree(p->class_val_to_struct); 779 kfree(p->class_val_to_struct);
778 kfree(p->role_val_to_struct); 780 kfree(p->role_val_to_struct);
779 kfree(p->user_val_to_struct); 781 kfree(p->user_val_to_struct);
780 kvfree(p->type_val_to_struct_array); 782 kvfree(p->type_val_to_struct);
781 783
782 avtab_destroy(&p->te_avtab); 784 avtab_destroy(&p->te_avtab);
783 785
@@ -1722,7 +1724,7 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap)
1722 return -EINVAL; 1724 return -EINVAL;
1723 } 1725 }
1724 1726
1725 upper = p->type_val_to_struct_array[upper->bounds - 1]; 1727 upper = p->type_val_to_struct[upper->bounds - 1];
1726 BUG_ON(!upper); 1728 BUG_ON(!upper);
1727 1729
1728 if (upper->attribute) { 1730 if (upper->attribute) {
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index fcc6366b447f..162d0e79b85b 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -253,7 +253,7 @@ struct policydb {
253 struct class_datum **class_val_to_struct; 253 struct class_datum **class_val_to_struct;
254 struct role_datum **role_val_to_struct; 254 struct role_datum **role_val_to_struct;
255 struct user_datum **user_val_to_struct; 255 struct user_datum **user_val_to_struct;
256 struct type_datum **type_val_to_struct_array; 256 struct type_datum **type_val_to_struct;
257 257
258 /* type enforcement access vectors and transitions */ 258 /* type enforcement access vectors and transitions */
259 struct avtab te_avtab; 259 struct avtab te_avtab;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index d61563a3695e..3a29e7c24ba9 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -542,13 +542,13 @@ static void type_attribute_bounds_av(struct policydb *policydb,
542 struct type_datum *target; 542 struct type_datum *target;
543 u32 masked = 0; 543 u32 masked = 0;
544 544
545 source = policydb->type_val_to_struct_array[scontext->type - 1]; 545 source = policydb->type_val_to_struct[scontext->type - 1];
546 BUG_ON(!source); 546 BUG_ON(!source);
547 547
548 if (!source->bounds) 548 if (!source->bounds)
549 return; 549 return;
550 550
551 target = policydb->type_val_to_struct_array[tcontext->type - 1]; 551 target = policydb->type_val_to_struct[tcontext->type - 1];
552 BUG_ON(!target); 552 BUG_ON(!target);
553 553
554 memset(&lo_avd, 0, sizeof(lo_avd)); 554 memset(&lo_avd, 0, sizeof(lo_avd));
@@ -891,7 +891,7 @@ int security_bounded_transition(struct selinux_state *state,
891 891
892 index = new_context->type; 892 index = new_context->type;
893 while (true) { 893 while (true) {
894 type = policydb->type_val_to_struct_array[index - 1]; 894 type = policydb->type_val_to_struct[index - 1];
895 BUG_ON(!type); 895 BUG_ON(!type);
896 896
897 /* not bounded anymore */ 897 /* not bounded anymore */
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 1f0a6eaa2d6a..7d49994e8d5f 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -12,7 +12,7 @@
12#include <linux/slab.h> 12#include <linux/slab.h>
13#include <linux/sched.h> 13#include <linux/sched.h>
14#include <linux/spinlock.h> 14#include <linux/spinlock.h>
15#include <linux/atomic.h> 15#include <asm/barrier.h>
16#include "flask.h" 16#include "flask.h"
17#include "security.h" 17#include "security.h"
18#include "sidtab.h" 18#include "sidtab.h"
@@ -23,14 +23,14 @@ int sidtab_init(struct sidtab *s)
23 23
24 memset(s->roots, 0, sizeof(s->roots)); 24 memset(s->roots, 0, sizeof(s->roots));
25 25
26 /* max count is SIDTAB_MAX so valid index is always < SIDTAB_MAX */
26 for (i = 0; i < SIDTAB_RCACHE_SIZE; i++) 27 for (i = 0; i < SIDTAB_RCACHE_SIZE; i++)
27 atomic_set(&s->rcache[i], -1); 28 s->rcache[i] = SIDTAB_MAX;
28 29
29 for (i = 0; i < SECINITSID_NUM; i++) 30 for (i = 0; i < SECINITSID_NUM; i++)
30 s->isids[i].set = 0; 31 s->isids[i].set = 0;
31 32
32 atomic_set(&s->count, 0); 33 s->count = 0;
33
34 s->convert = NULL; 34 s->convert = NULL;
35 35
36 spin_lock_init(&s->lock); 36 spin_lock_init(&s->lock);
@@ -130,14 +130,12 @@ static struct context *sidtab_do_lookup(struct sidtab *s, u32 index, int alloc)
130 130
131static struct context *sidtab_lookup(struct sidtab *s, u32 index) 131static struct context *sidtab_lookup(struct sidtab *s, u32 index)
132{ 132{
133 u32 count = (u32)atomic_read(&s->count); 133 /* read entries only after reading count */
134 u32 count = smp_load_acquire(&s->count);
134 135
135 if (index >= count) 136 if (index >= count)
136 return NULL; 137 return NULL;
137 138
138 /* read entries after reading count */
139 smp_rmb();
140
141 return sidtab_do_lookup(s, index, 0); 139 return sidtab_do_lookup(s, index, 0);
142} 140}
143 141
@@ -210,10 +208,10 @@ static int sidtab_find_context(union sidtab_entry_inner entry,
210static void sidtab_rcache_update(struct sidtab *s, u32 index, u32 pos) 208static void sidtab_rcache_update(struct sidtab *s, u32 index, u32 pos)
211{ 209{
212 while (pos > 0) { 210 while (pos > 0) {
213 atomic_set(&s->rcache[pos], atomic_read(&s->rcache[pos - 1])); 211 WRITE_ONCE(s->rcache[pos], READ_ONCE(s->rcache[pos - 1]));
214 --pos; 212 --pos;
215 } 213 }
216 atomic_set(&s->rcache[0], (int)index); 214 WRITE_ONCE(s->rcache[0], index);
217} 215}
218 216
219static void sidtab_rcache_push(struct sidtab *s, u32 index) 217static void sidtab_rcache_push(struct sidtab *s, u32 index)
@@ -227,14 +225,14 @@ static int sidtab_rcache_search(struct sidtab *s, struct context *context,
227 u32 i; 225 u32 i;
228 226
229 for (i = 0; i < SIDTAB_RCACHE_SIZE; i++) { 227 for (i = 0; i < SIDTAB_RCACHE_SIZE; i++) {
230 int v = atomic_read(&s->rcache[i]); 228 u32 v = READ_ONCE(s->rcache[i]);
231 229
232 if (v < 0) 230 if (v >= SIDTAB_MAX)
233 continue; 231 continue;
234 232
235 if (context_cmp(sidtab_do_lookup(s, (u32)v, 0), context)) { 233 if (context_cmp(sidtab_do_lookup(s, v, 0), context)) {
236 sidtab_rcache_update(s, (u32)v, i); 234 sidtab_rcache_update(s, v, i);
237 *index = (u32)v; 235 *index = v;
238 return 0; 236 return 0;
239 } 237 }
240 } 238 }
@@ -245,8 +243,7 @@ static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
245 u32 *index) 243 u32 *index)
246{ 244{
247 unsigned long flags; 245 unsigned long flags;
248 u32 count = (u32)atomic_read(&s->count); 246 u32 count, count_locked, level, pos;
249 u32 count_locked, level, pos;
250 struct sidtab_convert_params *convert; 247 struct sidtab_convert_params *convert;
251 struct context *dst, *dst_convert; 248 struct context *dst, *dst_convert;
252 int rc; 249 int rc;
@@ -255,11 +252,10 @@ static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
255 if (rc == 0) 252 if (rc == 0)
256 return 0; 253 return 0;
257 254
255 /* read entries only after reading count */
256 count = smp_load_acquire(&s->count);
258 level = sidtab_level_from_count(count); 257 level = sidtab_level_from_count(count);
259 258
260 /* read entries after reading count */
261 smp_rmb();
262
263 pos = 0; 259 pos = 0;
264 rc = sidtab_find_context(s->roots[level], &pos, count, level, 260 rc = sidtab_find_context(s->roots[level], &pos, count, level,
265 context, index); 261 context, index);
@@ -272,7 +268,7 @@ static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
272 spin_lock_irqsave(&s->lock, flags); 268 spin_lock_irqsave(&s->lock, flags);
273 269
274 convert = s->convert; 270 convert = s->convert;
275 count_locked = (u32)atomic_read(&s->count); 271 count_locked = s->count;
276 level = sidtab_level_from_count(count_locked); 272 level = sidtab_level_from_count(count_locked);
277 273
278 /* if count has changed before we acquired the lock, then catch up */ 274 /* if count has changed before we acquired the lock, then catch up */
@@ -320,7 +316,7 @@ static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
320 } 316 }
321 317
322 /* at this point we know the insert won't fail */ 318 /* at this point we know the insert won't fail */
323 atomic_set(&convert->target->count, count + 1); 319 convert->target->count = count + 1;
324 } 320 }
325 321
326 if (context->len) 322 if (context->len)
@@ -331,9 +327,7 @@ static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
331 *index = count; 327 *index = count;
332 328
333 /* write entries before writing new count */ 329 /* write entries before writing new count */
334 smp_wmb(); 330 smp_store_release(&s->count, count + 1);
335
336 atomic_set(&s->count, count + 1);
337 331
338 rc = 0; 332 rc = 0;
339out_unlock: 333out_unlock:
@@ -423,7 +417,7 @@ int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params)
423 return -EBUSY; 417 return -EBUSY;
424 } 418 }
425 419
426 count = (u32)atomic_read(&s->count); 420 count = s->count;
427 level = sidtab_level_from_count(count); 421 level = sidtab_level_from_count(count);
428 422
429 /* allocate last leaf in the new sidtab (to avoid race with 423 /* allocate last leaf in the new sidtab (to avoid race with
@@ -436,7 +430,7 @@ int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params)
436 } 430 }
437 431
438 /* set count in case no new entries are added during conversion */ 432 /* set count in case no new entries are added during conversion */
439 atomic_set(&params->target->count, count); 433 params->target->count = count;
440 434
441 /* enable live convert of new entries */ 435 /* enable live convert of new entries */
442 s->convert = params; 436 s->convert = params;
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
index bbd5c0d1f3bd..1f4763141aa1 100644
--- a/security/selinux/ss/sidtab.h
+++ b/security/selinux/ss/sidtab.h
@@ -40,8 +40,8 @@ union sidtab_entry_inner {
40#define SIDTAB_LEAF_ENTRIES \ 40#define SIDTAB_LEAF_ENTRIES \
41 (SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry_leaf)) 41 (SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry_leaf))
42 42
43#define SIDTAB_MAX_BITS 31 /* limited to INT_MAX due to atomic_t range */ 43#define SIDTAB_MAX_BITS 32
44#define SIDTAB_MAX (((u32)1 << SIDTAB_MAX_BITS) - 1) 44#define SIDTAB_MAX U32_MAX
45/* ensure enough tree levels for SIDTAB_MAX entries */ 45/* ensure enough tree levels for SIDTAB_MAX entries */
46#define SIDTAB_MAX_LEVEL \ 46#define SIDTAB_MAX_LEVEL \
47 DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \ 47 DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \
@@ -69,13 +69,22 @@ struct sidtab_convert_params {
69#define SIDTAB_RCACHE_SIZE 3 69#define SIDTAB_RCACHE_SIZE 3
70 70
71struct sidtab { 71struct sidtab {
72 /*
73 * lock-free read access only for as many items as a prior read of
74 * 'count'
75 */
72 union sidtab_entry_inner roots[SIDTAB_MAX_LEVEL + 1]; 76 union sidtab_entry_inner roots[SIDTAB_MAX_LEVEL + 1];
73 atomic_t count; 77 /*
78 * access atomically via {READ|WRITE}_ONCE(); only increment under
79 * spinlock
80 */
81 u32 count;
82 /* access only under spinlock */
74 struct sidtab_convert_params *convert; 83 struct sidtab_convert_params *convert;
75 spinlock_t lock; 84 spinlock_t lock;
76 85
77 /* reverse lookup cache */ 86 /* reverse lookup cache - access atomically via {READ|WRITE}_ONCE() */
78 atomic_t rcache[SIDTAB_RCACHE_SIZE]; 87 u32 rcache[SIDTAB_RCACHE_SIZE];
79 88
80 /* index == SID - 1 (no entry for SECSID_NULL) */ 89 /* index == SID - 1 (no entry for SECSID_NULL) */
81 struct sidtab_isid_entry isids[SECINITSID_NUM]; 90 struct sidtab_isid_entry isids[SECINITSID_NUM];