Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+596 -500
+12 -3
fs/notify/dnotify/dnotify.c
··· 13 13 #include <linux/sched/signal.h> 14 14 #include <linux/dnotify.h> 15 15 #include <linux/init.h> 16 + #include <linux/security.h> 16 17 #include <linux/spinlock.h> 17 18 #include <linux/slab.h> 18 19 #include <linux/fdtable.h> ··· 280 279 goto out_err; 281 280 } 282 281 282 + /* 283 + * convert the userspace DN_* "arg" to the internal FS_* 284 + * defined in fsnotify 285 + */ 286 + mask = convert_arg(arg); 287 + 288 + error = security_path_notify(&filp->f_path, mask, 289 + FSNOTIFY_OBJ_TYPE_INODE); 290 + if (error) 291 + goto out_err; 292 + 283 293 /* expect most fcntl to add new rather than augment old */ 284 294 dn = kmem_cache_alloc(dnotify_struct_cache, GFP_KERNEL); 285 295 if (!dn) { ··· 304 292 error = -ENOMEM; 305 293 goto out_err; 306 294 } 307 - 308 - /* convert the userspace DN_* "arg" to the internal FS_* defines in fsnotify */ 309 - mask = convert_arg(arg); 310 295 311 296 /* set up the new_fsn_mark and new_dn_mark */ 312 297 new_fsn_mark = &new_dn_mark->fsn_mark;
+17 -2
fs/notify/fanotify/fanotify_user.c
··· 528 528 }; 529 529 530 530 static 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 534 int ret; 534 535 ··· 568 567 569 568 /* you can only watch an inode if you have read permissions on it */ 570 569 ret = inode_permission(path->dentry->d_inode, MAY_READ); 570 + if (ret) { 571 + path_put(path); 572 + goto out; 573 + } 574 + 575 + ret = security_path_notify(path, mask, obj_type); 571 576 if (ret) 572 577 path_put(path); 578 + 573 579 out: 574 580 return ret; 575 581 } ··· 955 947 __kernel_fsid_t __fsid, *fsid = NULL; 956 948 u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; 957 949 unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; 950 + unsigned int obj_type; 958 951 int ret; 959 952 960 953 pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n", ··· 970 961 971 962 switch (mark_type) { 972 963 case FAN_MARK_INODE: 964 + obj_type = FSNOTIFY_OBJ_TYPE_INODE; 965 + break; 973 966 case FAN_MARK_MOUNT: 967 + obj_type = FSNOTIFY_OBJ_TYPE_VFSMOUNT; 968 + break; 974 969 case FAN_MARK_FILESYSTEM: 970 + obj_type = FSNOTIFY_OBJ_TYPE_SB; 975 971 break; 976 972 default: 977 973 return -EINVAL; ··· 1044 1030 goto fput_and_out; 1045 1031 } 1046 1032 1047 - ret = fanotify_find_path(dfd, pathname, &path, flags); 1033 + ret = fanotify_find_path(dfd, pathname, &path, flags, 1034 + (mask & ALL_FSNOTIFY_EVENTS), obj_type); 1048 1035 if (ret) 1049 1036 goto fput_and_out; 1050 1037
+12 -2
fs/notify/inotify/inotify_user.c
··· 30 30 #include <linux/poll.h> 31 31 #include <linux/wait.h> 32 32 #include <linux/memcontrol.h> 33 + #include <linux/security.h> 33 34 34 35 #include "inotify.h" 35 36 #include "../fdinfo.h" ··· 332 331 /* 333 332 * find_inode - resolve a user-given path to a specific inode 334 333 */ 335 - static int inotify_find_inode(const char __user *dirname, struct path *path, unsigned flags) 334 + static int inotify_find_inode(const char __user *dirname, struct path *path, 335 + unsigned int flags, __u64 mask) 336 336 { 337 337 int error; 338 338 ··· 342 340 return error; 343 341 /* you can only watch an inode if you have read permissions on it */ 344 342 error = inode_permission(path->dentry->d_inode, MAY_READ); 343 + if (error) { 344 + path_put(path); 345 + return error; 346 + } 347 + error = security_path_notify(path, mask, 348 + FSNOTIFY_OBJ_TYPE_INODE); 345 349 if (error) 346 350 path_put(path); 351 + 347 352 return error; 348 353 } 349 354 ··· 742 733 if (mask & IN_ONLYDIR) 743 734 flags |= LOOKUP_DIRECTORY; 744 735 745 - ret = inotify_find_inode(pathname, &path, flags); 736 + ret = inotify_find_inode(pathname, &path, flags, 737 + (mask & IN_ALL_EVENTS)); 746 738 if (ret) 747 739 goto fput_and_out; 748 740
-1
include/linux/cred.h
··· 386 386 #define current_fsgid() (current_cred_xxx(fsgid)) 387 387 #define current_cap() (current_cred_xxx(cap_effective)) 388 388 #define current_user() (current_cred_xxx(user)) 389 - #define current_security() (current_cred_xxx(security)) 390 389 391 390 extern struct user_namespace init_user_ns; 392 391 #ifdef CONFIG_USER_NS
+8 -1
include/linux/lsm_hooks.h
··· 339 339 * Check for permission to change root directory. 340 340 * @path contains the path structure. 341 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 345 * @inode_readlink: 343 346 * Check the permission to read the symbolic link. 344 347 * @dentry contains the dentry structure for the file link. ··· 1538 1535 int (*path_chown)(const struct path *path, kuid_t uid, kgid_t gid); 1539 1536 int (*path_chroot)(const struct path *path); 1540 1537 #endif 1541 - 1538 + /* Needed for inode based security check */ 1539 + int (*path_notify)(const struct path *path, u64 mask, 1540 + unsigned int obj_type); 1542 1541 int (*inode_alloc_security)(struct inode *inode); 1543 1542 void (*inode_free_security)(struct inode *inode); 1544 1543 int (*inode_init_security)(struct inode *inode, struct inode *dir, ··· 1865 1860 struct hlist_head path_chown; 1866 1861 struct hlist_head path_chroot; 1867 1862 #endif 1863 + /* Needed for inode based modules as well */ 1864 + struct hlist_head path_notify; 1868 1865 struct hlist_head inode_alloc_security; 1869 1866 struct hlist_head inode_free_security; 1870 1867 struct hlist_head inode_init_security;
+8 -2
include/linux/security.h
··· 259 259 struct qstr *name, 260 260 const struct cred *old, 261 261 struct cred *new); 262 - 262 + int security_path_notify(const struct path *path, u64 mask, 263 + unsigned int obj_type); 263 264 int security_inode_alloc(struct inode *inode); 264 265 void security_inode_free(struct inode *inode); 265 266 int security_inode_init_security(struct inode *inode, struct inode *dir, ··· 388 387 int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); 389 388 int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); 390 389 void security_release_secctx(char *secdata, u32 seclen); 391 - 392 390 void security_inode_invalidate_secctx(struct inode *inode); 393 391 int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); 394 392 int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); ··· 617 617 618 618 static inline int security_move_mount(const struct path *from_path, 619 619 const struct path *to_path) 620 + { 621 + return 0; 622 + } 623 + 624 + static inline int security_path_notify(const struct path *path, u64 mask, 625 + unsigned int obj_type) 620 626 { 621 627 return 0; 622 628 }
+6
security/security.c
··· 870 870 return call_int_hook(move_mount, 0, from_path, to_path); 871 871 } 872 872 873 + int 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 + 873 879 int security_inode_alloc(struct inode *inode) 874 880 { 875 881 int rc = lsm_inode_alloc(inode);
+48 -1
security/selinux/hooks.c
··· 89 89 #include <linux/kernfs.h> 90 90 #include <linux/stringhash.h> /* for hashlen_string() */ 91 91 #include <uapi/linux/mount.h> 92 + #include <linux/fsnotify.h> 93 + #include <linux/fanotify.h> 92 94 93 95 #include "avc.h" 94 96 #include "objsec.h" ··· 3277 3275 return -EACCES; 3278 3276 } 3279 3277 3278 + static int selinux_path_notify(const struct path *path, u64 mask, 3279 + unsigned int obj_type) 3280 + { 3281 + int ret; 3282 + u32 perm; 3283 + 3284 + struct common_audit_data ad; 3285 + 3286 + ad.type = LSM_AUDIT_DATA_PATH; 3287 + ad.u.path = *path; 3288 + 3289 + /* 3290 + * Set permission needed based on the type of mark being set. 3291 + * Performs an additional check for sb watches. 3292 + */ 3293 + switch (obj_type) { 3294 + case FSNOTIFY_OBJ_TYPE_VFSMOUNT: 3295 + perm = FILE__WATCH_MOUNT; 3296 + break; 3297 + case FSNOTIFY_OBJ_TYPE_SB: 3298 + perm = FILE__WATCH_SB; 3299 + ret = superblock_has_perm(current_cred(), path->dentry->d_sb, 3300 + FILESYSTEM__WATCH, &ad); 3301 + if (ret) 3302 + return ret; 3303 + break; 3304 + case FSNOTIFY_OBJ_TYPE_INODE: 3305 + perm = FILE__WATCH; 3306 + break; 3307 + default: 3308 + return -EINVAL; 3309 + } 3310 + 3311 + /* blocking watches require the file:watch_with_perm permission */ 3312 + if (mask & (ALL_FSNOTIFY_PERM_EVENTS)) 3313 + perm |= FILE__WATCH_WITH_PERM; 3314 + 3315 + /* watches on read-like events need the file:watch_reads permission */ 3316 + if (mask & (FS_ACCESS | FS_ACCESS_PERM | FS_CLOSE_NOWRITE)) 3317 + perm |= FILE__WATCH_READS; 3318 + 3319 + return path_has_perm(current_cred(), path, perm); 3320 + } 3321 + 3280 3322 /* 3281 3323 * Copy the inode security context value to the user. 3282 3324 * ··· 3449 3403 static int selinux_kernfs_init_security(struct kernfs_node *kn_dir, 3450 3404 struct kernfs_node *kn) 3451 3405 { 3452 - const struct task_security_struct *tsec = current_security(); 3406 + const struct task_security_struct *tsec = selinux_cred(current_cred()); 3453 3407 u32 parent_sid, newsid, clen; 3454 3408 int rc; 3455 3409 char *context; ··· 6864 6818 LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid), 6865 6819 LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), 6866 6820 LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), 6821 + LSM_HOOK_INIT(path_notify, selinux_path_notify), 6867 6822 6868 6823 LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security), 6869 6824
+3 -2
security/selinux/include/classmap.h
··· 7 7 8 8 #define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \ 9 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 13 #define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \ 13 14 "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \ ··· 61 60 { "filesystem", 62 61 { "mount", "remount", "unmount", "getattr", 63 62 "relabelfrom", "relabelto", "associate", "quotamod", 64 - "quotaget", NULL } }, 63 + "quotaget", "watch", NULL } }, 65 64 { "file", 66 65 { COMMON_FILE_PERMS, 67 66 "execute_no_trans", "entrypoint", NULL } },
+10 -10
security/selinux/include/objsec.h
··· 37 37 u32 sockcreate_sid; /* fscreate SID */ 38 38 }; 39 39 40 - /* 41 - * get the subjective security ID of the current task 42 - */ 43 - static inline u32 current_sid(void) 44 - { 45 - const struct task_security_struct *tsec = current_security(); 46 - 47 - return tsec->sid; 48 - } 49 - 50 40 enum label_initialized { 51 41 LABEL_INVALID, /* invalid or not initialized */ 52 42 LABEL_INITIALIZED, /* initialized */ ··· 173 183 const struct kern_ipc_perm *ipc) 174 184 { 175 185 return ipc->security + selinux_blob_sizes.lbs_ipc; 186 + } 187 + 188 + /* 189 + * get the subjective security ID of the current task 190 + */ 191 + static inline u32 current_sid(void) 192 + { 193 + const struct task_security_struct *tsec = selinux_cred(current_cred()); 194 + 195 + return tsec->sid; 176 196 } 177 197 178 198 #endif /* _SELINUX_OBJSEC_H_ */
+13 -18
security/selinux/netif.c
··· 132 132 */ 133 133 static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) 134 134 { 135 - int ret; 135 + int ret = 0; 136 136 struct sel_netif *netif; 137 - struct sel_netif *new = NULL; 137 + struct sel_netif *new; 138 138 struct net_device *dev; 139 139 140 140 /* NOTE: we always use init's network namespace since we don't ··· 151 151 netif = sel_netif_find(ns, ifindex); 152 152 if (netif != NULL) { 153 153 *sid = netif->nsec.sid; 154 - ret = 0; 155 154 goto out; 156 155 } 156 + 157 + ret = security_netif_sid(&selinux_state, dev->name, sid); 158 + if (ret != 0) 159 + goto out; 157 160 new = kzalloc(sizeof(*new), GFP_ATOMIC); 158 - if (new == NULL) { 159 - ret = -ENOMEM; 160 - goto out; 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); 161 167 } 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) 169 - goto out; 170 - *sid = new->nsec.sid; 171 168 172 169 out: 173 170 spin_unlock_bh(&sel_netif_lock); 174 171 dev_put(dev); 175 - if (unlikely(ret)) { 172 + if (unlikely(ret)) 176 173 pr_warn("SELinux: failure in %s(), unable to determine network interface label (%d)\n", 177 174 __func__, ifindex); 178 - kfree(new); 179 - } 180 175 return ret; 181 176 } 182 177
+14 -16
security/selinux/netnode.c
··· 189 189 */ 190 190 static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) 191 191 { 192 - int ret = -ENOMEM; 192 + int ret; 193 193 struct sel_netnode *node; 194 - struct sel_netnode *new = NULL; 194 + struct sel_netnode *new; 195 195 196 196 spin_lock_bh(&sel_netnode_lock); 197 197 node = sel_netnode_find(addr, family); ··· 200 200 spin_unlock_bh(&sel_netnode_lock); 201 201 return 0; 202 202 } 203 + 203 204 new = kzalloc(sizeof(*new), GFP_ATOMIC); 204 - if (new == NULL) 205 - goto out; 206 205 switch (family) { 207 206 case PF_INET: 208 207 ret = security_node_sid(&selinux_state, PF_INET, 209 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 211 break; 212 212 case PF_INET6: 213 213 ret = security_node_sid(&selinux_state, PF_INET6, 214 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 217 break; 217 218 default: 218 219 BUG(); 219 220 ret = -EINVAL; 220 221 } 221 - if (ret != 0) 222 - goto out; 222 + if (ret == 0 && new) { 223 + new->nsec.family = family; 224 + new->nsec.sid = *sid; 225 + sel_netnode_insert(new); 226 + } else 227 + kfree(new); 223 228 224 - new->nsec.family = family; 225 - new->nsec.sid = *sid; 226 - sel_netnode_insert(new); 227 - 228 - out: 229 229 spin_unlock_bh(&sel_netnode_lock); 230 - if (unlikely(ret)) { 230 + if (unlikely(ret)) 231 231 pr_warn("SELinux: failure in %s(), unable to determine network node label\n", 232 232 __func__); 233 - kfree(new); 234 - } 235 233 return ret; 236 234 } 237 235
+11 -13
security/selinux/netport.c
··· 137 137 */ 138 138 static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) 139 139 { 140 - int ret = -ENOMEM; 140 + int ret; 141 141 struct sel_netport *port; 142 - struct sel_netport *new = NULL; 142 + struct sel_netport *new; 143 143 144 144 spin_lock_bh(&sel_netport_lock); 145 145 port = sel_netport_find(protocol, pnum); ··· 148 148 spin_unlock_bh(&sel_netport_lock); 149 149 return 0; 150 150 } 151 - new = kzalloc(sizeof(*new), GFP_ATOMIC); 152 - if (new == NULL) 153 - goto out; 151 + 154 152 ret = security_port_sid(&selinux_state, protocol, pnum, sid); 155 153 if (ret != 0) 156 154 goto out; 157 - 158 - new->psec.port = pnum; 159 - new->psec.protocol = protocol; 160 - new->psec.sid = *sid; 161 - sel_netport_insert(new); 155 + new = kzalloc(sizeof(*new), GFP_ATOMIC); 156 + if (new) { 157 + new->psec.port = pnum; 158 + new->psec.protocol = protocol; 159 + new->psec.sid = *sid; 160 + sel_netport_insert(new); 161 + } 162 162 163 163 out: 164 164 spin_unlock_bh(&sel_netport_lock); 165 - if (unlikely(ret)) { 165 + if (unlikely(ret)) 166 166 pr_warn("SELinux: failure in %s(), unable to determine network port label\n", 167 167 __func__); 168 - kfree(new); 169 - } 170 168 return ret; 171 169 } 172 170
+395 -393
security/selinux/ss/policydb.c
··· 177 177 } 178 178 179 179 /* 180 - * Initialize the role table. 181 - */ 182 - static int roles_init(struct policydb *p) 183 - { 184 - char *key = NULL; 185 - int rc; 186 - struct role_datum *role; 187 - 188 - role = kzalloc(sizeof(*role), GFP_KERNEL); 189 - if (!role) 190 - return -ENOMEM; 191 - 192 - rc = -EINVAL; 193 - role->value = ++p->p_roles.nprim; 194 - if (role->value != OBJECT_R_VAL) 195 - goto out; 196 - 197 - rc = -ENOMEM; 198 - key = kstrdup(OBJECT_R, GFP_KERNEL); 199 - if (!key) 200 - goto out; 201 - 202 - rc = hashtab_insert(p->p_roles.table, key, role); 203 - if (rc) 204 - goto out; 205 - 206 - return 0; 207 - out: 208 - kfree(key); 209 - kfree(role); 210 - return rc; 211 - } 212 - 213 - static u32 filenametr_hash(struct hashtab *h, const void *k) 214 - { 215 - const struct filename_trans *ft = k; 216 - unsigned long hash; 217 - unsigned int byte_num; 218 - unsigned char focus; 219 - 220 - hash = ft->stype ^ ft->ttype ^ ft->tclass; 221 - 222 - byte_num = 0; 223 - while ((focus = ft->name[byte_num++])) 224 - hash = partial_name_hash(focus, hash); 225 - return hash & (h->size - 1); 226 - } 227 - 228 - static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2) 229 - { 230 - const struct filename_trans *ft1 = k1; 231 - const struct filename_trans *ft2 = k2; 232 - int v; 233 - 234 - v = ft1->stype - ft2->stype; 235 - if (v) 236 - return v; 237 - 238 - v = ft1->ttype - ft2->ttype; 239 - if (v) 240 - return v; 241 - 242 - v = ft1->tclass - ft2->tclass; 243 - if (v) 244 - return v; 245 - 246 - return strcmp(ft1->name, ft2->name); 247 - 248 - } 249 - 250 - static u32 rangetr_hash(struct hashtab *h, const void *k) 251 - { 252 - const struct range_trans *key = k; 253 - return (key->source_type + (key->target_type << 3) + 254 - (key->target_class << 5)) & (h->size - 1); 255 - } 256 - 257 - static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) 258 - { 259 - const struct range_trans *key1 = k1, *key2 = k2; 260 - int v; 261 - 262 - v = key1->source_type - key2->source_type; 263 - if (v) 264 - return v; 265 - 266 - v = key1->target_type - key2->target_type; 267 - if (v) 268 - return v; 269 - 270 - v = key1->target_class - key2->target_class; 271 - 272 - return v; 273 - } 274 - 275 - static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap); 276 - 277 - /* 278 - * Initialize a policy database structure. 279 - */ 280 - static int policydb_init(struct policydb *p) 281 - { 282 - int i, rc; 283 - 284 - memset(p, 0, sizeof(*p)); 285 - 286 - for (i = 0; i < SYM_NUM; i++) { 287 - rc = symtab_init(&p->symtab[i], symtab_sizes[i]); 288 - if (rc) 289 - goto out; 290 - } 291 - 292 - rc = avtab_init(&p->te_avtab); 293 - if (rc) 294 - goto out; 295 - 296 - rc = roles_init(p); 297 - if (rc) 298 - goto out; 299 - 300 - rc = cond_policydb_init(p); 301 - if (rc) 302 - goto out; 303 - 304 - p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); 305 - if (!p->filename_trans) { 306 - rc = -ENOMEM; 307 - goto out; 308 - } 309 - 310 - p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); 311 - if (!p->range_tr) { 312 - rc = -ENOMEM; 313 - goto out; 314 - } 315 - 316 - ebitmap_init(&p->filename_trans_ttypes); 317 - ebitmap_init(&p->policycaps); 318 - ebitmap_init(&p->permissive_map); 319 - 320 - return 0; 321 - out: 322 - hashtab_destroy(p->filename_trans); 323 - hashtab_destroy(p->range_tr); 324 - for (i = 0; i < SYM_NUM; i++) { 325 - hashtab_map(p->symtab[i].table, destroy_f[i], NULL); 326 - hashtab_destroy(p->symtab[i].table); 327 - } 328 - return rc; 329 - } 330 - 331 - /* 332 - * The following *_index functions are used to 333 - * define the val_to_name and val_to_struct arrays 334 - * in a policy database structure. The val_to_name 335 - * arrays are used when converting security context 336 - * structures into string representations. The 337 - * val_to_struct arrays are used when the attributes 338 - * of a class, role, or user are needed. 339 - */ 340 - 341 - static int common_index(void *key, void *datum, void *datap) 342 - { 343 - struct policydb *p; 344 - struct common_datum *comdatum; 345 - 346 - comdatum = datum; 347 - p = datap; 348 - if (!comdatum->value || comdatum->value > p->p_commons.nprim) 349 - return -EINVAL; 350 - 351 - p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1] = key; 352 - 353 - return 0; 354 - } 355 - 356 - static int class_index(void *key, void *datum, void *datap) 357 - { 358 - struct policydb *p; 359 - struct class_datum *cladatum; 360 - 361 - cladatum = datum; 362 - p = datap; 363 - if (!cladatum->value || cladatum->value > p->p_classes.nprim) 364 - return -EINVAL; 365 - 366 - p->sym_val_to_name[SYM_CLASSES][cladatum->value - 1] = key; 367 - p->class_val_to_struct[cladatum->value - 1] = cladatum; 368 - return 0; 369 - } 370 - 371 - static int role_index(void *key, void *datum, void *datap) 372 - { 373 - struct policydb *p; 374 - struct role_datum *role; 375 - 376 - role = datum; 377 - p = datap; 378 - if (!role->value 379 - || role->value > p->p_roles.nprim 380 - || role->bounds > p->p_roles.nprim) 381 - return -EINVAL; 382 - 383 - p->sym_val_to_name[SYM_ROLES][role->value - 1] = key; 384 - p->role_val_to_struct[role->value - 1] = role; 385 - return 0; 386 - } 387 - 388 - static int type_index(void *key, void *datum, void *datap) 389 - { 390 - struct policydb *p; 391 - struct type_datum *typdatum; 392 - 393 - typdatum = datum; 394 - p = datap; 395 - 396 - if (typdatum->primary) { 397 - if (!typdatum->value 398 - || typdatum->value > p->p_types.nprim 399 - || typdatum->bounds > p->p_types.nprim) 400 - return -EINVAL; 401 - p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key; 402 - p->type_val_to_struct_array[typdatum->value - 1] = typdatum; 403 - } 404 - 405 - return 0; 406 - } 407 - 408 - static int user_index(void *key, void *datum, void *datap) 409 - { 410 - struct policydb *p; 411 - struct user_datum *usrdatum; 412 - 413 - usrdatum = datum; 414 - p = datap; 415 - if (!usrdatum->value 416 - || usrdatum->value > p->p_users.nprim 417 - || usrdatum->bounds > p->p_users.nprim) 418 - return -EINVAL; 419 - 420 - p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key; 421 - p->user_val_to_struct[usrdatum->value - 1] = usrdatum; 422 - return 0; 423 - } 424 - 425 - static int sens_index(void *key, void *datum, void *datap) 426 - { 427 - struct policydb *p; 428 - struct level_datum *levdatum; 429 - 430 - levdatum = datum; 431 - p = datap; 432 - 433 - if (!levdatum->isalias) { 434 - if (!levdatum->level->sens || 435 - levdatum->level->sens > p->p_levels.nprim) 436 - return -EINVAL; 437 - 438 - p->sym_val_to_name[SYM_LEVELS][levdatum->level->sens - 1] = key; 439 - } 440 - 441 - return 0; 442 - } 443 - 444 - static int cat_index(void *key, void *datum, void *datap) 445 - { 446 - struct policydb *p; 447 - struct cat_datum *catdatum; 448 - 449 - catdatum = datum; 450 - p = datap; 451 - 452 - if (!catdatum->isalias) { 453 - if (!catdatum->value || catdatum->value > p->p_cats.nprim) 454 - return -EINVAL; 455 - 456 - p->sym_val_to_name[SYM_CATS][catdatum->value - 1] = key; 457 - } 458 - 459 - return 0; 460 - } 461 - 462 - static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = 463 - { 464 - common_index, 465 - class_index, 466 - role_index, 467 - type_index, 468 - user_index, 469 - cond_index_bool, 470 - sens_index, 471 - cat_index, 472 - }; 473 - 474 - #ifdef DEBUG_HASHES 475 - static void hash_eval(struct hashtab *h, const char *hash_name) 476 - { 477 - struct hashtab_info info; 478 - 479 - hashtab_stat(h, &info); 480 - pr_debug("SELinux: %s: %d entries and %d/%d buckets used, " 481 - "longest chain length %d\n", hash_name, h->nel, 482 - info.slots_used, h->size, info.max_chain_len); 483 - } 484 - 485 - static void symtab_hash_eval(struct symtab *s) 486 - { 487 - int i; 488 - 489 - for (i = 0; i < SYM_NUM; i++) 490 - hash_eval(s[i].table, symtab_name[i]); 491 - } 492 - 493 - #else 494 - static inline void hash_eval(struct hashtab *h, char *hash_name) 495 - { 496 - } 497 - #endif 498 - 499 - /* 500 - * Define the other val_to_name and val_to_struct arrays 501 - * in a policy database structure. 502 - * 503 - * Caller must clean up on failure. 504 - */ 505 - static int policydb_index(struct policydb *p) 506 - { 507 - int i, rc; 508 - 509 - if (p->mls_enabled) 510 - pr_debug("SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n", 511 - p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, 512 - p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim); 513 - else 514 - pr_debug("SELinux: %d users, %d roles, %d types, %d bools\n", 515 - p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, 516 - p->p_bools.nprim); 517 - 518 - pr_debug("SELinux: %d classes, %d rules\n", 519 - p->p_classes.nprim, p->te_avtab.nel); 520 - 521 - #ifdef DEBUG_HASHES 522 - avtab_hash_eval(&p->te_avtab, "rules"); 523 - symtab_hash_eval(p->symtab); 524 - #endif 525 - 526 - p->class_val_to_struct = kcalloc(p->p_classes.nprim, 527 - sizeof(*p->class_val_to_struct), 528 - GFP_KERNEL); 529 - if (!p->class_val_to_struct) 530 - return -ENOMEM; 531 - 532 - p->role_val_to_struct = kcalloc(p->p_roles.nprim, 533 - sizeof(*p->role_val_to_struct), 534 - GFP_KERNEL); 535 - if (!p->role_val_to_struct) 536 - return -ENOMEM; 537 - 538 - p->user_val_to_struct = kcalloc(p->p_users.nprim, 539 - sizeof(*p->user_val_to_struct), 540 - GFP_KERNEL); 541 - if (!p->user_val_to_struct) 542 - return -ENOMEM; 543 - 544 - p->type_val_to_struct_array = kvcalloc(p->p_types.nprim, 545 - sizeof(*p->type_val_to_struct_array), 546 - GFP_KERNEL); 547 - if (!p->type_val_to_struct_array) 548 - return -ENOMEM; 549 - 550 - rc = cond_init_bool_indexes(p); 551 - if (rc) 552 - goto out; 553 - 554 - for (i = 0; i < SYM_NUM; i++) { 555 - p->sym_val_to_name[i] = kvcalloc(p->symtab[i].nprim, 556 - sizeof(char *), 557 - GFP_KERNEL); 558 - if (!p->sym_val_to_name[i]) 559 - return -ENOMEM; 560 - 561 - rc = hashtab_map(p->symtab[i].table, index_f[i], p); 562 - if (rc) 563 - goto out; 564 - } 565 - rc = 0; 566 - out: 567 - return rc; 568 - } 569 - 570 - /* 571 180 * The following *_destroy functions are used to 572 181 * free any memory allocated for each kind of 573 182 * symbol data in the policy database. ··· 332 723 static int filenametr_destroy(void *key, void *datum, void *p) 333 724 { 334 725 struct filename_trans *ft = key; 726 + 335 727 kfree(ft->name); 336 728 kfree(key); 337 729 kfree(datum); ··· 343 733 static int range_tr_destroy(void *key, void *datum, void *p) 344 734 { 345 735 struct mls_range *rt = datum; 736 + 346 737 kfree(key); 347 738 ebitmap_destroy(&rt->level[0].cat); 348 739 ebitmap_destroy(&rt->level[1].cat); ··· 363 752 i == OCON_NETIF || i == OCON_FSUSE) 364 753 kfree(c->u.name); 365 754 kfree(c); 755 + } 756 + 757 + /* 758 + * Initialize the role table. 759 + */ 760 + static int roles_init(struct policydb *p) 761 + { 762 + char *key = NULL; 763 + int rc; 764 + struct role_datum *role; 765 + 766 + role = kzalloc(sizeof(*role), GFP_KERNEL); 767 + if (!role) 768 + return -ENOMEM; 769 + 770 + rc = -EINVAL; 771 + role->value = ++p->p_roles.nprim; 772 + if (role->value != OBJECT_R_VAL) 773 + goto out; 774 + 775 + rc = -ENOMEM; 776 + key = kstrdup(OBJECT_R, GFP_KERNEL); 777 + if (!key) 778 + goto out; 779 + 780 + rc = hashtab_insert(p->p_roles.table, key, role); 781 + if (rc) 782 + goto out; 783 + 784 + return 0; 785 + out: 786 + kfree(key); 787 + kfree(role); 788 + return rc; 789 + } 790 + 791 + static u32 filenametr_hash(struct hashtab *h, const void *k) 792 + { 793 + const struct filename_trans *ft = k; 794 + unsigned long hash; 795 + unsigned int byte_num; 796 + unsigned char focus; 797 + 798 + hash = ft->stype ^ ft->ttype ^ ft->tclass; 799 + 800 + byte_num = 0; 801 + while ((focus = ft->name[byte_num++])) 802 + hash = partial_name_hash(focus, hash); 803 + return hash & (h->size - 1); 804 + } 805 + 806 + static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2) 807 + { 808 + const struct filename_trans *ft1 = k1; 809 + const struct filename_trans *ft2 = k2; 810 + int v; 811 + 812 + v = ft1->stype - ft2->stype; 813 + if (v) 814 + return v; 815 + 816 + v = ft1->ttype - ft2->ttype; 817 + if (v) 818 + return v; 819 + 820 + v = ft1->tclass - ft2->tclass; 821 + if (v) 822 + return v; 823 + 824 + return strcmp(ft1->name, ft2->name); 825 + 826 + } 827 + 828 + static u32 rangetr_hash(struct hashtab *h, const void *k) 829 + { 830 + const struct range_trans *key = k; 831 + 832 + return (key->source_type + (key->target_type << 3) + 833 + (key->target_class << 5)) & (h->size - 1); 834 + } 835 + 836 + static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) 837 + { 838 + const struct range_trans *key1 = k1, *key2 = k2; 839 + int v; 840 + 841 + v = key1->source_type - key2->source_type; 842 + if (v) 843 + return v; 844 + 845 + v = key1->target_type - key2->target_type; 846 + if (v) 847 + return v; 848 + 849 + v = key1->target_class - key2->target_class; 850 + 851 + return v; 852 + } 853 + 854 + /* 855 + * Initialize a policy database structure. 856 + */ 857 + static int policydb_init(struct policydb *p) 858 + { 859 + int i, rc; 860 + 861 + memset(p, 0, sizeof(*p)); 862 + 863 + for (i = 0; i < SYM_NUM; i++) { 864 + rc = symtab_init(&p->symtab[i], symtab_sizes[i]); 865 + if (rc) 866 + goto out; 867 + } 868 + 869 + rc = avtab_init(&p->te_avtab); 870 + if (rc) 871 + goto out; 872 + 873 + rc = roles_init(p); 874 + if (rc) 875 + goto out; 876 + 877 + rc = cond_policydb_init(p); 878 + if (rc) 879 + goto out; 880 + 881 + p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, 882 + (1 << 10)); 883 + if (!p->filename_trans) { 884 + rc = -ENOMEM; 885 + goto out; 886 + } 887 + 888 + p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); 889 + if (!p->range_tr) { 890 + rc = -ENOMEM; 891 + goto out; 892 + } 893 + 894 + ebitmap_init(&p->filename_trans_ttypes); 895 + ebitmap_init(&p->policycaps); 896 + ebitmap_init(&p->permissive_map); 897 + 898 + return 0; 899 + out: 900 + hashtab_destroy(p->filename_trans); 901 + hashtab_destroy(p->range_tr); 902 + for (i = 0; i < SYM_NUM; i++) { 903 + hashtab_map(p->symtab[i].table, destroy_f[i], NULL); 904 + hashtab_destroy(p->symtab[i].table); 905 + } 906 + return rc; 907 + } 908 + 909 + /* 910 + * The following *_index functions are used to 911 + * define the val_to_name and val_to_struct arrays 912 + * in a policy database structure. The val_to_name 913 + * arrays are used when converting security context 914 + * structures into string representations. The 915 + * val_to_struct arrays are used when the attributes 916 + * of a class, role, or user are needed. 917 + */ 918 + 919 + static int common_index(void *key, void *datum, void *datap) 920 + { 921 + struct policydb *p; 922 + struct common_datum *comdatum; 923 + 924 + comdatum = datum; 925 + p = datap; 926 + if (!comdatum->value || comdatum->value > p->p_commons.nprim) 927 + return -EINVAL; 928 + 929 + p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1] = key; 930 + 931 + return 0; 932 + } 933 + 934 + static int class_index(void *key, void *datum, void *datap) 935 + { 936 + struct policydb *p; 937 + struct class_datum *cladatum; 938 + 939 + cladatum = datum; 940 + p = datap; 941 + if (!cladatum->value || cladatum->value > p->p_classes.nprim) 942 + return -EINVAL; 943 + 944 + p->sym_val_to_name[SYM_CLASSES][cladatum->value - 1] = key; 945 + p->class_val_to_struct[cladatum->value - 1] = cladatum; 946 + return 0; 947 + } 948 + 949 + static int role_index(void *key, void *datum, void *datap) 950 + { 951 + struct policydb *p; 952 + struct role_datum *role; 953 + 954 + role = datum; 955 + p = datap; 956 + if (!role->value 957 + || role->value > p->p_roles.nprim 958 + || role->bounds > p->p_roles.nprim) 959 + return -EINVAL; 960 + 961 + p->sym_val_to_name[SYM_ROLES][role->value - 1] = key; 962 + p->role_val_to_struct[role->value - 1] = role; 963 + return 0; 964 + } 965 + 966 + static int type_index(void *key, void *datum, void *datap) 967 + { 968 + struct policydb *p; 969 + struct type_datum *typdatum; 970 + 971 + typdatum = datum; 972 + p = datap; 973 + 974 + if (typdatum->primary) { 975 + if (!typdatum->value 976 + || typdatum->value > p->p_types.nprim 977 + || typdatum->bounds > p->p_types.nprim) 978 + return -EINVAL; 979 + p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key; 980 + p->type_val_to_struct[typdatum->value - 1] = typdatum; 981 + } 982 + 983 + return 0; 984 + } 985 + 986 + static int user_index(void *key, void *datum, void *datap) 987 + { 988 + struct policydb *p; 989 + struct user_datum *usrdatum; 990 + 991 + usrdatum = datum; 992 + p = datap; 993 + if (!usrdatum->value 994 + || usrdatum->value > p->p_users.nprim 995 + || usrdatum->bounds > p->p_users.nprim) 996 + return -EINVAL; 997 + 998 + p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key; 999 + p->user_val_to_struct[usrdatum->value - 1] = usrdatum; 1000 + return 0; 1001 + } 1002 + 1003 + static int sens_index(void *key, void *datum, void *datap) 1004 + { 1005 + struct policydb *p; 1006 + struct level_datum *levdatum; 1007 + 1008 + levdatum = datum; 1009 + p = datap; 1010 + 1011 + if (!levdatum->isalias) { 1012 + if (!levdatum->level->sens || 1013 + levdatum->level->sens > p->p_levels.nprim) 1014 + return -EINVAL; 1015 + 1016 + p->sym_val_to_name[SYM_LEVELS][levdatum->level->sens - 1] = key; 1017 + } 1018 + 1019 + return 0; 1020 + } 1021 + 1022 + static int cat_index(void *key, void *datum, void *datap) 1023 + { 1024 + struct policydb *p; 1025 + struct cat_datum *catdatum; 1026 + 1027 + catdatum = datum; 1028 + p = datap; 1029 + 1030 + if (!catdatum->isalias) { 1031 + if (!catdatum->value || catdatum->value > p->p_cats.nprim) 1032 + return -EINVAL; 1033 + 1034 + p->sym_val_to_name[SYM_CATS][catdatum->value - 1] = key; 1035 + } 1036 + 1037 + return 0; 1038 + } 1039 + 1040 + static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = 1041 + { 1042 + common_index, 1043 + class_index, 1044 + role_index, 1045 + type_index, 1046 + user_index, 1047 + cond_index_bool, 1048 + sens_index, 1049 + cat_index, 1050 + }; 1051 + 1052 + #ifdef DEBUG_HASHES 1053 + static void hash_eval(struct hashtab *h, const char *hash_name) 1054 + { 1055 + struct hashtab_info info; 1056 + 1057 + hashtab_stat(h, &info); 1058 + pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d\n", 1059 + hash_name, h->nel, info.slots_used, h->size, 1060 + info.max_chain_len); 1061 + } 1062 + 1063 + static void symtab_hash_eval(struct symtab *s) 1064 + { 1065 + int i; 1066 + 1067 + for (i = 0; i < SYM_NUM; i++) 1068 + hash_eval(s[i].table, symtab_name[i]); 1069 + } 1070 + 1071 + #else 1072 + static inline void hash_eval(struct hashtab *h, char *hash_name) 1073 + { 1074 + } 1075 + #endif 1076 + 1077 + /* 1078 + * Define the other val_to_name and val_to_struct arrays 1079 + * in a policy database structure. 1080 + * 1081 + * Caller must clean up on failure. 1082 + */ 1083 + static int policydb_index(struct policydb *p) 1084 + { 1085 + int i, rc; 1086 + 1087 + if (p->mls_enabled) 1088 + pr_debug("SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n", 1089 + p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, 1090 + p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim); 1091 + else 1092 + pr_debug("SELinux: %d users, %d roles, %d types, %d bools\n", 1093 + p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, 1094 + p->p_bools.nprim); 1095 + 1096 + pr_debug("SELinux: %d classes, %d rules\n", 1097 + p->p_classes.nprim, p->te_avtab.nel); 1098 + 1099 + #ifdef DEBUG_HASHES 1100 + avtab_hash_eval(&p->te_avtab, "rules"); 1101 + symtab_hash_eval(p->symtab); 1102 + #endif 1103 + 1104 + p->class_val_to_struct = kcalloc(p->p_classes.nprim, 1105 + sizeof(*p->class_val_to_struct), 1106 + GFP_KERNEL); 1107 + if (!p->class_val_to_struct) 1108 + return -ENOMEM; 1109 + 1110 + p->role_val_to_struct = kcalloc(p->p_roles.nprim, 1111 + sizeof(*p->role_val_to_struct), 1112 + GFP_KERNEL); 1113 + if (!p->role_val_to_struct) 1114 + return -ENOMEM; 1115 + 1116 + p->user_val_to_struct = kcalloc(p->p_users.nprim, 1117 + sizeof(*p->user_val_to_struct), 1118 + GFP_KERNEL); 1119 + if (!p->user_val_to_struct) 1120 + return -ENOMEM; 1121 + 1122 + p->type_val_to_struct = kvcalloc(p->p_types.nprim, 1123 + sizeof(*p->type_val_to_struct), 1124 + GFP_KERNEL); 1125 + if (!p->type_val_to_struct) 1126 + return -ENOMEM; 1127 + 1128 + rc = cond_init_bool_indexes(p); 1129 + if (rc) 1130 + goto out; 1131 + 1132 + for (i = 0; i < SYM_NUM; i++) { 1133 + p->sym_val_to_name[i] = kvcalloc(p->symtab[i].nprim, 1134 + sizeof(char *), 1135 + GFP_KERNEL); 1136 + if (!p->sym_val_to_name[i]) 1137 + return -ENOMEM; 1138 + 1139 + rc = hashtab_map(p->symtab[i].table, index_f[i], p); 1140 + if (rc) 1141 + goto out; 1142 + } 1143 + rc = 0; 1144 + out: 1145 + return rc; 366 1146 } 367 1147 368 1148 /* ··· 779 777 kfree(p->class_val_to_struct); 780 778 kfree(p->role_val_to_struct); 781 779 kfree(p->user_val_to_struct); 782 - kvfree(p->type_val_to_struct_array); 780 + kvfree(p->type_val_to_struct); 783 781 784 782 avtab_destroy(&p->te_avtab); 785 783 ··· 1724 1722 return -EINVAL; 1725 1723 } 1726 1724 1727 - upper = p->type_val_to_struct_array[upper->bounds - 1]; 1725 + upper = p->type_val_to_struct[upper->bounds - 1]; 1728 1726 BUG_ON(!upper); 1729 1727 1730 1728 if (upper->attribute) {
+1 -1
security/selinux/ss/policydb.h
··· 253 253 struct class_datum **class_val_to_struct; 254 254 struct role_datum **role_val_to_struct; 255 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 258 /* type enforcement access vectors and transitions */ 259 259 struct avtab te_avtab;
+3 -3
security/selinux/ss/services.c
··· 542 542 struct type_datum *target; 543 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 546 BUG_ON(!source); 547 547 548 548 if (!source->bounds) 549 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 552 BUG_ON(!target); 553 553 554 554 memset(&lo_avd, 0, sizeof(lo_avd)); ··· 891 891 892 892 index = new_context->type; 893 893 while (true) { 894 - type = policydb->type_val_to_struct_array[index - 1]; 894 + type = policydb->type_val_to_struct[index - 1]; 895 895 BUG_ON(!type); 896 896 897 897 /* not bounded anymore */
+21 -27
security/selinux/ss/sidtab.c
··· 12 12 #include <linux/slab.h> 13 13 #include <linux/sched.h> 14 14 #include <linux/spinlock.h> 15 - #include <linux/atomic.h> 15 + #include <asm/barrier.h> 16 16 #include "flask.h" 17 17 #include "security.h" 18 18 #include "sidtab.h" ··· 23 23 24 24 memset(s->roots, 0, sizeof(s->roots)); 25 25 26 + /* max count is SIDTAB_MAX so valid index is always < SIDTAB_MAX */ 26 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 30 for (i = 0; i < SECINITSID_NUM; i++) 30 31 s->isids[i].set = 0; 31 32 32 - atomic_set(&s->count, 0); 33 - 33 + s->count = 0; 34 34 s->convert = NULL; 35 35 36 36 spin_lock_init(&s->lock); ··· 130 130 131 131 static 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 136 if (index >= count) 136 137 return NULL; 137 - 138 - /* read entries after reading count */ 139 - smp_rmb(); 140 138 141 139 return sidtab_do_lookup(s, index, 0); 142 140 } ··· 208 210 static void sidtab_rcache_update(struct sidtab *s, u32 index, u32 pos) 209 211 { 210 212 while (pos > 0) { 211 - atomic_set(&s->rcache[pos], atomic_read(&s->rcache[pos - 1])); 213 + WRITE_ONCE(s->rcache[pos], READ_ONCE(s->rcache[pos - 1])); 212 214 --pos; 213 215 } 214 - atomic_set(&s->rcache[0], (int)index); 216 + WRITE_ONCE(s->rcache[0], index); 215 217 } 216 218 217 219 static void sidtab_rcache_push(struct sidtab *s, u32 index) ··· 225 227 u32 i; 226 228 227 229 for (i = 0; i < SIDTAB_RCACHE_SIZE; i++) { 228 - int v = atomic_read(&s->rcache[i]); 230 + u32 v = READ_ONCE(s->rcache[i]); 229 231 230 - if (v < 0) 232 + if (v >= SIDTAB_MAX) 231 233 continue; 232 234 233 - if (context_cmp(sidtab_do_lookup(s, (u32)v, 0), context)) { 234 - sidtab_rcache_update(s, (u32)v, i); 235 - *index = (u32)v; 235 + if (context_cmp(sidtab_do_lookup(s, v, 0), context)) { 236 + sidtab_rcache_update(s, v, i); 237 + *index = v; 236 238 return 0; 237 239 } 238 240 } ··· 243 245 u32 *index) 244 246 { 245 247 unsigned long flags; 246 - u32 count = (u32)atomic_read(&s->count); 247 - u32 count_locked, level, pos; 248 + u32 count, count_locked, level, pos; 248 249 struct sidtab_convert_params *convert; 249 250 struct context *dst, *dst_convert; 250 251 int rc; ··· 252 255 if (rc == 0) 253 256 return 0; 254 257 258 + /* read entries only after reading count */ 259 + count = smp_load_acquire(&s->count); 255 260 level = sidtab_level_from_count(count); 256 - 257 - /* read entries after reading count */ 258 - smp_rmb(); 259 261 260 262 pos = 0; 261 263 rc = sidtab_find_context(s->roots[level], &pos, count, level, ··· 268 272 spin_lock_irqsave(&s->lock, flags); 269 273 270 274 convert = s->convert; 271 - count_locked = (u32)atomic_read(&s->count); 275 + count_locked = s->count; 272 276 level = sidtab_level_from_count(count_locked); 273 277 274 278 /* if count has changed before we acquired the lock, then catch up */ ··· 316 320 } 317 321 318 322 /* at this point we know the insert won't fail */ 319 - atomic_set(&convert->target->count, count + 1); 323 + convert->target->count = count + 1; 320 324 } 321 325 322 326 if (context->len) ··· 327 331 *index = count; 328 332 329 333 /* write entries before writing new count */ 330 - smp_wmb(); 331 - 332 - atomic_set(&s->count, count + 1); 334 + smp_store_release(&s->count, count + 1); 333 335 334 336 rc = 0; 335 337 out_unlock: ··· 417 423 return -EBUSY; 418 424 } 419 425 420 - count = (u32)atomic_read(&s->count); 426 + count = s->count; 421 427 level = sidtab_level_from_count(count); 422 428 423 429 /* allocate last leaf in the new sidtab (to avoid race with ··· 430 436 } 431 437 432 438 /* set count in case no new entries are added during conversion */ 433 - atomic_set(&params->target->count, count); 439 + params->target->count = count; 434 440 435 441 /* enable live convert of new entries */ 436 442 s->convert = params;
+14 -5
security/selinux/ss/sidtab.h
··· 40 40 #define SIDTAB_LEAF_ENTRIES \ 41 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 */ 44 - #define SIDTAB_MAX (((u32)1 << SIDTAB_MAX_BITS) - 1) 43 + #define SIDTAB_MAX_BITS 32 44 + #define SIDTAB_MAX U32_MAX 45 45 /* ensure enough tree levels for SIDTAB_MAX entries */ 46 46 #define SIDTAB_MAX_LEVEL \ 47 47 DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \ ··· 69 69 #define SIDTAB_RCACHE_SIZE 3 70 70 71 71 struct sidtab { 72 + /* 73 + * lock-free read access only for as many items as a prior read of 74 + * 'count' 75 + */ 72 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 83 struct sidtab_convert_params *convert; 75 84 spinlock_t lock; 76 85 77 - /* reverse lookup cache */ 78 - atomic_t rcache[SIDTAB_RCACHE_SIZE]; 86 + /* reverse lookup cache - access atomically via {READ|WRITE}_ONCE() */ 87 + u32 rcache[SIDTAB_RCACHE_SIZE]; 79 88 80 89 /* index == SID - 1 (no entry for SECSID_NULL) */ 81 90 struct sidtab_isid_entry isids[SECINITSID_NUM];