Merge branch 'stable-4.7' of git://git.infradead.org/users/pcmoore/selinux into next

This commit is contained in:
James Morris 2016-05-06 09:31:34 +10:00
commit a6926cc989
6 changed files with 128 additions and 61 deletions

View file

@ -677,7 +677,7 @@ int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap,
u32 spot = start; u32 spot = start;
while (rc == 0 && spot <= end) { while (rc == 0 && spot <= end) {
if (((spot & (BITS_PER_LONG - 1)) != 0) && if (((spot & (BITS_PER_LONG - 1)) == 0) &&
((end - spot) > BITS_PER_LONG)) { ((end - spot) > BITS_PER_LONG)) {
rc = netlbl_catmap_setlong(catmap, rc = netlbl_catmap_setlong(catmap,
spot, spot,

View file

@ -259,7 +259,7 @@ static int __inode_security_revalidate(struct inode *inode,
might_sleep_if(may_sleep); might_sleep_if(may_sleep);
if (isec->initialized == LABEL_INVALID) { if (ss_initialized && isec->initialized != LABEL_INITIALIZED) {
if (!may_sleep) if (!may_sleep)
return -ECHILD; return -ECHILD;
@ -297,6 +297,13 @@ static struct inode_security_struct *inode_security(struct inode *inode)
return inode->i_security; return inode->i_security;
} }
static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry)
{
struct inode *inode = d_backing_inode(dentry);
return inode->i_security;
}
/* /*
* Get the security label of a dentry's backing inode. * Get the security label of a dentry's backing inode.
*/ */
@ -686,7 +693,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
struct superblock_security_struct *sbsec = sb->s_security; struct superblock_security_struct *sbsec = sb->s_security;
const char *name = sb->s_type->name; const char *name = sb->s_type->name;
struct dentry *root = sbsec->sb->s_root; struct dentry *root = sbsec->sb->s_root;
struct inode_security_struct *root_isec = backing_inode_security(root); struct inode_security_struct *root_isec;
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
u32 defcontext_sid = 0; u32 defcontext_sid = 0;
char **mount_options = opts->mnt_opts; char **mount_options = opts->mnt_opts;
@ -729,6 +736,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
&& (num_opts == 0)) && (num_opts == 0))
goto out; goto out;
root_isec = backing_inode_security_novalidate(root);
/* /*
* parse the mount options, check if they are valid sids. * parse the mount options, check if they are valid sids.
* also check if someone is trying to mount the same sb more * also check if someone is trying to mount the same sb more
@ -1622,7 +1631,7 @@ static int current_has_perm(const struct task_struct *tsk,
/* Check whether a task is allowed to use a capability. */ /* Check whether a task is allowed to use a capability. */
static int cred_has_capability(const struct cred *cred, static int cred_has_capability(const struct cred *cred,
int cap, int audit) int cap, int audit, bool initns)
{ {
struct common_audit_data ad; struct common_audit_data ad;
struct av_decision avd; struct av_decision avd;
@ -1636,10 +1645,10 @@ static int cred_has_capability(const struct cred *cred,
switch (CAP_TO_INDEX(cap)) { switch (CAP_TO_INDEX(cap)) {
case 0: case 0:
sclass = SECCLASS_CAPABILITY; sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS;
break; break;
case 1: case 1:
sclass = SECCLASS_CAPABILITY2; sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS;
break; break;
default: default:
printk(KERN_ERR printk(KERN_ERR
@ -1781,7 +1790,6 @@ static int selinux_determine_inode_label(struct inode *dir,
u32 *_new_isid) u32 *_new_isid)
{ {
const struct superblock_security_struct *sbsec = dir->i_sb->s_security; const struct superblock_security_struct *sbsec = dir->i_sb->s_security;
const struct inode_security_struct *dsec = inode_security(dir);
const struct task_security_struct *tsec = current_security(); const struct task_security_struct *tsec = current_security();
if ((sbsec->flags & SE_SBINITIALIZED) && if ((sbsec->flags & SE_SBINITIALIZED) &&
@ -1791,6 +1799,7 @@ static int selinux_determine_inode_label(struct inode *dir,
tsec->create_sid) { tsec->create_sid) {
*_new_isid = tsec->create_sid; *_new_isid = tsec->create_sid;
} else { } else {
const struct inode_security_struct *dsec = inode_security(dir);
return security_transition_sid(tsec->sid, dsec->sid, tclass, return security_transition_sid(tsec->sid, dsec->sid, tclass,
name, _new_isid); name, _new_isid);
} }
@ -2075,7 +2084,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
u32 sid = task_sid(to); u32 sid = task_sid(to);
struct file_security_struct *fsec = file->f_security; struct file_security_struct *fsec = file->f_security;
struct dentry *dentry = file->f_path.dentry; struct dentry *dentry = file->f_path.dentry;
struct inode_security_struct *isec = backing_inode_security(dentry); struct inode_security_struct *isec;
struct common_audit_data ad; struct common_audit_data ad;
int rc; int rc;
@ -2094,6 +2103,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0; return 0;
isec = backing_inode_security(dentry);
return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file), return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
&ad); &ad);
} }
@ -2142,7 +2152,7 @@ static int selinux_capset(struct cred *new, const struct cred *old,
static int selinux_capable(const struct cred *cred, struct user_namespace *ns, static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
int cap, int audit) int cap, int audit)
{ {
return cred_has_capability(cred, cap, audit); return cred_has_capability(cred, cap, audit, ns == &init_user_ns);
} }
static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
@ -2220,7 +2230,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
int rc, cap_sys_admin = 0; int rc, cap_sys_admin = 0;
rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN, rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
SECURITY_CAP_NOAUDIT); SECURITY_CAP_NOAUDIT, true);
if (rc == 0) if (rc == 0)
cap_sys_admin = 1; cap_sys_admin = 1;
@ -2229,6 +2239,20 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
/* binprm security operations */ /* binprm security operations */
static u32 ptrace_parent_sid(struct task_struct *task)
{
u32 sid = 0;
struct task_struct *tracer;
rcu_read_lock();
tracer = ptrace_parent(task);
if (tracer)
sid = task_sid(tracer);
rcu_read_unlock();
return sid;
}
static int check_nnp_nosuid(const struct linux_binprm *bprm, static int check_nnp_nosuid(const struct linux_binprm *bprm,
const struct task_security_struct *old_tsec, const struct task_security_struct *old_tsec,
const struct task_security_struct *new_tsec) const struct task_security_struct *new_tsec)
@ -2350,18 +2374,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
* changes its SID has the appropriate permit */ * changes its SID has the appropriate permit */
if (bprm->unsafe & if (bprm->unsafe &
(LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
struct task_struct *tracer; u32 ptsid = ptrace_parent_sid(current);
struct task_security_struct *sec;
u32 ptsid = 0;
rcu_read_lock();
tracer = ptrace_parent(current);
if (likely(tracer != NULL)) {
sec = __task_cred(tracer)->security;
ptsid = sec->sid;
}
rcu_read_unlock();
if (ptsid != 0) { if (ptsid != 0) {
rc = avc_has_perm(ptsid, new_tsec->sid, rc = avc_has_perm(ptsid, new_tsec->sid,
SECCLASS_PROCESS, SECCLASS_PROCESS,
@ -3045,7 +3058,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags)
{ {
struct inode *inode = d_backing_inode(dentry); struct inode *inode = d_backing_inode(dentry);
struct inode_security_struct *isec = backing_inode_security(dentry); struct inode_security_struct *isec;
struct superblock_security_struct *sbsec; struct superblock_security_struct *sbsec;
struct common_audit_data ad; struct common_audit_data ad;
u32 newsid, sid = current_sid(); u32 newsid, sid = current_sid();
@ -3064,6 +3077,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
ad.type = LSM_AUDIT_DATA_DENTRY; ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry; ad.u.dentry = dentry;
isec = backing_inode_security(dentry);
rc = avc_has_perm(sid, isec->sid, isec->sclass, rc = avc_has_perm(sid, isec->sid, isec->sclass,
FILE__RELABELFROM, &ad); FILE__RELABELFROM, &ad);
if (rc) if (rc)
@ -3122,7 +3136,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
int flags) int flags)
{ {
struct inode *inode = d_backing_inode(dentry); struct inode *inode = d_backing_inode(dentry);
struct inode_security_struct *isec = backing_inode_security(dentry); struct inode_security_struct *isec;
u32 newsid; u32 newsid;
int rc; int rc;
@ -3139,6 +3153,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return; return;
} }
isec = backing_inode_security(dentry);
isec->sclass = inode_mode_to_security_class(inode->i_mode); isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid; isec->sid = newsid;
isec->initialized = LABEL_INITIALIZED; isec->initialized = LABEL_INITIALIZED;
@ -3180,7 +3195,7 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
u32 size; u32 size;
int error; int error;
char *context = NULL; char *context = NULL;
struct inode_security_struct *isec = inode_security(inode); struct inode_security_struct *isec;
if (strcmp(name, XATTR_SELINUX_SUFFIX)) if (strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -3198,7 +3213,8 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
SECURITY_CAP_NOAUDIT); SECURITY_CAP_NOAUDIT);
if (!error) if (!error)
error = cred_has_capability(current_cred(), CAP_MAC_ADMIN, error = cred_has_capability(current_cred(), CAP_MAC_ADMIN,
SECURITY_CAP_NOAUDIT); SECURITY_CAP_NOAUDIT, true);
isec = inode_security(inode);
if (!error) if (!error)
error = security_sid_to_context_force(isec->sid, &context, error = security_sid_to_context_force(isec->sid, &context,
&size); &size);
@ -3219,7 +3235,7 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
static int selinux_inode_setsecurity(struct inode *inode, const char *name, static int selinux_inode_setsecurity(struct inode *inode, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags)
{ {
struct inode_security_struct *isec = inode_security(inode); struct inode_security_struct *isec = inode_security_novalidate(inode);
u32 newsid; u32 newsid;
int rc; int rc;
@ -3308,7 +3324,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
struct common_audit_data ad; struct common_audit_data ad;
struct file_security_struct *fsec = file->f_security; struct file_security_struct *fsec = file->f_security;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct inode_security_struct *isec = inode_security(inode); struct inode_security_struct *isec;
struct lsm_ioctlop_audit ioctl; struct lsm_ioctlop_audit ioctl;
u32 ssid = cred_sid(cred); u32 ssid = cred_sid(cred);
int rc; int rc;
@ -3332,6 +3348,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
if (unlikely(IS_PRIVATE(inode))) if (unlikely(IS_PRIVATE(inode)))
return 0; return 0;
isec = inode_security(inode);
rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,
requested, driver, xperm, &ad); requested, driver, xperm, &ad);
out: out:
@ -3373,7 +3390,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
case KDSKBENT: case KDSKBENT:
case KDSKBSENT: case KDSKBSENT:
error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
SECURITY_CAP_AUDIT); SECURITY_CAP_AUDIT, true);
break; break;
/* default case assumes that the command will go /* default case assumes that the command will go
@ -3462,8 +3479,9 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
vma->vm_end <= vma->vm_mm->brk) { vma->vm_end <= vma->vm_mm->brk) {
rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
} else if (!vma->vm_file && } else if (!vma->vm_file &&
vma->vm_start <= vma->vm_mm->start_stack && ((vma->vm_start <= vma->vm_mm->start_stack &&
vma->vm_end >= vma->vm_mm->start_stack) { vma->vm_end >= vma->vm_mm->start_stack) ||
vma_is_stack_for_task(vma, current))) {
rc = current_has_perm(current, PROCESS__EXECSTACK); rc = current_has_perm(current, PROCESS__EXECSTACK);
} else if (vma->vm_file && vma->anon_vma) { } else if (vma->vm_file && vma->anon_vma) {
/* /*
@ -3719,6 +3737,52 @@ static int selinux_kernel_module_request(char *kmod_name)
SYSTEM__MODULE_REQUEST, &ad); SYSTEM__MODULE_REQUEST, &ad);
} }
static int selinux_kernel_module_from_file(struct file *file)
{
struct common_audit_data ad;
struct inode_security_struct *isec;
struct file_security_struct *fsec;
u32 sid = current_sid();
int rc;
/* init_module */
if (file == NULL)
return avc_has_perm(sid, sid, SECCLASS_SYSTEM,
SYSTEM__MODULE_LOAD, NULL);
/* finit_module */
ad.type = LSM_AUDIT_DATA_PATH;
ad.u.path = file->f_path;
fsec = file->f_security;
if (sid != fsec->sid) {
rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
if (rc)
return rc;
}
isec = inode_security(file_inode(file));
return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM,
SYSTEM__MODULE_LOAD, &ad);
}
static int selinux_kernel_read_file(struct file *file,
enum kernel_read_file_id id)
{
int rc = 0;
switch (id) {
case READING_MODULE:
rc = selinux_kernel_module_from_file(file);
break;
default:
break;
}
return rc;
}
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{ {
return current_has_perm(p, PROCESS__SETPGID); return current_has_perm(p, PROCESS__SETPGID);
@ -4598,6 +4662,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
{ {
u32 peer_secid = SECSID_NULL; u32 peer_secid = SECSID_NULL;
u16 family; u16 family;
struct inode_security_struct *isec;
if (skb && skb->protocol == htons(ETH_P_IP)) if (skb && skb->protocol == htons(ETH_P_IP))
family = PF_INET; family = PF_INET;
@ -4608,9 +4673,10 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
else else
goto out; goto out;
if (sock && family == PF_UNIX) if (sock && family == PF_UNIX) {
selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid); isec = inode_security_novalidate(SOCK_INODE(sock));
else if (skb) peer_secid = isec->sid;
} else if (skb)
selinux_skb_peerlbl_sid(skb, family, &peer_secid); selinux_skb_peerlbl_sid(skb, family, &peer_secid);
out: out:
@ -5675,7 +5741,6 @@ static int selinux_setprocattr(struct task_struct *p,
char *name, void *value, size_t size) char *name, void *value, size_t size)
{ {
struct task_security_struct *tsec; struct task_security_struct *tsec;
struct task_struct *tracer;
struct cred *new; struct cred *new;
u32 sid = 0, ptsid; u32 sid = 0, ptsid;
int error; int error;
@ -5782,14 +5847,8 @@ static int selinux_setprocattr(struct task_struct *p,
/* Check for ptracing, and update the task SID if ok. /* Check for ptracing, and update the task SID if ok.
Otherwise, leave SID unchanged and fail. */ Otherwise, leave SID unchanged and fail. */
ptsid = 0; ptsid = ptrace_parent_sid(p);
rcu_read_lock(); if (ptsid != 0) {
tracer = ptrace_parent(p);
if (tracer)
ptsid = task_sid(tracer);
rcu_read_unlock();
if (tracer) {
error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
PROCESS__PTRACE, NULL); PROCESS__PTRACE, NULL);
if (error) if (error)
@ -6020,6 +6079,7 @@ static struct security_hook_list selinux_hooks[] = {
LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as), LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as), LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request), LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
LSM_HOOK_INIT(kernel_read_file, selinux_kernel_read_file),
LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid), LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid), LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
LSM_HOOK_INIT(task_getsid, selinux_task_getsid), LSM_HOOK_INIT(task_getsid, selinux_task_getsid),

View file

@ -12,6 +12,18 @@
#define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \ #define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \
"write", "associate", "unix_read", "unix_write" "write", "associate", "unix_read", "unix_write"
#define COMMON_CAP_PERMS "chown", "dac_override", "dac_read_search", \
"fowner", "fsetid", "kill", "setgid", "setuid", "setpcap", \
"linux_immutable", "net_bind_service", "net_broadcast", \
"net_admin", "net_raw", "ipc_lock", "ipc_owner", "sys_module", \
"sys_rawio", "sys_chroot", "sys_ptrace", "sys_pacct", "sys_admin", \
"sys_boot", "sys_nice", "sys_resource", "sys_time", \
"sys_tty_config", "mknod", "lease", "audit_write", \
"audit_control", "setfcap"
#define COMMON_CAP2_PERMS "mac_override", "mac_admin", "syslog", \
"wake_alarm", "block_suspend", "audit_read"
/* /*
* Note: The name for any socket class should be suffixed by "socket", * Note: The name for any socket class should be suffixed by "socket",
* and doesn't contain more than one substr of "socket". * and doesn't contain more than one substr of "socket".
@ -32,16 +44,9 @@ struct security_class_mapping secclass_map[] = {
"setsockcreate", NULL } }, "setsockcreate", NULL } },
{ "system", { "system",
{ "ipc_info", "syslog_read", "syslog_mod", { "ipc_info", "syslog_read", "syslog_mod",
"syslog_console", "module_request", NULL } }, "syslog_console", "module_request", "module_load", NULL } },
{ "capability", { "capability",
{ "chown", "dac_override", "dac_read_search", { COMMON_CAP_PERMS, NULL } },
"fowner", "fsetid", "kill", "setgid", "setuid", "setpcap",
"linux_immutable", "net_bind_service", "net_broadcast",
"net_admin", "net_raw", "ipc_lock", "ipc_owner", "sys_module",
"sys_rawio", "sys_chroot", "sys_ptrace", "sys_pacct", "sys_admin",
"sys_boot", "sys_nice", "sys_resource", "sys_time",
"sys_tty_config", "mknod", "lease", "audit_write",
"audit_control", "setfcap", NULL } },
{ "filesystem", { "filesystem",
{ "mount", "remount", "unmount", "getattr", { "mount", "remount", "unmount", "getattr",
"relabelfrom", "relabelto", "associate", "quotamod", "relabelfrom", "relabelto", "associate", "quotamod",
@ -150,12 +155,15 @@ struct security_class_mapping secclass_map[] = {
{ "memprotect", { "mmap_zero", NULL } }, { "memprotect", { "mmap_zero", NULL } },
{ "peer", { "recv", NULL } }, { "peer", { "recv", NULL } },
{ "capability2", { "capability2",
{ "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", { COMMON_CAP2_PERMS, NULL } },
"audit_read", NULL } },
{ "kernel_service", { "use_as_override", "create_files_as", NULL } }, { "kernel_service", { "use_as_override", "create_files_as", NULL } },
{ "tun_socket", { "tun_socket",
{ COMMON_SOCK_PERMS, "attach_queue", NULL } }, { COMMON_SOCK_PERMS, "attach_queue", NULL } },
{ "binder", { "impersonate", "call", "set_context_mgr", "transfer", { "binder", { "impersonate", "call", "set_context_mgr", "transfer",
NULL } }, NULL } },
{ "cap_userns",
{ COMMON_CAP_PERMS, NULL } },
{ "cap2_userns",
{ COMMON_CAP2_PERMS, NULL } },
{ NULL } { NULL }
}; };

View file

@ -17,6 +17,6 @@ int security_get_bools(int *len, char ***names, int **values);
int security_set_bools(int len, int *values); int security_set_bools(int len, int *values);
int security_get_bool_value(int bool); int security_get_bool_value(int index);
#endif #endif

View file

@ -38,9 +38,8 @@ struct task_security_struct {
}; };
enum label_initialized { enum label_initialized {
LABEL_MISSING, /* not initialized */ LABEL_INVALID, /* invalid or not initialized */
LABEL_INITIALIZED, /* inizialized */ LABEL_INITIALIZED /* initialized */
LABEL_INVALID /* invalid */
}; };
struct inode_security_struct { struct inode_security_struct {

View file

@ -2696,7 +2696,7 @@ int security_set_bools(int len, int *values)
return rc; return rc;
} }
int security_get_bool_value(int bool) int security_get_bool_value(int index)
{ {
int rc; int rc;
int len; int len;
@ -2705,10 +2705,10 @@ int security_get_bool_value(int bool)
rc = -EFAULT; rc = -EFAULT;
len = policydb.p_bools.nprim; len = policydb.p_bools.nprim;
if (bool >= len) if (index >= len)
goto out; goto out;
rc = policydb.bool_val_to_struct[bool]->state; rc = policydb.bool_val_to_struct[index]->state;
out: out:
read_unlock(&policy_rwlock); read_unlock(&policy_rwlock);
return rc; return rc;