selinux/stable-5.4 PR 20190917

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCAAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAl2BLvcUHHBhdWxAcGF1
 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXP9pA/+Ls9sRGZoEipycbgRnwkL9/6yFtn4
 UCFGMP0eobrjL82i8uMOa/72Budsp3ZaZRxf36NpbMDPyB9ohp5jf7o1WFTELESv
 EwxVvOMNwrxO2UbzRv3iywnhdPVJ4gHPa4GWfBHu2EEfhz3/Bv0tPIBdeXAbq4aC
 R0p+M9X0FFEp9eP4ftwOvFGpbZ8zKo1kwgdvCnqLhHDkyqtapqO/ByCTe1VATERP
 fyxjYDZNnITmI0plaIxCeeudklOTtVSAL4JPh1rk8rZIkUznZ4EBDHxdKiaz3j9C
 ZtAthiAA9PfAwf4DZSPHnGsfINxeNBKLD65jZn/PUne/gNJEx4DK041X9HXBNwjv
 OoArw58LCzxtTNZ//WB4CovRpeSdKvmKv0oh61k8cdQahLeHhzXE1wLQbnnBJLI3
 CTsumIp4ZPEOX5r4ogdS3UIQpo3KrZump7VO85yUTRni150JpZR3egYpmcJ0So1A
 QTPemBhC2CHJVTpycYZ9fVTlPeC4oNwosPmvpB8XeGu3w5JpuNSId+BDR/ZlQAmq
 xWiIocGL3UMuPuJUrTGChifqBAgzK+gLa7S7RYPEnTCkj6LVQwsuP4gBXf75QTG4
 FPwVcoMSDFxUDF0oFqwz4GfJlCxBSzX+BkWUn6jIiXKXBnQjU+1gu6KTwE25mf/j
 snJznFk25hFYFaM=
 =n4ht
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2019-09-23 11:21:04 -07:00
Родитель 3c6a6910a8 15322a0d90
Коммит 5825a95fe9
18 изменённых файлов: 596 добавлений и 500 удалений

Просмотреть файл

@ -13,6 +13,7 @@
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/dnotify.h> #include <linux/dnotify.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/security.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/fdtable.h> #include <linux/fdtable.h>
@ -279,6 +280,17 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
goto out_err; goto out_err;
} }
/*
* convert the userspace DN_* "arg" to the internal FS_*
* defined in fsnotify
*/
mask = convert_arg(arg);
error = security_path_notify(&filp->f_path, mask,
FSNOTIFY_OBJ_TYPE_INODE);
if (error)
goto out_err;
/* expect most fcntl to add new rather than augment old */ /* expect most fcntl to add new rather than augment old */
dn = kmem_cache_alloc(dnotify_struct_cache, GFP_KERNEL); dn = kmem_cache_alloc(dnotify_struct_cache, GFP_KERNEL);
if (!dn) { if (!dn) {
@ -293,9 +305,6 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
goto out_err; goto out_err;
} }
/* convert the userspace DN_* "arg" to the internal FS_* defines in fsnotify */
mask = convert_arg(arg);
/* set up the new_fsn_mark and new_dn_mark */ /* set up the new_fsn_mark and new_dn_mark */
new_fsn_mark = &new_dn_mark->fsn_mark; new_fsn_mark = &new_dn_mark->fsn_mark;
fsnotify_init_mark(new_fsn_mark, dnotify_group); fsnotify_init_mark(new_fsn_mark, dnotify_group);

Просмотреть файл

@ -528,7 +528,8 @@ static const struct file_operations fanotify_fops = {
}; };
static int fanotify_find_path(int dfd, const char __user *filename, static int fanotify_find_path(int dfd, const char __user *filename,
struct path *path, unsigned int flags) struct path *path, unsigned int flags, __u64 mask,
unsigned int obj_type)
{ {
int ret; int ret;
@ -567,8 +568,15 @@ static int fanotify_find_path(int dfd, const char __user *filename,
/* you can only watch an inode if you have read permissions on it */ /* you can only watch an inode if you have read permissions on it */
ret = inode_permission(path->dentry->d_inode, MAY_READ); ret = inode_permission(path->dentry->d_inode, MAY_READ);
if (ret) {
path_put(path);
goto out;
}
ret = security_path_notify(path, mask, obj_type);
if (ret) if (ret)
path_put(path); path_put(path);
out: out:
return ret; return ret;
} }
@ -947,6 +955,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
__kernel_fsid_t __fsid, *fsid = NULL; __kernel_fsid_t __fsid, *fsid = NULL;
u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
unsigned int obj_type;
int ret; int ret;
pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n", 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,
switch (mark_type) { switch (mark_type) {
case FAN_MARK_INODE: case FAN_MARK_INODE:
obj_type = FSNOTIFY_OBJ_TYPE_INODE;
break;
case FAN_MARK_MOUNT: case FAN_MARK_MOUNT:
obj_type = FSNOTIFY_OBJ_TYPE_VFSMOUNT;
break;
case FAN_MARK_FILESYSTEM: case FAN_MARK_FILESYSTEM:
obj_type = FSNOTIFY_OBJ_TYPE_SB;
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -1030,7 +1044,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
goto fput_and_out; goto fput_and_out;
} }
ret = fanotify_find_path(dfd, pathname, &path, flags); ret = fanotify_find_path(dfd, pathname, &path, flags,
(mask & ALL_FSNOTIFY_EVENTS), obj_type);
if (ret) if (ret)
goto fput_and_out; goto fput_and_out;

Просмотреть файл

@ -30,6 +30,7 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/memcontrol.h> #include <linux/memcontrol.h>
#include <linux/security.h>
#include "inotify.h" #include "inotify.h"
#include "../fdinfo.h" #include "../fdinfo.h"
@ -331,7 +332,8 @@ static const struct file_operations inotify_fops = {
/* /*
* find_inode - resolve a user-given path to a specific inode * find_inode - resolve a user-given path to a specific inode
*/ */
static int inotify_find_inode(const char __user *dirname, struct path *path, unsigned flags) static int inotify_find_inode(const char __user *dirname, struct path *path,
unsigned int flags, __u64 mask)
{ {
int error; int error;
@ -340,8 +342,15 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
return error; return error;
/* you can only watch an inode if you have read permissions on it */ /* you can only watch an inode if you have read permissions on it */
error = inode_permission(path->dentry->d_inode, MAY_READ); error = inode_permission(path->dentry->d_inode, MAY_READ);
if (error) {
path_put(path);
return error;
}
error = security_path_notify(path, mask,
FSNOTIFY_OBJ_TYPE_INODE);
if (error) if (error)
path_put(path); path_put(path);
return error; return error;
} }
@ -733,7 +742,8 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
if (mask & IN_ONLYDIR) if (mask & IN_ONLYDIR)
flags |= LOOKUP_DIRECTORY; flags |= LOOKUP_DIRECTORY;
ret = inotify_find_inode(pathname, &path, flags); ret = inotify_find_inode(pathname, &path, flags,
(mask & IN_ALL_EVENTS));
if (ret) if (ret)
goto fput_and_out; goto fput_and_out;

Просмотреть файл

@ -386,7 +386,6 @@ static inline void put_cred(const struct cred *_cred)
#define current_fsgid() (current_cred_xxx(fsgid)) #define current_fsgid() (current_cred_xxx(fsgid))
#define current_cap() (current_cred_xxx(cap_effective)) #define current_cap() (current_cred_xxx(cap_effective))
#define current_user() (current_cred_xxx(user)) #define current_user() (current_cred_xxx(user))
#define current_security() (current_cred_xxx(security))
extern struct user_namespace init_user_ns; extern struct user_namespace init_user_ns;
#ifdef CONFIG_USER_NS #ifdef CONFIG_USER_NS

Просмотреть файл

@ -339,6 +339,9 @@
* Check for permission to change root directory. * Check for permission to change root directory.
* @path contains the path structure. * @path contains the path structure.
* Return 0 if permission is granted. * Return 0 if permission is granted.
* @path_notify:
* Check permissions before setting a watch on events as defined by @mask,
* on an object at @path, whose type is defined by @obj_type.
* @inode_readlink: * @inode_readlink:
* Check the permission to read the symbolic link. * Check the permission to read the symbolic link.
* @dentry contains the dentry structure for the file link. * @dentry contains the dentry structure for the file link.
@ -1535,7 +1538,9 @@ union security_list_options {
int (*path_chown)(const struct path *path, kuid_t uid, kgid_t gid); int (*path_chown)(const struct path *path, kuid_t uid, kgid_t gid);
int (*path_chroot)(const struct path *path); int (*path_chroot)(const struct path *path);
#endif #endif
/* Needed for inode based security check */
int (*path_notify)(const struct path *path, u64 mask,
unsigned int obj_type);
int (*inode_alloc_security)(struct inode *inode); int (*inode_alloc_security)(struct inode *inode);
void (*inode_free_security)(struct inode *inode); void (*inode_free_security)(struct inode *inode);
int (*inode_init_security)(struct inode *inode, struct inode *dir, int (*inode_init_security)(struct inode *inode, struct inode *dir,
@ -1860,6 +1865,8 @@ struct security_hook_heads {
struct hlist_head path_chown; struct hlist_head path_chown;
struct hlist_head path_chroot; struct hlist_head path_chroot;
#endif #endif
/* Needed for inode based modules as well */
struct hlist_head path_notify;
struct hlist_head inode_alloc_security; struct hlist_head inode_alloc_security;
struct hlist_head inode_free_security; struct hlist_head inode_free_security;
struct hlist_head inode_init_security; struct hlist_head inode_init_security;

Просмотреть файл

@ -259,7 +259,8 @@ int security_dentry_create_files_as(struct dentry *dentry, int mode,
struct qstr *name, struct qstr *name,
const struct cred *old, const struct cred *old,
struct cred *new); struct cred *new);
int security_path_notify(const struct path *path, u64 mask,
unsigned int obj_type);
int security_inode_alloc(struct inode *inode); int security_inode_alloc(struct inode *inode);
void security_inode_free(struct inode *inode); void security_inode_free(struct inode *inode);
int security_inode_init_security(struct inode *inode, struct inode *dir, int security_inode_init_security(struct inode *inode, struct inode *dir,
@ -387,7 +388,6 @@ int security_ismaclabel(const char *name);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen); void security_release_secctx(char *secdata, u32 seclen);
void security_inode_invalidate_secctx(struct inode *inode); void security_inode_invalidate_secctx(struct inode *inode);
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); int 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,
return 0; return 0;
} }
static inline int security_path_notify(const struct path *path, u64 mask,
unsigned int obj_type)
{
return 0;
}
static inline int security_inode_alloc(struct inode *inode) static inline int security_inode_alloc(struct inode *inode)
{ {
return 0; return 0;

Просмотреть файл

@ -870,6 +870,12 @@ int security_move_mount(const struct path *from_path, const struct path *to_path
return call_int_hook(move_mount, 0, from_path, to_path); return call_int_hook(move_mount, 0, from_path, to_path);
} }
int security_path_notify(const struct path *path, u64 mask,
unsigned int obj_type)
{
return call_int_hook(path_notify, 0, path, mask, obj_type);
}
int security_inode_alloc(struct inode *inode) int security_inode_alloc(struct inode *inode)
{ {
int rc = lsm_inode_alloc(inode); int rc = lsm_inode_alloc(inode);

Просмотреть файл

@ -89,6 +89,8 @@
#include <linux/kernfs.h> #include <linux/kernfs.h>
#include <linux/stringhash.h> /* for hashlen_string() */ #include <linux/stringhash.h> /* for hashlen_string() */
#include <uapi/linux/mount.h> #include <uapi/linux/mount.h>
#include <linux/fsnotify.h>
#include <linux/fanotify.h>
#include "avc.h" #include "avc.h"
#include "objsec.h" #include "objsec.h"
@ -3275,6 +3277,50 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
return -EACCES; return -EACCES;
} }
static int selinux_path_notify(const struct path *path, u64 mask,
unsigned int obj_type)
{
int ret;
u32 perm;
struct common_audit_data ad;
ad.type = LSM_AUDIT_DATA_PATH;
ad.u.path = *path;
/*
* Set permission needed based on the type of mark being set.
* Performs an additional check for sb watches.
*/
switch (obj_type) {
case FSNOTIFY_OBJ_TYPE_VFSMOUNT:
perm = FILE__WATCH_MOUNT;
break;
case FSNOTIFY_OBJ_TYPE_SB:
perm = FILE__WATCH_SB;
ret = superblock_has_perm(current_cred(), path->dentry->d_sb,
FILESYSTEM__WATCH, &ad);
if (ret)
return ret;
break;
case FSNOTIFY_OBJ_TYPE_INODE:
perm = FILE__WATCH;
break;
default:
return -EINVAL;
}
/* blocking watches require the file:watch_with_perm permission */
if (mask & (ALL_FSNOTIFY_PERM_EVENTS))
perm |= FILE__WATCH_WITH_PERM;
/* watches on read-like events need the file:watch_reads permission */
if (mask & (FS_ACCESS | FS_ACCESS_PERM | FS_CLOSE_NOWRITE))
perm |= FILE__WATCH_READS;
return path_has_perm(current_cred(), path, perm);
}
/* /*
* Copy the inode security context value to the user. * Copy the inode security context value to the user.
* *
@ -3403,7 +3449,7 @@ static int selinux_inode_copy_up_xattr(const char *name)
static int selinux_kernfs_init_security(struct kernfs_node *kn_dir, static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
struct kernfs_node *kn) struct kernfs_node *kn)
{ {
const struct task_security_struct *tsec = current_security(); const struct task_security_struct *tsec = selinux_cred(current_cred());
u32 parent_sid, newsid, clen; u32 parent_sid, newsid, clen;
int rc; int rc;
char *context; char *context;
@ -6818,6 +6864,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid), LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
LSM_HOOK_INIT(path_notify, selinux_path_notify),
LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security), LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security),

Просмотреть файл

@ -7,7 +7,8 @@
#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \ #define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
"rename", "execute", "quotaon", "mounton", "audit_access", \ "rename", "execute", "quotaon", "mounton", "audit_access", \
"open", "execmod" "open", "execmod", "watch", "watch_mount", "watch_sb", \
"watch_with_perm", "watch_reads"
#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \ #define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
"listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \ "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \
@ -60,7 +61,7 @@ struct security_class_mapping secclass_map[] = {
{ "filesystem", { "filesystem",
{ "mount", "remount", "unmount", "getattr", { "mount", "remount", "unmount", "getattr",
"relabelfrom", "relabelto", "associate", "quotamod", "relabelfrom", "relabelto", "associate", "quotamod",
"quotaget", NULL } }, "quotaget", "watch", NULL } },
{ "file", { "file",
{ COMMON_FILE_PERMS, { COMMON_FILE_PERMS,
"execute_no_trans", "entrypoint", NULL } }, "execute_no_trans", "entrypoint", NULL } },

Просмотреть файл

@ -37,16 +37,6 @@ struct task_security_struct {
u32 sockcreate_sid; /* fscreate SID */ u32 sockcreate_sid; /* fscreate SID */
}; };
/*
* get the subjective security ID of the current task
*/
static inline u32 current_sid(void)
{
const struct task_security_struct *tsec = current_security();
return tsec->sid;
}
enum label_initialized { enum label_initialized {
LABEL_INVALID, /* invalid or not initialized */ LABEL_INVALID, /* invalid or not initialized */
LABEL_INITIALIZED, /* initialized */ LABEL_INITIALIZED, /* initialized */
@ -185,4 +175,14 @@ static inline struct ipc_security_struct *selinux_ipc(
return ipc->security + selinux_blob_sizes.lbs_ipc; return ipc->security + selinux_blob_sizes.lbs_ipc;
} }
/*
* get the subjective security ID of the current task
*/
static inline u32 current_sid(void)
{
const struct task_security_struct *tsec = selinux_cred(current_cred());
return tsec->sid;
}
#endif /* _SELINUX_OBJSEC_H_ */ #endif /* _SELINUX_OBJSEC_H_ */

Просмотреть файл

@ -132,9 +132,9 @@ static void sel_netif_destroy(struct sel_netif *netif)
*/ */
static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
{ {
int ret; int ret = 0;
struct sel_netif *netif; struct sel_netif *netif;
struct sel_netif *new = NULL; struct sel_netif *new;
struct net_device *dev; struct net_device *dev;
/* NOTE: we always use init's network namespace since we don't /* 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)
netif = sel_netif_find(ns, ifindex); netif = sel_netif_find(ns, ifindex);
if (netif != NULL) { if (netif != NULL) {
*sid = netif->nsec.sid; *sid = netif->nsec.sid;
ret = 0;
goto out; goto out;
} }
ret = security_netif_sid(&selinux_state, dev->name, sid);
if (ret != 0)
goto out;
new = kzalloc(sizeof(*new), GFP_ATOMIC); new = kzalloc(sizeof(*new), GFP_ATOMIC);
if (new == NULL) { if (new) {
ret = -ENOMEM; new->nsec.ns = ns;
goto out; new->nsec.ifindex = ifindex;
new->nsec.sid = *sid;
if (sel_netif_insert(new))
kfree(new);
} }
ret = security_netif_sid(&selinux_state, dev->name, &new->nsec.sid);
if (ret != 0)
goto out;
new->nsec.ns = ns;
new->nsec.ifindex = ifindex;
ret = sel_netif_insert(new);
if (ret != 0)
goto out;
*sid = new->nsec.sid;
out: out:
spin_unlock_bh(&sel_netif_lock); spin_unlock_bh(&sel_netif_lock);
dev_put(dev); dev_put(dev);
if (unlikely(ret)) { if (unlikely(ret))
pr_warn("SELinux: failure in %s(), unable to determine network interface label (%d)\n", pr_warn("SELinux: failure in %s(), unable to determine network interface label (%d)\n",
__func__, ifindex); __func__, ifindex);
kfree(new);
}
return ret; return ret;
} }

Просмотреть файл

@ -189,9 +189,9 @@ static void sel_netnode_insert(struct sel_netnode *node)
*/ */
static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
{ {
int ret = -ENOMEM; int ret;
struct sel_netnode *node; struct sel_netnode *node;
struct sel_netnode *new = NULL; struct sel_netnode *new;
spin_lock_bh(&sel_netnode_lock); spin_lock_bh(&sel_netnode_lock);
node = sel_netnode_find(addr, family); node = sel_netnode_find(addr, family);
@ -200,38 +200,36 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
spin_unlock_bh(&sel_netnode_lock); spin_unlock_bh(&sel_netnode_lock);
return 0; return 0;
} }
new = kzalloc(sizeof(*new), GFP_ATOMIC); new = kzalloc(sizeof(*new), GFP_ATOMIC);
if (new == NULL)
goto out;
switch (family) { switch (family) {
case PF_INET: case PF_INET:
ret = security_node_sid(&selinux_state, PF_INET, ret = security_node_sid(&selinux_state, PF_INET,
addr, sizeof(struct in_addr), sid); addr, sizeof(struct in_addr), sid);
new->nsec.addr.ipv4 = *(__be32 *)addr; if (new)
new->nsec.addr.ipv4 = *(__be32 *)addr;
break; break;
case PF_INET6: case PF_INET6:
ret = security_node_sid(&selinux_state, PF_INET6, ret = security_node_sid(&selinux_state, PF_INET6,
addr, sizeof(struct in6_addr), sid); addr, sizeof(struct in6_addr), sid);
new->nsec.addr.ipv6 = *(struct in6_addr *)addr; if (new)
new->nsec.addr.ipv6 = *(struct in6_addr *)addr;
break; break;
default: default:
BUG(); BUG();
ret = -EINVAL; ret = -EINVAL;
} }
if (ret != 0) if (ret == 0 && new) {
goto out; new->nsec.family = family;
new->nsec.sid = *sid;
sel_netnode_insert(new);
} else
kfree(new);
new->nsec.family = family;
new->nsec.sid = *sid;
sel_netnode_insert(new);
out:
spin_unlock_bh(&sel_netnode_lock); spin_unlock_bh(&sel_netnode_lock);
if (unlikely(ret)) { if (unlikely(ret))
pr_warn("SELinux: failure in %s(), unable to determine network node label\n", pr_warn("SELinux: failure in %s(), unable to determine network node label\n",
__func__); __func__);
kfree(new);
}
return ret; return ret;
} }

Просмотреть файл

@ -137,9 +137,9 @@ static void sel_netport_insert(struct sel_netport *port)
*/ */
static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
{ {
int ret = -ENOMEM; int ret;
struct sel_netport *port; struct sel_netport *port;
struct sel_netport *new = NULL; struct sel_netport *new;
spin_lock_bh(&sel_netport_lock); spin_lock_bh(&sel_netport_lock);
port = sel_netport_find(protocol, pnum); port = sel_netport_find(protocol, pnum);
@ -148,25 +148,23 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
spin_unlock_bh(&sel_netport_lock); spin_unlock_bh(&sel_netport_lock);
return 0; return 0;
} }
new = kzalloc(sizeof(*new), GFP_ATOMIC);
if (new == NULL)
goto out;
ret = security_port_sid(&selinux_state, protocol, pnum, sid); ret = security_port_sid(&selinux_state, protocol, pnum, sid);
if (ret != 0) if (ret != 0)
goto out; goto out;
new = kzalloc(sizeof(*new), GFP_ATOMIC);
new->psec.port = pnum; if (new) {
new->psec.protocol = protocol; new->psec.port = pnum;
new->psec.sid = *sid; new->psec.protocol = protocol;
sel_netport_insert(new); new->psec.sid = *sid;
sel_netport_insert(new);
}
out: out:
spin_unlock_bh(&sel_netport_lock); spin_unlock_bh(&sel_netport_lock);
if (unlikely(ret)) { if (unlikely(ret))
pr_warn("SELinux: failure in %s(), unable to determine network port label\n", pr_warn("SELinux: failure in %s(), unable to determine network port label\n",
__func__); __func__);
kfree(new);
}
return ret; return ret;
} }

Просмотреть файл

@ -176,397 +176,6 @@ static struct policydb_compat_info *policydb_lookup_compat(int version)
return info; return info;
} }
/*
* Initialize the role table.
*/
static int roles_init(struct policydb *p)
{
char *key = NULL;
int rc;
struct role_datum *role;
role = kzalloc(sizeof(*role), GFP_KERNEL);
if (!role)
return -ENOMEM;
rc = -EINVAL;
role->value = ++p->p_roles.nprim;
if (role->value != OBJECT_R_VAL)
goto out;
rc = -ENOMEM;
key = kstrdup(OBJECT_R, GFP_KERNEL);
if (!key)
goto out;
rc = hashtab_insert(p->p_roles.table, key, role);
if (rc)
goto out;
return 0;
out:
kfree(key);
kfree(role);
return rc;
}
static u32 filenametr_hash(struct hashtab *h, const void *k)
{
const struct filename_trans *ft = k;
unsigned long hash;
unsigned int byte_num;
unsigned char focus;
hash = ft->stype ^ ft->ttype ^ ft->tclass;
byte_num = 0;
while ((focus = ft->name[byte_num++]))
hash = partial_name_hash(focus, hash);
return hash & (h->size - 1);
}
static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
{
const struct filename_trans *ft1 = k1;
const struct filename_trans *ft2 = k2;
int v;
v = ft1->stype - ft2->stype;
if (v)
return v;
v = ft1->ttype - ft2->ttype;
if (v)
return v;
v = ft1->tclass - ft2->tclass;
if (v)
return v;
return strcmp(ft1->name, ft2->name);
}
static u32 rangetr_hash(struct hashtab *h, const void *k)
{
const struct range_trans *key = k;
return (key->source_type + (key->target_type << 3) +
(key->target_class << 5)) & (h->size - 1);
}
static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
{
const struct range_trans *key1 = k1, *key2 = k2;
int v;
v = key1->source_type - key2->source_type;
if (v)
return v;
v = key1->target_type - key2->target_type;
if (v)
return v;
v = key1->target_class - key2->target_class;
return v;
}
static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap);
/*
* Initialize a policy database structure.
*/
static int policydb_init(struct policydb *p)
{
int i, rc;
memset(p, 0, sizeof(*p));
for (i = 0; i < SYM_NUM; i++) {
rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
if (rc)
goto out;
}
rc = avtab_init(&p->te_avtab);
if (rc)
goto out;
rc = roles_init(p);
if (rc)
goto out;
rc = cond_policydb_init(p);
if (rc)
goto out;
p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
if (!p->filename_trans) {
rc = -ENOMEM;
goto out;
}
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
if (!p->range_tr) {
rc = -ENOMEM;
goto out;
}
ebitmap_init(&p->filename_trans_ttypes);
ebitmap_init(&p->policycaps);
ebitmap_init(&p->permissive_map);
return 0;
out:
hashtab_destroy(p->filename_trans);
hashtab_destroy(p->range_tr);
for (i = 0; i < SYM_NUM; i++) {
hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
hashtab_destroy(p->symtab[i].table);
}
return rc;
}
/*
* The following *_index functions are used to
* define the val_to_name and val_to_struct arrays
* in a policy database structure. The val_to_name
* arrays are used when converting security context
* structures into string representations. The
* val_to_struct arrays are used when the attributes
* of a class, role, or user are needed.
*/
static int common_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct common_datum *comdatum;
comdatum = datum;
p = datap;
if (!comdatum->value || comdatum->value > p->p_commons.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1] = key;
return 0;
}
static int class_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct class_datum *cladatum;
cladatum = datum;
p = datap;
if (!cladatum->value || cladatum->value > p->p_classes.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_CLASSES][cladatum->value - 1] = key;
p->class_val_to_struct[cladatum->value - 1] = cladatum;
return 0;
}
static int role_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct role_datum *role;
role = datum;
p = datap;
if (!role->value
|| role->value > p->p_roles.nprim
|| role->bounds > p->p_roles.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_ROLES][role->value - 1] = key;
p->role_val_to_struct[role->value - 1] = role;
return 0;
}
static int type_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct type_datum *typdatum;
typdatum = datum;
p = datap;
if (typdatum->primary) {
if (!typdatum->value
|| typdatum->value > p->p_types.nprim
|| typdatum->bounds > p->p_types.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key;
p->type_val_to_struct_array[typdatum->value - 1] = typdatum;
}
return 0;
}
static int user_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct user_datum *usrdatum;
usrdatum = datum;
p = datap;
if (!usrdatum->value
|| usrdatum->value > p->p_users.nprim
|| usrdatum->bounds > p->p_users.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key;
p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
return 0;
}
static int sens_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct level_datum *levdatum;
levdatum = datum;
p = datap;
if (!levdatum->isalias) {
if (!levdatum->level->sens ||
levdatum->level->sens > p->p_levels.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_LEVELS][levdatum->level->sens - 1] = key;
}
return 0;
}
static int cat_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct cat_datum *catdatum;
catdatum = datum;
p = datap;
if (!catdatum->isalias) {
if (!catdatum->value || catdatum->value > p->p_cats.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_CATS][catdatum->value - 1] = key;
}
return 0;
}
static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
{
common_index,
class_index,
role_index,
type_index,
user_index,
cond_index_bool,
sens_index,
cat_index,
};
#ifdef DEBUG_HASHES
static void hash_eval(struct hashtab *h, const char *hash_name)
{
struct hashtab_info info;
hashtab_stat(h, &info);
pr_debug("SELinux: %s: %d entries and %d/%d buckets used, "
"longest chain length %d\n", hash_name, h->nel,
info.slots_used, h->size, info.max_chain_len);
}
static void symtab_hash_eval(struct symtab *s)
{
int i;
for (i = 0; i < SYM_NUM; i++)
hash_eval(s[i].table, symtab_name[i]);
}
#else
static inline void hash_eval(struct hashtab *h, char *hash_name)
{
}
#endif
/*
* Define the other val_to_name and val_to_struct arrays
* in a policy database structure.
*
* Caller must clean up on failure.
*/
static int policydb_index(struct policydb *p)
{
int i, rc;
if (p->mls_enabled)
pr_debug("SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n",
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim);
else
pr_debug("SELinux: %d users, %d roles, %d types, %d bools\n",
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
p->p_bools.nprim);
pr_debug("SELinux: %d classes, %d rules\n",
p->p_classes.nprim, p->te_avtab.nel);
#ifdef DEBUG_HASHES
avtab_hash_eval(&p->te_avtab, "rules");
symtab_hash_eval(p->symtab);
#endif
p->class_val_to_struct = kcalloc(p->p_classes.nprim,
sizeof(*p->class_val_to_struct),
GFP_KERNEL);
if (!p->class_val_to_struct)
return -ENOMEM;
p->role_val_to_struct = kcalloc(p->p_roles.nprim,
sizeof(*p->role_val_to_struct),
GFP_KERNEL);
if (!p->role_val_to_struct)
return -ENOMEM;
p->user_val_to_struct = kcalloc(p->p_users.nprim,
sizeof(*p->user_val_to_struct),
GFP_KERNEL);
if (!p->user_val_to_struct)
return -ENOMEM;
p->type_val_to_struct_array = kvcalloc(p->p_types.nprim,
sizeof(*p->type_val_to_struct_array),
GFP_KERNEL);
if (!p->type_val_to_struct_array)
return -ENOMEM;
rc = cond_init_bool_indexes(p);
if (rc)
goto out;
for (i = 0; i < SYM_NUM; i++) {
p->sym_val_to_name[i] = kvcalloc(p->symtab[i].nprim,
sizeof(char *),
GFP_KERNEL);
if (!p->sym_val_to_name[i])
return -ENOMEM;
rc = hashtab_map(p->symtab[i].table, index_f[i], p);
if (rc)
goto out;
}
rc = 0;
out:
return rc;
}
/* /*
* The following *_destroy functions are used to * The following *_destroy functions are used to
* free any memory allocated for each kind of * free any memory allocated for each kind of
@ -723,6 +332,7 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
static int filenametr_destroy(void *key, void *datum, void *p) static int filenametr_destroy(void *key, void *datum, void *p)
{ {
struct filename_trans *ft = key; struct filename_trans *ft = key;
kfree(ft->name); kfree(ft->name);
kfree(key); kfree(key);
kfree(datum); kfree(datum);
@ -733,6 +343,7 @@ static int filenametr_destroy(void *key, void *datum, void *p)
static int range_tr_destroy(void *key, void *datum, void *p) static int range_tr_destroy(void *key, void *datum, void *p)
{ {
struct mls_range *rt = datum; struct mls_range *rt = datum;
kfree(key); kfree(key);
ebitmap_destroy(&rt->level[0].cat); ebitmap_destroy(&rt->level[0].cat);
ebitmap_destroy(&rt->level[1].cat); ebitmap_destroy(&rt->level[1].cat);
@ -754,6 +365,397 @@ static void ocontext_destroy(struct ocontext *c, int i)
kfree(c); kfree(c);
} }
/*
* Initialize the role table.
*/
static int roles_init(struct policydb *p)
{
char *key = NULL;
int rc;
struct role_datum *role;
role = kzalloc(sizeof(*role), GFP_KERNEL);
if (!role)
return -ENOMEM;
rc = -EINVAL;
role->value = ++p->p_roles.nprim;
if (role->value != OBJECT_R_VAL)
goto out;
rc = -ENOMEM;
key = kstrdup(OBJECT_R, GFP_KERNEL);
if (!key)
goto out;
rc = hashtab_insert(p->p_roles.table, key, role);
if (rc)
goto out;
return 0;
out:
kfree(key);
kfree(role);
return rc;
}
static u32 filenametr_hash(struct hashtab *h, const void *k)
{
const struct filename_trans *ft = k;
unsigned long hash;
unsigned int byte_num;
unsigned char focus;
hash = ft->stype ^ ft->ttype ^ ft->tclass;
byte_num = 0;
while ((focus = ft->name[byte_num++]))
hash = partial_name_hash(focus, hash);
return hash & (h->size - 1);
}
static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
{
const struct filename_trans *ft1 = k1;
const struct filename_trans *ft2 = k2;
int v;
v = ft1->stype - ft2->stype;
if (v)
return v;
v = ft1->ttype - ft2->ttype;
if (v)
return v;
v = ft1->tclass - ft2->tclass;
if (v)
return v;
return strcmp(ft1->name, ft2->name);
}
static u32 rangetr_hash(struct hashtab *h, const void *k)
{
const struct range_trans *key = k;
return (key->source_type + (key->target_type << 3) +
(key->target_class << 5)) & (h->size - 1);
}
static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
{
const struct range_trans *key1 = k1, *key2 = k2;
int v;
v = key1->source_type - key2->source_type;
if (v)
return v;
v = key1->target_type - key2->target_type;
if (v)
return v;
v = key1->target_class - key2->target_class;
return v;
}
/*
* Initialize a policy database structure.
*/
static int policydb_init(struct policydb *p)
{
int i, rc;
memset(p, 0, sizeof(*p));
for (i = 0; i < SYM_NUM; i++) {
rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
if (rc)
goto out;
}
rc = avtab_init(&p->te_avtab);
if (rc)
goto out;
rc = roles_init(p);
if (rc)
goto out;
rc = cond_policydb_init(p);
if (rc)
goto out;
p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp,
(1 << 10));
if (!p->filename_trans) {
rc = -ENOMEM;
goto out;
}
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
if (!p->range_tr) {
rc = -ENOMEM;
goto out;
}
ebitmap_init(&p->filename_trans_ttypes);
ebitmap_init(&p->policycaps);
ebitmap_init(&p->permissive_map);
return 0;
out:
hashtab_destroy(p->filename_trans);
hashtab_destroy(p->range_tr);
for (i = 0; i < SYM_NUM; i++) {
hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
hashtab_destroy(p->symtab[i].table);
}
return rc;
}
/*
* The following *_index functions are used to
* define the val_to_name and val_to_struct arrays
* in a policy database structure. The val_to_name
* arrays are used when converting security context
* structures into string representations. The
* val_to_struct arrays are used when the attributes
* of a class, role, or user are needed.
*/
static int common_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct common_datum *comdatum;
comdatum = datum;
p = datap;
if (!comdatum->value || comdatum->value > p->p_commons.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1] = key;
return 0;
}
static int class_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct class_datum *cladatum;
cladatum = datum;
p = datap;
if (!cladatum->value || cladatum->value > p->p_classes.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_CLASSES][cladatum->value - 1] = key;
p->class_val_to_struct[cladatum->value - 1] = cladatum;
return 0;
}
static int role_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct role_datum *role;
role = datum;
p = datap;
if (!role->value
|| role->value > p->p_roles.nprim
|| role->bounds > p->p_roles.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_ROLES][role->value - 1] = key;
p->role_val_to_struct[role->value - 1] = role;
return 0;
}
static int type_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct type_datum *typdatum;
typdatum = datum;
p = datap;
if (typdatum->primary) {
if (!typdatum->value
|| typdatum->value > p->p_types.nprim
|| typdatum->bounds > p->p_types.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key;
p->type_val_to_struct[typdatum->value - 1] = typdatum;
}
return 0;
}
static int user_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct user_datum *usrdatum;
usrdatum = datum;
p = datap;
if (!usrdatum->value
|| usrdatum->value > p->p_users.nprim
|| usrdatum->bounds > p->p_users.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key;
p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
return 0;
}
static int sens_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct level_datum *levdatum;
levdatum = datum;
p = datap;
if (!levdatum->isalias) {
if (!levdatum->level->sens ||
levdatum->level->sens > p->p_levels.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_LEVELS][levdatum->level->sens - 1] = key;
}
return 0;
}
static int cat_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct cat_datum *catdatum;
catdatum = datum;
p = datap;
if (!catdatum->isalias) {
if (!catdatum->value || catdatum->value > p->p_cats.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_CATS][catdatum->value - 1] = key;
}
return 0;
}
static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
{
common_index,
class_index,
role_index,
type_index,
user_index,
cond_index_bool,
sens_index,
cat_index,
};
#ifdef DEBUG_HASHES
static void hash_eval(struct hashtab *h, const char *hash_name)
{
struct hashtab_info info;
hashtab_stat(h, &info);
pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d\n",
hash_name, h->nel, info.slots_used, h->size,
info.max_chain_len);
}
static void symtab_hash_eval(struct symtab *s)
{
int i;
for (i = 0; i < SYM_NUM; i++)
hash_eval(s[i].table, symtab_name[i]);
}
#else
static inline void hash_eval(struct hashtab *h, char *hash_name)
{
}
#endif
/*
* Define the other val_to_name and val_to_struct arrays
* in a policy database structure.
*
* Caller must clean up on failure.
*/
static int policydb_index(struct policydb *p)
{
int i, rc;
if (p->mls_enabled)
pr_debug("SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n",
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim);
else
pr_debug("SELinux: %d users, %d roles, %d types, %d bools\n",
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
p->p_bools.nprim);
pr_debug("SELinux: %d classes, %d rules\n",
p->p_classes.nprim, p->te_avtab.nel);
#ifdef DEBUG_HASHES
avtab_hash_eval(&p->te_avtab, "rules");
symtab_hash_eval(p->symtab);
#endif
p->class_val_to_struct = kcalloc(p->p_classes.nprim,
sizeof(*p->class_val_to_struct),
GFP_KERNEL);
if (!p->class_val_to_struct)
return -ENOMEM;
p->role_val_to_struct = kcalloc(p->p_roles.nprim,
sizeof(*p->role_val_to_struct),
GFP_KERNEL);
if (!p->role_val_to_struct)
return -ENOMEM;
p->user_val_to_struct = kcalloc(p->p_users.nprim,
sizeof(*p->user_val_to_struct),
GFP_KERNEL);
if (!p->user_val_to_struct)
return -ENOMEM;
p->type_val_to_struct = kvcalloc(p->p_types.nprim,
sizeof(*p->type_val_to_struct),
GFP_KERNEL);
if (!p->type_val_to_struct)
return -ENOMEM;
rc = cond_init_bool_indexes(p);
if (rc)
goto out;
for (i = 0; i < SYM_NUM; i++) {
p->sym_val_to_name[i] = kvcalloc(p->symtab[i].nprim,
sizeof(char *),
GFP_KERNEL);
if (!p->sym_val_to_name[i])
return -ENOMEM;
rc = hashtab_map(p->symtab[i].table, index_f[i], p);
if (rc)
goto out;
}
rc = 0;
out:
return rc;
}
/* /*
* Free any memory allocated by a policy database structure. * Free any memory allocated by a policy database structure.
*/ */
@ -777,7 +779,7 @@ void policydb_destroy(struct policydb *p)
kfree(p->class_val_to_struct); kfree(p->class_val_to_struct);
kfree(p->role_val_to_struct); kfree(p->role_val_to_struct);
kfree(p->user_val_to_struct); kfree(p->user_val_to_struct);
kvfree(p->type_val_to_struct_array); kvfree(p->type_val_to_struct);
avtab_destroy(&p->te_avtab); avtab_destroy(&p->te_avtab);
@ -1722,7 +1724,7 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap)
return -EINVAL; return -EINVAL;
} }
upper = p->type_val_to_struct_array[upper->bounds - 1]; upper = p->type_val_to_struct[upper->bounds - 1];
BUG_ON(!upper); BUG_ON(!upper);
if (upper->attribute) { if (upper->attribute) {

Просмотреть файл

@ -253,7 +253,7 @@ struct policydb {
struct class_datum **class_val_to_struct; struct class_datum **class_val_to_struct;
struct role_datum **role_val_to_struct; struct role_datum **role_val_to_struct;
struct user_datum **user_val_to_struct; struct user_datum **user_val_to_struct;
struct type_datum **type_val_to_struct_array; struct type_datum **type_val_to_struct;
/* type enforcement access vectors and transitions */ /* type enforcement access vectors and transitions */
struct avtab te_avtab; struct avtab te_avtab;

Просмотреть файл

@ -542,13 +542,13 @@ static void type_attribute_bounds_av(struct policydb *policydb,
struct type_datum *target; struct type_datum *target;
u32 masked = 0; u32 masked = 0;
source = policydb->type_val_to_struct_array[scontext->type - 1]; source = policydb->type_val_to_struct[scontext->type - 1];
BUG_ON(!source); BUG_ON(!source);
if (!source->bounds) if (!source->bounds)
return; return;
target = policydb->type_val_to_struct_array[tcontext->type - 1]; target = policydb->type_val_to_struct[tcontext->type - 1];
BUG_ON(!target); BUG_ON(!target);
memset(&lo_avd, 0, sizeof(lo_avd)); memset(&lo_avd, 0, sizeof(lo_avd));
@ -891,7 +891,7 @@ int security_bounded_transition(struct selinux_state *state,
index = new_context->type; index = new_context->type;
while (true) { while (true) {
type = policydb->type_val_to_struct_array[index - 1]; type = policydb->type_val_to_struct[index - 1];
BUG_ON(!type); BUG_ON(!type);
/* not bounded anymore */ /* not bounded anymore */

Просмотреть файл

@ -12,7 +12,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/atomic.h> #include <asm/barrier.h>
#include "flask.h" #include "flask.h"
#include "security.h" #include "security.h"
#include "sidtab.h" #include "sidtab.h"
@ -23,14 +23,14 @@ int sidtab_init(struct sidtab *s)
memset(s->roots, 0, sizeof(s->roots)); memset(s->roots, 0, sizeof(s->roots));
/* max count is SIDTAB_MAX so valid index is always < SIDTAB_MAX */
for (i = 0; i < SIDTAB_RCACHE_SIZE; i++) for (i = 0; i < SIDTAB_RCACHE_SIZE; i++)
atomic_set(&s->rcache[i], -1); s->rcache[i] = SIDTAB_MAX;
for (i = 0; i < SECINITSID_NUM; i++) for (i = 0; i < SECINITSID_NUM; i++)
s->isids[i].set = 0; s->isids[i].set = 0;
atomic_set(&s->count, 0); s->count = 0;
s->convert = NULL; s->convert = NULL;
spin_lock_init(&s->lock); spin_lock_init(&s->lock);
@ -130,14 +130,12 @@ static struct context *sidtab_do_lookup(struct sidtab *s, u32 index, int alloc)
static struct context *sidtab_lookup(struct sidtab *s, u32 index) static struct context *sidtab_lookup(struct sidtab *s, u32 index)
{ {
u32 count = (u32)atomic_read(&s->count); /* read entries only after reading count */
u32 count = smp_load_acquire(&s->count);
if (index >= count) if (index >= count)
return NULL; return NULL;
/* read entries after reading count */
smp_rmb();
return sidtab_do_lookup(s, index, 0); return sidtab_do_lookup(s, index, 0);
} }
@ -210,10 +208,10 @@ static int sidtab_find_context(union sidtab_entry_inner entry,
static void sidtab_rcache_update(struct sidtab *s, u32 index, u32 pos) static void sidtab_rcache_update(struct sidtab *s, u32 index, u32 pos)
{ {
while (pos > 0) { while (pos > 0) {
atomic_set(&s->rcache[pos], atomic_read(&s->rcache[pos - 1])); WRITE_ONCE(s->rcache[pos], READ_ONCE(s->rcache[pos - 1]));
--pos; --pos;
} }
atomic_set(&s->rcache[0], (int)index); WRITE_ONCE(s->rcache[0], index);
} }
static void sidtab_rcache_push(struct sidtab *s, u32 index) static void sidtab_rcache_push(struct sidtab *s, u32 index)
@ -227,14 +225,14 @@ static int sidtab_rcache_search(struct sidtab *s, struct context *context,
u32 i; u32 i;
for (i = 0; i < SIDTAB_RCACHE_SIZE; i++) { for (i = 0; i < SIDTAB_RCACHE_SIZE; i++) {
int v = atomic_read(&s->rcache[i]); u32 v = READ_ONCE(s->rcache[i]);
if (v < 0) if (v >= SIDTAB_MAX)
continue; continue;
if (context_cmp(sidtab_do_lookup(s, (u32)v, 0), context)) { if (context_cmp(sidtab_do_lookup(s, v, 0), context)) {
sidtab_rcache_update(s, (u32)v, i); sidtab_rcache_update(s, v, i);
*index = (u32)v; *index = v;
return 0; return 0;
} }
} }
@ -245,8 +243,7 @@ static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
u32 *index) u32 *index)
{ {
unsigned long flags; unsigned long flags;
u32 count = (u32)atomic_read(&s->count); u32 count, count_locked, level, pos;
u32 count_locked, level, pos;
struct sidtab_convert_params *convert; struct sidtab_convert_params *convert;
struct context *dst, *dst_convert; struct context *dst, *dst_convert;
int rc; int rc;
@ -255,11 +252,10 @@ static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
if (rc == 0) if (rc == 0)
return 0; return 0;
/* read entries only after reading count */
count = smp_load_acquire(&s->count);
level = sidtab_level_from_count(count); level = sidtab_level_from_count(count);
/* read entries after reading count */
smp_rmb();
pos = 0; pos = 0;
rc = sidtab_find_context(s->roots[level], &pos, count, level, rc = sidtab_find_context(s->roots[level], &pos, count, level,
context, index); context, index);
@ -272,7 +268,7 @@ static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
spin_lock_irqsave(&s->lock, flags); spin_lock_irqsave(&s->lock, flags);
convert = s->convert; convert = s->convert;
count_locked = (u32)atomic_read(&s->count); count_locked = s->count;
level = sidtab_level_from_count(count_locked); level = sidtab_level_from_count(count_locked);
/* if count has changed before we acquired the lock, then catch up */ /* 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,
} }
/* at this point we know the insert won't fail */ /* at this point we know the insert won't fail */
atomic_set(&convert->target->count, count + 1); convert->target->count = count + 1;
} }
if (context->len) if (context->len)
@ -331,9 +327,7 @@ static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
*index = count; *index = count;
/* write entries before writing new count */ /* write entries before writing new count */
smp_wmb(); smp_store_release(&s->count, count + 1);
atomic_set(&s->count, count + 1);
rc = 0; rc = 0;
out_unlock: out_unlock:
@ -423,7 +417,7 @@ int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params)
return -EBUSY; return -EBUSY;
} }
count = (u32)atomic_read(&s->count); count = s->count;
level = sidtab_level_from_count(count); level = sidtab_level_from_count(count);
/* allocate last leaf in the new sidtab (to avoid race with /* 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)
} }
/* set count in case no new entries are added during conversion */ /* set count in case no new entries are added during conversion */
atomic_set(&params->target->count, count); params->target->count = count;
/* enable live convert of new entries */ /* enable live convert of new entries */
s->convert = params; s->convert = params;

Просмотреть файл

@ -40,8 +40,8 @@ union sidtab_entry_inner {
#define SIDTAB_LEAF_ENTRIES \ #define SIDTAB_LEAF_ENTRIES \
(SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry_leaf)) (SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry_leaf))
#define SIDTAB_MAX_BITS 31 /* limited to INT_MAX due to atomic_t range */ #define SIDTAB_MAX_BITS 32
#define SIDTAB_MAX (((u32)1 << SIDTAB_MAX_BITS) - 1) #define SIDTAB_MAX U32_MAX
/* ensure enough tree levels for SIDTAB_MAX entries */ /* ensure enough tree levels for SIDTAB_MAX entries */
#define SIDTAB_MAX_LEVEL \ #define SIDTAB_MAX_LEVEL \
DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \ DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \
@ -69,13 +69,22 @@ struct sidtab_convert_params {
#define SIDTAB_RCACHE_SIZE 3 #define SIDTAB_RCACHE_SIZE 3
struct sidtab { struct sidtab {
/*
* lock-free read access only for as many items as a prior read of
* 'count'
*/
union sidtab_entry_inner roots[SIDTAB_MAX_LEVEL + 1]; union sidtab_entry_inner roots[SIDTAB_MAX_LEVEL + 1];
atomic_t count; /*
* access atomically via {READ|WRITE}_ONCE(); only increment under
* spinlock
*/
u32 count;
/* access only under spinlock */
struct sidtab_convert_params *convert; struct sidtab_convert_params *convert;
spinlock_t lock; spinlock_t lock;
/* reverse lookup cache */ /* reverse lookup cache - access atomically via {READ|WRITE}_ONCE() */
atomic_t rcache[SIDTAB_RCACHE_SIZE]; u32 rcache[SIDTAB_RCACHE_SIZE];
/* index == SID - 1 (no entry for SECSID_NULL) */ /* index == SID - 1 (no entry for SECSID_NULL) */
struct sidtab_isid_entry isids[SECINITSID_NUM]; struct sidtab_isid_entry isids[SECINITSID_NUM];