selinux/stable-5.7 PR 20200330
-----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAl6Ch6wUHHBhdWxAcGF1 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXPdcg/9FDMS/n0Xl1HQBUyu26EwLu3aUpNE BdghXW1LKSTp7MrOENE60PGzZSAiC07ci1DqFd7zfLPZf2q5IwPwOBa/Avy8z95V oHKqcMT6WO1SPOm/PxZn16FCKyET4gZDTXvHBAyiyFsbk36R522ZY615P9T3eLu/ ZA1NFsSjj68SqMCUlAWfeqjcbQiX63bryEpugOIg0qWy7R/+rtWxj9TjriZ+v9tq uC45UcjBqphpmoPG8BifA3jjyclwO3DeQb5u7E8//HPPraGeB19ntsymUg7ljoGk NrqCkZtv6E+FRCDTR5f0O7M1T4BWJodxw2NwngnTwKByLC25EZaGx80o+VyMt0eT Pog+++JZaa5zZr2OYOtdlPVMLc2ALL6p/8lHOqFU3GKfIf04hWOm6/Lb2IWoXs3f CG2b6vzoXYyjbF0Q7kxadb8uBY2S1Ds+CVu2HMBBsXsPdwbbtFWOT/6aRAQu61qn PW+f47NR8By3SO6nMzWts2SZEERZNIEdSKeXHuR7As1jFMXrHLItreb4GCSPay5h 2bzRpxt2br5CDLh7Jv2pZnHtUqBWOSbslTix77+Z/hPKaNowvD9v3tc5hX87rDmB dYXROD6/KoyXFYDcMdphlvORFhqGqd5bEYuHHum/VjSIRh237+/nxFY/vZ4i4bzU 2fvpAmUlVX1c4rw= =LlWA -----END PGP SIGNATURE----- Merge tag 'selinux-pr-20200330' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux Pull SELinux updates from Paul Moore: "We've got twenty SELinux patches for the v5.7 merge window, the highlights are below: - Deprecate setting /sys/fs/selinux/checkreqprot to 1. This flag was originally created to deal with legacy userspace and the READ_IMPLIES_EXEC personality flag. We changed the default from 1 to 0 back in Linux v4.4 and now we are taking the next step of deprecating it, at some point in the future we will take the final step of rejecting 1. - Allow kernfs symlinks to inherit the SELinux label of the parent directory. In order to preserve backwards compatibility this is protected by the genfs_seclabel_symlinks SELinux policy capability. - Optimize how we store filename transitions in the kernel, resulting in some significant improvements to policy load times. - Do a better job calculating our internal hash table sizes which resulted in additional policy load improvements and likely general SELinux performance improvements as well. - Remove the unused initial SIDs (labels) and improve how we handle initial SIDs. - Enable per-file labeling for the bpf filesystem. - Ensure that we properly label NFS v4.2 filesystems to avoid a temporary unlabeled condition. - Add some missing XFS quota command types to the SELinux quota access controls. - Fix a problem where we were not updating the seq_file position index correctly in selinuxfs. - We consolidate some duplicated code into helper functions. - A number of list to array conversions. - Update Stephen Smalley's email address in MAINTAINERS" * tag 'selinux-pr-20200330' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux: selinux: clean up indentation issue with assignment statement NFS: Ensure security label is set for root inode MAINTAINERS: Update my email address selinux: avtab_init() and cond_policydb_init() return void selinux: clean up error path in policydb_init() selinux: remove unused initial SIDs and improve handling selinux: reduce the use of hard-coded hash sizes selinux: Add xfs quota command types selinux: optimize storage of filename transitions selinux: factor out loop body from filename_trans_read() security: selinux: allow per-file labeling for bpffs selinux: generalize evaluate_cond_node() selinux: convert cond_expr to array selinux: convert cond_av_list to array selinux: convert cond_list to array selinux: sel_avc_get_stat_idx should increase position index selinux: allow kernfs symlinks to inherit parent directory context selinux: simplify evaluate_cond_node() Documentation,selinux: deprecate setting checkreqprot to 1 selinux: move status variables out of selinux_ss
This commit is contained in:
commit
b3aa112d57
23
Documentation/ABI/obsolete/sysfs-selinux-checkreqprot
Normal file
23
Documentation/ABI/obsolete/sysfs-selinux-checkreqprot
Normal file
@ -0,0 +1,23 @@
|
||||
What: /sys/fs/selinux/checkreqprot
|
||||
Date: April 2005 (predates git)
|
||||
KernelVersion: 2.6.12-rc2 (predates git)
|
||||
Contact: selinux@vger.kernel.org
|
||||
Description:
|
||||
|
||||
The selinuxfs "checkreqprot" node allows SELinux to be configured
|
||||
to check the protection requested by userspace for mmap/mprotect
|
||||
calls instead of the actual protection applied by the kernel.
|
||||
This was a compatibility mechanism for legacy userspace and
|
||||
for the READ_IMPLIES_EXEC personality flag. However, if set to
|
||||
1, it weakens security by allowing mappings to be made executable
|
||||
without authorization by policy. The default value of checkreqprot
|
||||
at boot was changed starting in Linux v4.4 to 0 (i.e. check the
|
||||
actual protection), and Android and Linux distributions have been
|
||||
explicitly writing a "0" to /sys/fs/selinux/checkreqprot during
|
||||
initialization for some time. Support for setting checkreqprot to 1
|
||||
will be removed in a future kernel release, at which point the kernel
|
||||
will always cease using checkreqprot internally and will always
|
||||
check the actual protections being applied upon mmap/mprotect calls.
|
||||
The checkreqprot selinuxfs node will remain for backward compatibility
|
||||
but will discard writes of the "0" value and will reject writes of the
|
||||
"1" value when this mechanism is removed.
|
@ -525,6 +525,7 @@
|
||||
Default value is set via a kernel config option.
|
||||
Value can be changed at runtime via
|
||||
/sys/fs/selinux/checkreqprot.
|
||||
Setting checkreqprot to 1 is deprecated.
|
||||
|
||||
cio_ignore= [S390]
|
||||
See Documentation/s390/common_io.rst for details.
|
||||
|
@ -15027,7 +15027,7 @@ X: security/selinux/
|
||||
|
||||
SELINUX SECURITY MODULE
|
||||
M: Paul Moore <paul@paul-moore.com>
|
||||
M: Stephen Smalley <sds@tycho.nsa.gov>
|
||||
M: Stephen Smalley <stephen.smalley.work@gmail.com>
|
||||
M: Eric Paris <eparis@parisplace.org>
|
||||
L: selinux@vger.kernel.org
|
||||
W: https://selinuxproject.org
|
||||
@ -15039,6 +15039,7 @@ F: security/selinux/
|
||||
F: scripts/selinux/
|
||||
F: Documentation/admin-guide/LSM/SELinux.rst
|
||||
F: Documentation/ABI/obsolete/sysfs-selinux-disable
|
||||
F: Documentation/ABI/obsolete/sysfs-selinux-checkreqprot
|
||||
|
||||
SENSABLE PHANTOM
|
||||
M: Jiri Slaby <jirislaby@gmail.com>
|
||||
|
@ -73,6 +73,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
|
||||
struct inode *inode;
|
||||
char *name;
|
||||
int error = -ENOMEM;
|
||||
unsigned long kflags = 0, kflags_out = 0;
|
||||
|
||||
name = kstrdup(fc->source, GFP_KERNEL);
|
||||
if (!name)
|
||||
@ -83,11 +84,14 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
|
||||
if (fsinfo.fattr == NULL)
|
||||
goto out_name;
|
||||
|
||||
fsinfo.fattr->label = nfs4_label_alloc(server, GFP_KERNEL);
|
||||
if (IS_ERR(fsinfo.fattr->label))
|
||||
goto out_fattr;
|
||||
error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo);
|
||||
if (error < 0) {
|
||||
dprintk("nfs_get_root: getattr error = %d\n", -error);
|
||||
nfs_errorf(fc, "NFS: Couldn't getattr on root");
|
||||
goto out_fattr;
|
||||
goto out_label;
|
||||
}
|
||||
|
||||
inode = nfs_fhget(s, ctx->mntfh, fsinfo.fattr, NULL);
|
||||
@ -95,12 +99,12 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
|
||||
dprintk("nfs_get_root: get root inode failed\n");
|
||||
error = PTR_ERR(inode);
|
||||
nfs_errorf(fc, "NFS: Couldn't get root inode");
|
||||
goto out_fattr;
|
||||
goto out_label;
|
||||
}
|
||||
|
||||
error = nfs_superblock_set_dummy_root(s, inode);
|
||||
if (error != 0)
|
||||
goto out_fattr;
|
||||
goto out_label;
|
||||
|
||||
/* root dentries normally start off anonymous and get spliced in later
|
||||
* if the dentry tree reaches them; however if the dentry already
|
||||
@ -111,7 +115,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
|
||||
dprintk("nfs_get_root: get root dentry failed\n");
|
||||
error = PTR_ERR(root);
|
||||
nfs_errorf(fc, "NFS: Couldn't get root dentry");
|
||||
goto out_fattr;
|
||||
goto out_label;
|
||||
}
|
||||
|
||||
security_d_instantiate(root, inode);
|
||||
@ -123,12 +127,39 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
|
||||
}
|
||||
spin_unlock(&root->d_lock);
|
||||
fc->root = root;
|
||||
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
|
||||
kflags |= SECURITY_LSM_NATIVE_LABELS;
|
||||
if (ctx->clone_data.sb) {
|
||||
if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
|
||||
error = -ESTALE;
|
||||
goto error_splat_root;
|
||||
}
|
||||
/* clone lsm security options from the parent to the new sb */
|
||||
error = security_sb_clone_mnt_opts(ctx->clone_data.sb,
|
||||
s, kflags, &kflags_out);
|
||||
} else {
|
||||
error = security_sb_set_mnt_opts(s, fc->security,
|
||||
kflags, &kflags_out);
|
||||
}
|
||||
if (error)
|
||||
goto error_splat_root;
|
||||
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
|
||||
!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
|
||||
NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
|
||||
|
||||
nfs_setsecurity(inode, fsinfo.fattr, fsinfo.fattr->label);
|
||||
error = 0;
|
||||
|
||||
out_label:
|
||||
nfs4_label_free(fsinfo.fattr->label);
|
||||
out_fattr:
|
||||
nfs_free_fattr(fsinfo.fattr);
|
||||
out_name:
|
||||
kfree(name);
|
||||
out:
|
||||
return error;
|
||||
error_splat_root:
|
||||
dput(fc->root);
|
||||
fc->root = NULL;
|
||||
goto out_label;
|
||||
}
|
||||
|
@ -4002,7 +4002,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
|
||||
{
|
||||
int error;
|
||||
struct nfs_fattr *fattr = info->fattr;
|
||||
struct nfs4_label *label = NULL;
|
||||
struct nfs4_label *label = fattr->label;
|
||||
|
||||
error = nfs4_server_capabilities(server, mntfh);
|
||||
if (error < 0) {
|
||||
@ -4010,23 +4010,17 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
|
||||
return error;
|
||||
}
|
||||
|
||||
label = nfs4_label_alloc(server, GFP_KERNEL);
|
||||
if (IS_ERR(label))
|
||||
return PTR_ERR(label);
|
||||
|
||||
error = nfs4_proc_getattr(server, mntfh, fattr, label, NULL);
|
||||
if (error < 0) {
|
||||
dprintk("nfs4_get_root: getattr error = %d\n", -error);
|
||||
goto err_free_label;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fattr->valid & NFS_ATTR_FATTR_FSID &&
|
||||
!nfs_fsid_equal(&server->fsid, &fattr->fsid))
|
||||
memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
|
||||
|
||||
err_free_label:
|
||||
nfs4_label_free(label);
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1179,7 +1179,6 @@ int nfs_get_tree_common(struct fs_context *fc)
|
||||
struct super_block *s;
|
||||
int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super;
|
||||
struct nfs_server *server = ctx->server;
|
||||
unsigned long kflags = 0, kflags_out = 0;
|
||||
int error;
|
||||
|
||||
ctx->server = NULL;
|
||||
@ -1239,26 +1238,6 @@ int nfs_get_tree_common(struct fs_context *fc)
|
||||
goto error_splat_super;
|
||||
}
|
||||
|
||||
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
|
||||
kflags |= SECURITY_LSM_NATIVE_LABELS;
|
||||
if (ctx->clone_data.sb) {
|
||||
if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
|
||||
error = -ESTALE;
|
||||
goto error_splat_root;
|
||||
}
|
||||
/* clone any lsm security options from the parent to the new sb */
|
||||
error = security_sb_clone_mnt_opts(ctx->clone_data.sb, s, kflags,
|
||||
&kflags_out);
|
||||
} else {
|
||||
error = security_sb_set_mnt_opts(s, fc->security,
|
||||
kflags, &kflags_out);
|
||||
}
|
||||
if (error)
|
||||
goto error_splat_root;
|
||||
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
|
||||
!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
|
||||
NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
|
||||
|
||||
s->s_flags |= SB_ACTIVE;
|
||||
error = 0;
|
||||
|
||||
@ -1268,10 +1247,6 @@ out:
|
||||
out_err_nosb:
|
||||
nfs_free_server(server);
|
||||
goto out;
|
||||
|
||||
error_splat_root:
|
||||
dput(fc->root);
|
||||
fc->root = NULL;
|
||||
error_splat_super:
|
||||
deactivate_locked_super(s);
|
||||
goto out;
|
||||
|
@ -75,6 +75,7 @@ struct nfs_fattr {
|
||||
struct nfs4_string *owner_name;
|
||||
struct nfs4_string *group_name;
|
||||
struct nfs4_threshold *mdsthreshold; /* pNFS threshold hints */
|
||||
struct nfs4_label *label;
|
||||
};
|
||||
|
||||
#define NFS_ATTR_FATTR_TYPE (1U << 0)
|
||||
|
@ -67,8 +67,12 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
isids_len = sizeof(initial_sid_to_string) / sizeof (char *);
|
||||
for (i = 1; i < isids_len; i++)
|
||||
initial_sid_to_string[i] = stoupperx(initial_sid_to_string[i]);
|
||||
for (i = 1; i < isids_len; i++) {
|
||||
const char *s = initial_sid_to_string[i];
|
||||
|
||||
if (s)
|
||||
initial_sid_to_string[i] = stoupperx(s);
|
||||
}
|
||||
|
||||
fprintf(fout, "/* This file is automatically generated. Do not edit. */\n");
|
||||
fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define _SELINUX_FLASK_H_\n\n");
|
||||
@ -82,7 +86,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
for (i = 1; i < isids_len; i++) {
|
||||
const char *s = initial_sid_to_string[i];
|
||||
fprintf(fout, "#define SECINITSID_%-39s %2d\n", s, i);
|
||||
if (s)
|
||||
fprintf(fout, "#define SECINITSID_%-39s %2d\n", s, i);
|
||||
}
|
||||
fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1);
|
||||
fprintf(fout, "\nstatic inline bool security_is_socket_class(u16 kern_tclass)\n");
|
||||
|
@ -88,6 +88,9 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
|
||||
'checkreqprot=' boot parameter. It may also be changed at runtime
|
||||
via /sys/fs/selinux/checkreqprot if authorized by policy.
|
||||
|
||||
WARNING: this option is deprecated and will be removed in a future
|
||||
kernel release.
|
||||
|
||||
If you are unsure how to answer this question, answer 0.
|
||||
|
||||
config SECURITY_SELINUX_SIDTAB_HASH_BITS
|
||||
|
@ -6,9 +6,9 @@
|
||||
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
|
||||
|
||||
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
|
||||
netnode.o netport.o \
|
||||
netnode.o netport.o status.o \
|
||||
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
|
||||
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o
|
||||
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o
|
||||
|
||||
selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
|
||||
|
||||
|
@ -142,8 +142,11 @@ static int __init checkreqprot_setup(char *str)
|
||||
{
|
||||
unsigned long checkreqprot;
|
||||
|
||||
if (!kstrtoul(str, 0, &checkreqprot))
|
||||
if (!kstrtoul(str, 0, &checkreqprot)) {
|
||||
selinux_checkreqprot_boot = checkreqprot ? 1 : 0;
|
||||
if (checkreqprot)
|
||||
pr_warn("SELinux: checkreqprot set to 1 via kernel parameter. This is deprecated and will be rejected in a future kernel release.\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
__setup("checkreqprot=", checkreqprot_setup);
|
||||
@ -699,6 +702,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
||||
if (!strcmp(sb->s_type->name, "debugfs") ||
|
||||
!strcmp(sb->s_type->name, "tracefs") ||
|
||||
!strcmp(sb->s_type->name, "binder") ||
|
||||
!strcmp(sb->s_type->name, "bpf") ||
|
||||
!strcmp(sb->s_type->name, "pstore"))
|
||||
sbsec->flags |= SE_SBGENFS;
|
||||
|
||||
@ -1475,7 +1479,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
|
||||
/* Default to the fs superblock SID. */
|
||||
sid = sbsec->sid;
|
||||
|
||||
if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
|
||||
if ((sbsec->flags & SE_SBGENFS) &&
|
||||
(!S_ISLNK(inode->i_mode) ||
|
||||
selinux_policycap_genfs_seclabel_symlinks())) {
|
||||
/* We must have a dentry to determine the label on
|
||||
* procfs inodes */
|
||||
if (opt_dentry) {
|
||||
@ -2139,11 +2145,18 @@ static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
|
||||
case Q_QUOTAOFF:
|
||||
case Q_SETINFO:
|
||||
case Q_SETQUOTA:
|
||||
case Q_XQUOTAOFF:
|
||||
case Q_XQUOTAON:
|
||||
case Q_XSETQLIM:
|
||||
rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
|
||||
break;
|
||||
case Q_GETFMT:
|
||||
case Q_GETINFO:
|
||||
case Q_GETQUOTA:
|
||||
case Q_XGETQUOTA:
|
||||
case Q_XGETQSTAT:
|
||||
case Q_XGETQSTATV:
|
||||
case Q_XGETNEXTQUOTA:
|
||||
rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
|
||||
break;
|
||||
default:
|
||||
@ -7161,6 +7174,7 @@ static __init int selinux_init(void)
|
||||
selinux_state.checkreqprot = selinux_checkreqprot_boot;
|
||||
selinux_ss_init(&selinux_state.ss);
|
||||
selinux_avc_init(&selinux_state.avc);
|
||||
mutex_init(&selinux_state.status_lock);
|
||||
|
||||
/* Set the security state for the initial task. */
|
||||
cred_init_security();
|
||||
|
@ -14,12 +14,10 @@
|
||||
#include "security.h"
|
||||
|
||||
int security_get_bools(struct selinux_state *state,
|
||||
int *len, char ***names, int **values);
|
||||
u32 *len, char ***names, int **values);
|
||||
|
||||
int security_set_bools(struct selinux_state *state,
|
||||
int len, int *values);
|
||||
int security_set_bools(struct selinux_state *state, u32 len, int *values);
|
||||
|
||||
int security_get_bool_value(struct selinux_state *state,
|
||||
int index);
|
||||
int security_get_bool_value(struct selinux_state *state, u32 index);
|
||||
|
||||
#endif
|
||||
|
@ -1,34 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* This file is automatically generated. Do not edit. */
|
||||
static const char *initial_sid_to_string[] =
|
||||
{
|
||||
"null",
|
||||
"kernel",
|
||||
"security",
|
||||
"unlabeled",
|
||||
"fs",
|
||||
"file",
|
||||
"file_labels",
|
||||
"init",
|
||||
"any_socket",
|
||||
"port",
|
||||
"netif",
|
||||
"netmsg",
|
||||
"node",
|
||||
"igmp_packet",
|
||||
"icmp_socket",
|
||||
"tcp_socket",
|
||||
"sysctl_modprobe",
|
||||
"sysctl",
|
||||
"sysctl_fs",
|
||||
"sysctl_kernel",
|
||||
"sysctl_net",
|
||||
"sysctl_net_unix",
|
||||
"sysctl_vm",
|
||||
"sysctl_dev",
|
||||
"kmod",
|
||||
"policy",
|
||||
"scmp_packet",
|
||||
"devnull",
|
||||
NULL,
|
||||
"kernel",
|
||||
"security",
|
||||
"unlabeled",
|
||||
NULL,
|
||||
"file",
|
||||
NULL,
|
||||
NULL,
|
||||
"any_socket",
|
||||
"port",
|
||||
"netif",
|
||||
"netmsg",
|
||||
"node",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"devnull",
|
||||
};
|
||||
|
||||
|
@ -79,6 +79,7 @@ enum {
|
||||
POLICYDB_CAPABILITY_ALWAYSNETWORK,
|
||||
POLICYDB_CAPABILITY_CGROUPSECLABEL,
|
||||
POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION,
|
||||
POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS,
|
||||
__POLICYDB_CAPABILITY_MAX
|
||||
};
|
||||
#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
|
||||
@ -108,6 +109,10 @@ struct selinux_state {
|
||||
bool checkreqprot;
|
||||
bool initialized;
|
||||
bool policycap[__POLICYDB_CAPABILITY_MAX];
|
||||
|
||||
struct page *status_page;
|
||||
struct mutex status_lock;
|
||||
|
||||
struct selinux_avc *avc;
|
||||
struct selinux_ss *ss;
|
||||
} __randomize_layout;
|
||||
@ -209,6 +214,13 @@ static inline bool selinux_policycap_nnp_nosuid_transition(void)
|
||||
return state->policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION];
|
||||
}
|
||||
|
||||
static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
|
||||
{
|
||||
struct selinux_state *state = &selinux_state;
|
||||
|
||||
return state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS];
|
||||
}
|
||||
|
||||
int security_mls_enabled(struct selinux_state *state);
|
||||
int security_load_policy(struct selinux_state *state,
|
||||
void *data, size_t len);
|
||||
|
@ -668,6 +668,14 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
|
||||
if (sscanf(page, "%u", &new_value) != 1)
|
||||
goto out;
|
||||
|
||||
if (new_value) {
|
||||
char comm[sizeof(current->comm)];
|
||||
|
||||
memcpy(comm, current->comm, sizeof(comm));
|
||||
pr_warn_once("SELinux: %s (%d) set checkreqprot to 1. This is deprecated and will be rejected in a future kernel release.\n",
|
||||
comm, current->pid);
|
||||
}
|
||||
|
||||
fsi->state->checkreqprot = new_value ? 1 : 0;
|
||||
length = count;
|
||||
out:
|
||||
@ -1327,14 +1335,14 @@ static void sel_remove_entries(struct dentry *de)
|
||||
|
||||
static int sel_make_bools(struct selinux_fs_info *fsi)
|
||||
{
|
||||
int i, ret;
|
||||
int ret;
|
||||
ssize_t len;
|
||||
struct dentry *dentry = NULL;
|
||||
struct dentry *dir = fsi->bool_dir;
|
||||
struct inode *inode = NULL;
|
||||
struct inode_security_struct *isec;
|
||||
char **names = NULL, *page;
|
||||
int num;
|
||||
u32 i, num;
|
||||
int *values = NULL;
|
||||
u32 sid;
|
||||
|
||||
@ -1536,6 +1544,7 @@ static struct avc_cache_stats *sel_avc_get_stat_idx(loff_t *idx)
|
||||
*idx = cpu + 1;
|
||||
return &per_cpu(avc_cache_stats, cpu);
|
||||
}
|
||||
(*idx)++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1692,7 +1701,11 @@ static int sel_make_initcon_files(struct dentry *dir)
|
||||
for (i = 1; i <= SECINITSID_NUM; i++) {
|
||||
struct inode *inode;
|
||||
struct dentry *dentry;
|
||||
dentry = d_alloc_name(dir, security_get_initial_sid_context(i));
|
||||
const char *s = security_get_initial_sid_context(i);
|
||||
|
||||
if (!s)
|
||||
continue;
|
||||
dentry = d_alloc_name(dir, s);
|
||||
if (!dentry)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -299,12 +299,11 @@ void avtab_destroy(struct avtab *h)
|
||||
h->mask = 0;
|
||||
}
|
||||
|
||||
int avtab_init(struct avtab *h)
|
||||
void avtab_init(struct avtab *h)
|
||||
{
|
||||
kvfree(h->htable);
|
||||
h->htable = NULL;
|
||||
h->nel = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int avtab_alloc(struct avtab *h, u32 nrules)
|
||||
|
@ -87,7 +87,7 @@ struct avtab {
|
||||
u32 mask; /* mask to compute hash func */
|
||||
};
|
||||
|
||||
int avtab_init(struct avtab *);
|
||||
void avtab_init(struct avtab *h);
|
||||
int avtab_alloc(struct avtab *, u32);
|
||||
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
|
||||
void avtab_destroy(struct avtab *h);
|
||||
|
@ -23,18 +23,19 @@
|
||||
*/
|
||||
static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
|
||||
{
|
||||
|
||||
struct cond_expr *cur;
|
||||
u32 i;
|
||||
int s[COND_EXPR_MAXDEPTH];
|
||||
int sp = -1;
|
||||
|
||||
for (cur = expr; cur; cur = cur->next) {
|
||||
switch (cur->expr_type) {
|
||||
for (i = 0; i < expr->len; i++) {
|
||||
struct cond_expr_node *node = &expr->nodes[i];
|
||||
|
||||
switch (node->expr_type) {
|
||||
case COND_BOOL:
|
||||
if (sp == (COND_EXPR_MAXDEPTH - 1))
|
||||
return -1;
|
||||
sp++;
|
||||
s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
|
||||
s[sp] = p->bool_val_to_struct[node->bool - 1]->state;
|
||||
break;
|
||||
case COND_NOT:
|
||||
if (sp < 0)
|
||||
@ -85,90 +86,76 @@ static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
|
||||
* list appropriately. If the result of the expression is undefined
|
||||
* all of the rules are disabled for safety.
|
||||
*/
|
||||
int evaluate_cond_node(struct policydb *p, struct cond_node *node)
|
||||
static void evaluate_cond_node(struct policydb *p, struct cond_node *node)
|
||||
{
|
||||
struct avtab_node *avnode;
|
||||
int new_state;
|
||||
struct cond_av_list *cur;
|
||||
u32 i;
|
||||
|
||||
new_state = cond_evaluate_expr(p, node->expr);
|
||||
new_state = cond_evaluate_expr(p, &node->expr);
|
||||
if (new_state != node->cur_state) {
|
||||
node->cur_state = new_state;
|
||||
if (new_state == -1)
|
||||
pr_err("SELinux: expression result was undefined - disabling all rules.\n");
|
||||
/* turn the rules on or off */
|
||||
for (cur = node->true_list; cur; cur = cur->next) {
|
||||
for (i = 0; i < node->true_list.len; i++) {
|
||||
avnode = node->true_list.nodes[i];
|
||||
if (new_state <= 0)
|
||||
cur->node->key.specified &= ~AVTAB_ENABLED;
|
||||
avnode->key.specified &= ~AVTAB_ENABLED;
|
||||
else
|
||||
cur->node->key.specified |= AVTAB_ENABLED;
|
||||
avnode->key.specified |= AVTAB_ENABLED;
|
||||
}
|
||||
|
||||
for (cur = node->false_list; cur; cur = cur->next) {
|
||||
for (i = 0; i < node->false_list.len; i++) {
|
||||
avnode = node->false_list.nodes[i];
|
||||
/* -1 or 1 */
|
||||
if (new_state)
|
||||
cur->node->key.specified &= ~AVTAB_ENABLED;
|
||||
avnode->key.specified &= ~AVTAB_ENABLED;
|
||||
else
|
||||
cur->node->key.specified |= AVTAB_ENABLED;
|
||||
avnode->key.specified |= AVTAB_ENABLED;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cond_policydb_init(struct policydb *p)
|
||||
void evaluate_cond_nodes(struct policydb *p)
|
||||
{
|
||||
int rc;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < p->cond_list_len; i++)
|
||||
evaluate_cond_node(p, &p->cond_list[i]);
|
||||
}
|
||||
|
||||
void cond_policydb_init(struct policydb *p)
|
||||
{
|
||||
p->bool_val_to_struct = NULL;
|
||||
p->cond_list = NULL;
|
||||
p->cond_list_len = 0;
|
||||
|
||||
rc = avtab_init(&p->te_cond_avtab);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cond_av_list_destroy(struct cond_av_list *list)
|
||||
{
|
||||
struct cond_av_list *cur, *next;
|
||||
for (cur = list; cur; cur = next) {
|
||||
next = cur->next;
|
||||
/* the avtab_ptr_t node is destroy by the avtab */
|
||||
kfree(cur);
|
||||
}
|
||||
avtab_init(&p->te_cond_avtab);
|
||||
}
|
||||
|
||||
static void cond_node_destroy(struct cond_node *node)
|
||||
{
|
||||
struct cond_expr *cur_expr, *next_expr;
|
||||
|
||||
for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) {
|
||||
next_expr = cur_expr->next;
|
||||
kfree(cur_expr);
|
||||
}
|
||||
cond_av_list_destroy(node->true_list);
|
||||
cond_av_list_destroy(node->false_list);
|
||||
kfree(node);
|
||||
kfree(node->expr.nodes);
|
||||
/* the avtab_ptr_t nodes are destroyed by the avtab */
|
||||
kfree(node->true_list.nodes);
|
||||
kfree(node->false_list.nodes);
|
||||
}
|
||||
|
||||
static void cond_list_destroy(struct cond_node *list)
|
||||
static void cond_list_destroy(struct policydb *p)
|
||||
{
|
||||
struct cond_node *next, *cur;
|
||||
u32 i;
|
||||
|
||||
if (list == NULL)
|
||||
return;
|
||||
|
||||
for (cur = list; cur; cur = next) {
|
||||
next = cur->next;
|
||||
cond_node_destroy(cur);
|
||||
}
|
||||
for (i = 0; i < p->cond_list_len; i++)
|
||||
cond_node_destroy(&p->cond_list[i]);
|
||||
kfree(p->cond_list);
|
||||
}
|
||||
|
||||
void cond_policydb_destroy(struct policydb *p)
|
||||
{
|
||||
kfree(p->bool_val_to_struct);
|
||||
avtab_destroy(&p->te_cond_avtab);
|
||||
cond_list_destroy(p->cond_list);
|
||||
cond_list_destroy(p);
|
||||
}
|
||||
|
||||
int cond_init_bool_indexes(struct policydb *p)
|
||||
@ -260,19 +247,18 @@ err:
|
||||
|
||||
struct cond_insertf_data {
|
||||
struct policydb *p;
|
||||
struct avtab_node **dst;
|
||||
struct cond_av_list *other;
|
||||
struct cond_av_list *head;
|
||||
struct cond_av_list *tail;
|
||||
};
|
||||
|
||||
static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
|
||||
{
|
||||
struct cond_insertf_data *data = ptr;
|
||||
struct policydb *p = data->p;
|
||||
struct cond_av_list *other = data->other, *list, *cur;
|
||||
struct cond_av_list *other = data->other;
|
||||
struct avtab_node *node_ptr;
|
||||
u8 found;
|
||||
int rc = -EINVAL;
|
||||
u32 i;
|
||||
bool found;
|
||||
|
||||
/*
|
||||
* For type rules we have to make certain there aren't any
|
||||
@ -282,7 +268,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
|
||||
if (k->specified & AVTAB_TYPE) {
|
||||
if (avtab_search(&p->te_avtab, k)) {
|
||||
pr_err("SELinux: type rule already exists outside of a conditional.\n");
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* If we are reading the false list other will be a pointer to
|
||||
@ -297,24 +283,24 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
|
||||
if (node_ptr) {
|
||||
if (avtab_search_node_next(node_ptr, k->specified)) {
|
||||
pr_err("SELinux: too many conflicting type rules.\n");
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
found = 0;
|
||||
for (cur = other; cur; cur = cur->next) {
|
||||
if (cur->node == node_ptr) {
|
||||
found = 1;
|
||||
found = false;
|
||||
for (i = 0; i < other->len; i++) {
|
||||
if (other->nodes[i] == node_ptr) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
pr_err("SELinux: conflicting type rules.\n");
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (avtab_search(&p->te_cond_avtab, k)) {
|
||||
pr_err("SELinux: conflicting type rules when adding type rule for true.\n");
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -322,39 +308,22 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
|
||||
node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
|
||||
if (!node_ptr) {
|
||||
pr_err("SELinux: could not insert rule.\n");
|
||||
rc = -ENOMEM;
|
||||
goto err;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
list = kzalloc(sizeof(*list), GFP_KERNEL);
|
||||
if (!list) {
|
||||
rc = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
list->node = node_ptr;
|
||||
if (!data->head)
|
||||
data->head = list;
|
||||
else
|
||||
data->tail->next = list;
|
||||
data->tail = list;
|
||||
*data->dst = node_ptr;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
cond_av_list_destroy(data->head);
|
||||
data->head = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
|
||||
static int cond_read_av_list(struct policydb *p, void *fp,
|
||||
struct cond_av_list *list,
|
||||
struct cond_av_list *other)
|
||||
{
|
||||
int i, rc;
|
||||
int rc;
|
||||
__le32 buf[1];
|
||||
u32 len;
|
||||
u32 i, len;
|
||||
struct cond_insertf_data data;
|
||||
|
||||
*ret_list = NULL;
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -363,22 +332,28 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list *
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
list->nodes = kcalloc(len, sizeof(*list->nodes), GFP_KERNEL);
|
||||
if (!list->nodes)
|
||||
return -ENOMEM;
|
||||
|
||||
data.p = p;
|
||||
data.other = other;
|
||||
data.head = NULL;
|
||||
data.tail = NULL;
|
||||
for (i = 0; i < len; i++) {
|
||||
data.dst = &list->nodes[i];
|
||||
rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
|
||||
&data);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
kfree(list->nodes);
|
||||
list->nodes = NULL;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
*ret_list = data.head;
|
||||
list->len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
|
||||
static int expr_node_isvalid(struct policydb *p, struct cond_expr_node *expr)
|
||||
{
|
||||
if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
|
||||
pr_err("SELinux: conditional expressions uses unknown operator.\n");
|
||||
@ -395,49 +370,43 @@ static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
|
||||
static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
|
||||
{
|
||||
__le32 buf[2];
|
||||
u32 len, i;
|
||||
u32 i, len;
|
||||
int rc;
|
||||
struct cond_expr *expr = NULL, *last = NULL;
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32) * 2);
|
||||
if (rc)
|
||||
goto err;
|
||||
return rc;
|
||||
|
||||
node->cur_state = le32_to_cpu(buf[0]);
|
||||
|
||||
/* expr */
|
||||
len = le32_to_cpu(buf[1]);
|
||||
node->expr.nodes = kcalloc(len, sizeof(*node->expr.nodes), GFP_KERNEL);
|
||||
if (!node->expr.nodes)
|
||||
return -ENOMEM;
|
||||
|
||||
node->expr.len = len;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
struct cond_expr_node *expr = &node->expr.nodes[i];
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32) * 2);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = -ENOMEM;
|
||||
expr = kzalloc(sizeof(*expr), GFP_KERNEL);
|
||||
if (!expr)
|
||||
goto err;
|
||||
|
||||
expr->expr_type = le32_to_cpu(buf[0]);
|
||||
expr->bool = le32_to_cpu(buf[1]);
|
||||
|
||||
if (!expr_isvalid(p, expr)) {
|
||||
if (!expr_node_isvalid(p, expr)) {
|
||||
rc = -EINVAL;
|
||||
kfree(expr);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
node->expr = expr;
|
||||
else
|
||||
last->next = expr;
|
||||
last = expr;
|
||||
}
|
||||
|
||||
rc = cond_read_av_list(p, fp, &node->true_list, NULL);
|
||||
if (rc)
|
||||
goto err;
|
||||
rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
|
||||
rc = cond_read_av_list(p, fp, &node->false_list, &node->true_list);
|
||||
if (rc)
|
||||
goto err;
|
||||
return 0;
|
||||
@ -448,7 +417,6 @@ err:
|
||||
|
||||
int cond_read_list(struct policydb *p, void *fp)
|
||||
{
|
||||
struct cond_node *node, *last = NULL;
|
||||
__le32 buf[1];
|
||||
u32 i, len;
|
||||
int rc;
|
||||
@ -459,29 +427,24 @@ int cond_read_list(struct policydb *p, void *fp)
|
||||
|
||||
len = le32_to_cpu(buf[0]);
|
||||
|
||||
p->cond_list = kcalloc(len, sizeof(*p->cond_list), GFP_KERNEL);
|
||||
if (!p->cond_list)
|
||||
return rc;
|
||||
|
||||
rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
rc = -ENOMEM;
|
||||
node = kzalloc(sizeof(*node), GFP_KERNEL);
|
||||
if (!node)
|
||||
goto err;
|
||||
p->cond_list_len = len;
|
||||
|
||||
rc = cond_read_node(p, node, fp);
|
||||
for (i = 0; i < len; i++) {
|
||||
rc = cond_read_node(p, &p->cond_list[i], fp);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
if (i == 0)
|
||||
p->cond_list = node;
|
||||
else
|
||||
last->next = node;
|
||||
last = node;
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
cond_list_destroy(p->cond_list);
|
||||
cond_list_destroy(p);
|
||||
p->cond_list = NULL;
|
||||
return rc;
|
||||
}
|
||||
@ -522,24 +485,16 @@ static int cond_write_av_list(struct policydb *p,
|
||||
struct cond_av_list *list, struct policy_file *fp)
|
||||
{
|
||||
__le32 buf[1];
|
||||
struct cond_av_list *cur_list;
|
||||
u32 len;
|
||||
u32 i;
|
||||
int rc;
|
||||
|
||||
len = 0;
|
||||
for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
|
||||
len++;
|
||||
|
||||
buf[0] = cpu_to_le32(len);
|
||||
buf[0] = cpu_to_le32(list->len);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
|
||||
rc = avtab_write_item(p, cur_list->node, fp);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
rc = avtab_write_item(p, list->nodes[i], fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
@ -550,59 +505,51 @@ static int cond_write_av_list(struct policydb *p,
|
||||
static int cond_write_node(struct policydb *p, struct cond_node *node,
|
||||
struct policy_file *fp)
|
||||
{
|
||||
struct cond_expr *cur_expr;
|
||||
__le32 buf[2];
|
||||
int rc;
|
||||
u32 len = 0;
|
||||
u32 i;
|
||||
|
||||
buf[0] = cpu_to_le32(node->cur_state);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
|
||||
len++;
|
||||
|
||||
buf[0] = cpu_to_le32(len);
|
||||
buf[0] = cpu_to_le32(node->expr.len);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
|
||||
buf[0] = cpu_to_le32(cur_expr->expr_type);
|
||||
buf[1] = cpu_to_le32(cur_expr->bool);
|
||||
for (i = 0; i < node->expr.len; i++) {
|
||||
buf[0] = cpu_to_le32(node->expr.nodes[i].expr_type);
|
||||
buf[1] = cpu_to_le32(node->expr.nodes[i].bool);
|
||||
rc = put_entry(buf, sizeof(u32), 2, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cond_write_av_list(p, node->true_list, fp);
|
||||
rc = cond_write_av_list(p, &node->true_list, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = cond_write_av_list(p, node->false_list, fp);
|
||||
rc = cond_write_av_list(p, &node->false_list, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
|
||||
int cond_write_list(struct policydb *p, void *fp)
|
||||
{
|
||||
struct cond_node *cur;
|
||||
u32 len;
|
||||
u32 i;
|
||||
__le32 buf[1];
|
||||
int rc;
|
||||
|
||||
len = 0;
|
||||
for (cur = list; cur != NULL; cur = cur->next)
|
||||
len++;
|
||||
buf[0] = cpu_to_le32(len);
|
||||
buf[0] = cpu_to_le32(p->cond_list_len);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (cur = list; cur != NULL; cur = cur->next) {
|
||||
rc = cond_write_node(p, cur, fp);
|
||||
for (i = 0; i < p->cond_list_len; i++) {
|
||||
rc = cond_write_node(p, &p->cond_list[i], fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
* A conditional expression is a list of operators and operands
|
||||
* in reverse polish notation.
|
||||
*/
|
||||
struct cond_expr {
|
||||
struct cond_expr_node {
|
||||
#define COND_BOOL 1 /* plain bool */
|
||||
#define COND_NOT 2 /* !bool */
|
||||
#define COND_OR 3 /* bool || bool */
|
||||
@ -28,9 +28,13 @@ struct cond_expr {
|
||||
#define COND_EQ 6 /* bool == bool */
|
||||
#define COND_NEQ 7 /* bool != bool */
|
||||
#define COND_LAST COND_NEQ
|
||||
__u32 expr_type;
|
||||
__u32 bool;
|
||||
struct cond_expr *next;
|
||||
u32 expr_type;
|
||||
u32 bool;
|
||||
};
|
||||
|
||||
struct cond_expr {
|
||||
struct cond_expr_node *nodes;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -39,8 +43,8 @@ struct cond_expr {
|
||||
* struct is for that list.
|
||||
*/
|
||||
struct cond_av_list {
|
||||
struct avtab_node *node;
|
||||
struct cond_av_list *next;
|
||||
struct avtab_node **nodes;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -52,13 +56,12 @@ struct cond_av_list {
|
||||
*/
|
||||
struct cond_node {
|
||||
int cur_state;
|
||||
struct cond_expr *expr;
|
||||
struct cond_av_list *true_list;
|
||||
struct cond_av_list *false_list;
|
||||
struct cond_node *next;
|
||||
struct cond_expr expr;
|
||||
struct cond_av_list true_list;
|
||||
struct cond_av_list false_list;
|
||||
};
|
||||
|
||||
int cond_policydb_init(struct policydb *p);
|
||||
void cond_policydb_init(struct policydb *p);
|
||||
void cond_policydb_destroy(struct policydb *p);
|
||||
|
||||
int cond_init_bool_indexes(struct policydb *p);
|
||||
@ -69,12 +72,12 @@ int cond_index_bool(void *key, void *datum, void *datap);
|
||||
int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
|
||||
int cond_read_list(struct policydb *p, void *fp);
|
||||
int cond_write_bool(void *key, void *datum, void *ptr);
|
||||
int cond_write_list(struct policydb *p, struct cond_node *list, void *fp);
|
||||
int cond_write_list(struct policydb *p, void *fp);
|
||||
|
||||
void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
|
||||
struct av_decision *avd, struct extended_perms *xperms);
|
||||
void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
|
||||
struct extended_perms_decision *xpermd);
|
||||
int evaluate_cond_node(struct policydb *p, struct cond_node *node);
|
||||
void evaluate_cond_nodes(struct policydb *p);
|
||||
|
||||
#endif /* _CONDITIONAL_H_ */
|
||||
|
@ -12,12 +12,29 @@
|
||||
|
||||
static struct kmem_cache *hashtab_node_cachep;
|
||||
|
||||
/*
|
||||
* Here we simply round the number of elements up to the nearest power of two.
|
||||
* I tried also other options like rouding down or rounding to the closest
|
||||
* power of two (up or down based on which is closer), but I was unable to
|
||||
* find any significant difference in lookup/insert performance that would
|
||||
* justify switching to a different (less intuitive) formula. It could be that
|
||||
* a different formula is actually more optimal, but any future changes here
|
||||
* should be supported with performance/memory usage data.
|
||||
*
|
||||
* The total memory used by the htable arrays (only) with Fedora policy loaded
|
||||
* is approximately 163 KB at the time of writing.
|
||||
*/
|
||||
static u32 hashtab_compute_size(u32 nel)
|
||||
{
|
||||
return nel == 0 ? 0 : roundup_pow_of_two(nel);
|
||||
}
|
||||
|
||||
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
|
||||
int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
|
||||
u32 size)
|
||||
u32 nel_hint)
|
||||
{
|
||||
struct hashtab *p;
|
||||
u32 i;
|
||||
u32 i, size = hashtab_compute_size(nel_hint);
|
||||
|
||||
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
@ -27,6 +44,9 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *
|
||||
p->nel = 0;
|
||||
p->hash_value = hash_value;
|
||||
p->keycmp = keycmp;
|
||||
if (!size)
|
||||
return p;
|
||||
|
||||
p->htable = kmalloc_array(size, sizeof(*p->htable), GFP_KERNEL);
|
||||
if (!p->htable) {
|
||||
kfree(p);
|
||||
@ -46,7 +66,7 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)
|
||||
|
||||
cond_resched();
|
||||
|
||||
if (!h || h->nel == HASHTAB_MAX_NODES)
|
||||
if (!h || !h->size || h->nel == HASHTAB_MAX_NODES)
|
||||
return -EINVAL;
|
||||
|
||||
hvalue = h->hash_value(h, key);
|
||||
@ -82,7 +102,7 @@ void *hashtab_search(struct hashtab *h, const void *key)
|
||||
u32 hvalue;
|
||||
struct hashtab_node *cur;
|
||||
|
||||
if (!h)
|
||||
if (!h || !h->size)
|
||||
return NULL;
|
||||
|
||||
hvalue = h->hash_value(h, key);
|
||||
|
@ -42,7 +42,7 @@ struct hashtab_info {
|
||||
*/
|
||||
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
|
||||
int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
|
||||
u32 size);
|
||||
u32 nel_hint);
|
||||
|
||||
/*
|
||||
* Inserts the specified (key, datum) pair into the specified hash table.
|
||||
|
@ -56,17 +56,6 @@ static const char *symtab_name[SYM_NUM] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static unsigned int symtab_sizes[SYM_NUM] = {
|
||||
2,
|
||||
32,
|
||||
16,
|
||||
512,
|
||||
128,
|
||||
16,
|
||||
16,
|
||||
16,
|
||||
};
|
||||
|
||||
struct policydb_compat_info {
|
||||
int version;
|
||||
int sym_num;
|
||||
@ -336,11 +325,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
|
||||
|
||||
static int filenametr_destroy(void *key, void *datum, void *p)
|
||||
{
|
||||
struct filename_trans *ft = key;
|
||||
struct filename_trans_key *ft = key;
|
||||
struct filename_trans_datum *next, *d = datum;
|
||||
|
||||
kfree(ft->name);
|
||||
kfree(key);
|
||||
kfree(datum);
|
||||
do {
|
||||
ebitmap_destroy(&d->stypes);
|
||||
next = d->next;
|
||||
kfree(d);
|
||||
d = next;
|
||||
} while (unlikely(d));
|
||||
cond_resched();
|
||||
return 0;
|
||||
}
|
||||
@ -406,12 +401,12 @@ out:
|
||||
|
||||
static u32 filenametr_hash(struct hashtab *h, const void *k)
|
||||
{
|
||||
const struct filename_trans *ft = k;
|
||||
const struct filename_trans_key *ft = k;
|
||||
unsigned long hash;
|
||||
unsigned int byte_num;
|
||||
unsigned char focus;
|
||||
|
||||
hash = ft->stype ^ ft->ttype ^ ft->tclass;
|
||||
hash = ft->ttype ^ ft->tclass;
|
||||
|
||||
byte_num = 0;
|
||||
while ((focus = ft->name[byte_num++]))
|
||||
@ -421,14 +416,10 @@ static u32 filenametr_hash(struct hashtab *h, const void *k)
|
||||
|
||||
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;
|
||||
const struct filename_trans_key *ft1 = k1;
|
||||
const struct filename_trans_key *ft2 = k2;
|
||||
int v;
|
||||
|
||||
v = ft1->stype - ft2->stype;
|
||||
if (v)
|
||||
return v;
|
||||
|
||||
v = ft1->ttype - ft2->ttype;
|
||||
if (v)
|
||||
return v;
|
||||
@ -472,54 +463,21 @@ static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
|
||||
*/
|
||||
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;
|
||||
avtab_init(&p->te_avtab);
|
||||
cond_policydb_init(p);
|
||||
|
||||
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;
|
||||
}
|
||||
(1 << 11));
|
||||
if (!p->filename_trans)
|
||||
return -ENOMEM;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -865,29 +823,28 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
|
||||
|
||||
head = p->ocontexts[OCON_ISID];
|
||||
for (c = head; c; c = c->next) {
|
||||
rc = -EINVAL;
|
||||
if (!c->context[0].user) {
|
||||
pr_err("SELinux: SID %s was never defined.\n",
|
||||
c->u.name);
|
||||
sidtab_destroy(s);
|
||||
goto out;
|
||||
}
|
||||
if (c->sid[0] == SECSID_NULL || c->sid[0] > SECINITSID_NUM) {
|
||||
pr_err("SELinux: Initial SID %s out of range.\n",
|
||||
c->u.name);
|
||||
u32 sid = c->sid[0];
|
||||
const char *name = security_get_initial_sid_context(sid);
|
||||
|
||||
if (sid == SECSID_NULL) {
|
||||
pr_err("SELinux: SID 0 was assigned a context.\n");
|
||||
sidtab_destroy(s);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Ignore initial SIDs unused by this kernel. */
|
||||
if (!name)
|
||||
continue;
|
||||
|
||||
rc = context_add_hash(p, &c->context[0]);
|
||||
if (rc) {
|
||||
sidtab_destroy(s);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = sidtab_set_initial(s, c->sid[0], &c->context[0]);
|
||||
rc = sidtab_set_initial(s, sid, &c->context[0]);
|
||||
if (rc) {
|
||||
pr_err("SELinux: unable to load initial SID %s.\n",
|
||||
c->u.name);
|
||||
name);
|
||||
sidtab_destroy(s);
|
||||
goto out;
|
||||
}
|
||||
@ -1140,12 +1097,12 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
|
||||
|
||||
len = le32_to_cpu(buf[0]);
|
||||
comdatum->value = le32_to_cpu(buf[1]);
|
||||
nel = le32_to_cpu(buf[3]);
|
||||
|
||||
rc = symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE);
|
||||
rc = symtab_init(&comdatum->permissions, nel);
|
||||
if (rc)
|
||||
goto bad;
|
||||
comdatum->permissions.nprim = le32_to_cpu(buf[2]);
|
||||
nel = le32_to_cpu(buf[3]);
|
||||
|
||||
rc = str_read(&key, GFP_KERNEL, fp, len);
|
||||
if (rc)
|
||||
@ -1262,10 +1219,9 @@ static int read_cons_helper(struct policydb *p,
|
||||
if (rc)
|
||||
return rc;
|
||||
if (p->policyvers >=
|
||||
POLICYDB_VERSION_CONSTRAINT_NAMES) {
|
||||
e->type_names = kzalloc(sizeof
|
||||
(*e->type_names),
|
||||
GFP_KERNEL);
|
||||
POLICYDB_VERSION_CONSTRAINT_NAMES) {
|
||||
e->type_names = kzalloc(sizeof
|
||||
(*e->type_names), GFP_KERNEL);
|
||||
if (!e->type_names)
|
||||
return -ENOMEM;
|
||||
type_set_init(e->type_names);
|
||||
@ -1306,12 +1262,12 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
|
||||
len = le32_to_cpu(buf[0]);
|
||||
len2 = le32_to_cpu(buf[1]);
|
||||
cladatum->value = le32_to_cpu(buf[2]);
|
||||
nel = le32_to_cpu(buf[4]);
|
||||
|
||||
rc = symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE);
|
||||
rc = symtab_init(&cladatum->permissions, nel);
|
||||
if (rc)
|
||||
goto bad;
|
||||
cladatum->permissions.nprim = le32_to_cpu(buf[3]);
|
||||
nel = le32_to_cpu(buf[4]);
|
||||
|
||||
ncons = le32_to_cpu(buf[5]);
|
||||
|
||||
@ -1824,6 +1780,11 @@ static int range_read(struct policydb *p, void *fp)
|
||||
return rc;
|
||||
|
||||
nel = le32_to_cpu(buf[0]);
|
||||
|
||||
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, nel);
|
||||
if (!p->range_tr)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < nel; i++) {
|
||||
rc = -ENOMEM;
|
||||
rt = kzalloc(sizeof(*rt), GFP_KERNEL);
|
||||
@ -1880,13 +1841,93 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int filename_trans_read_one(struct policydb *p, void *fp)
|
||||
{
|
||||
struct filename_trans_key key, *ft = NULL;
|
||||
struct filename_trans_datum *last, *datum = NULL;
|
||||
char *name = NULL;
|
||||
u32 len, stype, otype;
|
||||
__le32 buf[4];
|
||||
int rc;
|
||||
|
||||
/* length of the path component string */
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc)
|
||||
return rc;
|
||||
len = le32_to_cpu(buf[0]);
|
||||
|
||||
/* path component string */
|
||||
rc = str_read(&name, GFP_KERNEL, fp, len);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32) * 4);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
stype = le32_to_cpu(buf[0]);
|
||||
key.ttype = le32_to_cpu(buf[1]);
|
||||
key.tclass = le32_to_cpu(buf[2]);
|
||||
key.name = name;
|
||||
|
||||
otype = le32_to_cpu(buf[3]);
|
||||
|
||||
last = NULL;
|
||||
datum = hashtab_search(p->filename_trans, &key);
|
||||
while (datum) {
|
||||
if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) {
|
||||
/* conflicting/duplicate rules are ignored */
|
||||
datum = NULL;
|
||||
goto out;
|
||||
}
|
||||
if (likely(datum->otype == otype))
|
||||
break;
|
||||
last = datum;
|
||||
datum = datum->next;
|
||||
}
|
||||
if (!datum) {
|
||||
rc = -ENOMEM;
|
||||
datum = kmalloc(sizeof(*datum), GFP_KERNEL);
|
||||
if (!datum)
|
||||
goto out;
|
||||
|
||||
ebitmap_init(&datum->stypes);
|
||||
datum->otype = otype;
|
||||
datum->next = NULL;
|
||||
|
||||
if (unlikely(last)) {
|
||||
last->next = datum;
|
||||
} else {
|
||||
rc = -ENOMEM;
|
||||
ft = kmemdup(&key, sizeof(key), GFP_KERNEL);
|
||||
if (!ft)
|
||||
goto out;
|
||||
|
||||
rc = hashtab_insert(p->filename_trans, ft, datum);
|
||||
if (rc)
|
||||
goto out;
|
||||
name = NULL;
|
||||
|
||||
rc = ebitmap_set_bit(&p->filename_trans_ttypes,
|
||||
key.ttype, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
kfree(name);
|
||||
return ebitmap_set_bit(&datum->stypes, stype - 1, 1);
|
||||
|
||||
out:
|
||||
kfree(ft);
|
||||
kfree(name);
|
||||
kfree(datum);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int filename_trans_read(struct policydb *p, void *fp)
|
||||
{
|
||||
struct filename_trans *ft;
|
||||
struct filename_trans_datum *otype;
|
||||
char *name;
|
||||
u32 nel, len;
|
||||
__le32 buf[4];
|
||||
u32 nel;
|
||||
__le32 buf[1];
|
||||
int rc, i;
|
||||
|
||||
if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
|
||||
@ -1897,69 +1938,15 @@ static int filename_trans_read(struct policydb *p, void *fp)
|
||||
return rc;
|
||||
nel = le32_to_cpu(buf[0]);
|
||||
|
||||
p->filename_trans_count = nel;
|
||||
|
||||
for (i = 0; i < nel; i++) {
|
||||
otype = NULL;
|
||||
name = NULL;
|
||||
|
||||
rc = -ENOMEM;
|
||||
ft = kzalloc(sizeof(*ft), GFP_KERNEL);
|
||||
if (!ft)
|
||||
goto out;
|
||||
|
||||
rc = -ENOMEM;
|
||||
otype = kmalloc(sizeof(*otype), GFP_KERNEL);
|
||||
if (!otype)
|
||||
goto out;
|
||||
|
||||
/* length of the path component string */
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
rc = filename_trans_read_one(p, fp);
|
||||
if (rc)
|
||||
goto out;
|
||||
len = le32_to_cpu(buf[0]);
|
||||
|
||||
/* path component string */
|
||||
rc = str_read(&name, GFP_KERNEL, fp, len);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
ft->name = name;
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32) * 4);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
ft->stype = le32_to_cpu(buf[0]);
|
||||
ft->ttype = le32_to_cpu(buf[1]);
|
||||
ft->tclass = le32_to_cpu(buf[2]);
|
||||
|
||||
otype->otype = le32_to_cpu(buf[3]);
|
||||
|
||||
rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = hashtab_insert(p->filename_trans, ft, otype);
|
||||
if (rc) {
|
||||
/*
|
||||
* Do not return -EEXIST to the caller, or the system
|
||||
* will not boot.
|
||||
*/
|
||||
if (rc != -EEXIST)
|
||||
goto out;
|
||||
/* But free memory to avoid memory leak. */
|
||||
kfree(ft);
|
||||
kfree(name);
|
||||
kfree(otype);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
hash_eval(p->filename_trans, "filenametr");
|
||||
return 0;
|
||||
out:
|
||||
kfree(ft);
|
||||
kfree(name);
|
||||
kfree(otype);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int genfs_read(struct policydb *p, void *fp)
|
||||
@ -2390,6 +2377,17 @@ int policydb_read(struct policydb *p, void *fp)
|
||||
goto bad;
|
||||
nprim = le32_to_cpu(buf[0]);
|
||||
nel = le32_to_cpu(buf[1]);
|
||||
|
||||
rc = symtab_init(&p->symtab[i], nel);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (i == SYM_ROLES) {
|
||||
rc = roles_init(p);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (j = 0; j < nel; j++) {
|
||||
rc = read_f[i](p, p->symtab[i].table, fp);
|
||||
if (rc)
|
||||
@ -3330,50 +3328,50 @@ static int range_write(struct policydb *p, void *fp)
|
||||
|
||||
static int filename_write_helper(void *key, void *data, void *ptr)
|
||||
{
|
||||
__le32 buf[4];
|
||||
struct filename_trans *ft = key;
|
||||
struct filename_trans_datum *otype = data;
|
||||
struct filename_trans_key *ft = key;
|
||||
struct filename_trans_datum *datum = data;
|
||||
struct ebitmap_node *node;
|
||||
void *fp = ptr;
|
||||
__le32 buf[4];
|
||||
int rc;
|
||||
u32 len;
|
||||
u32 bit, len = strlen(ft->name);
|
||||
|
||||
len = strlen(ft->name);
|
||||
buf[0] = cpu_to_le32(len);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
do {
|
||||
ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
|
||||
buf[0] = cpu_to_le32(len);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = put_entry(ft->name, sizeof(char), len, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = put_entry(ft->name, sizeof(char), len, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
buf[0] = cpu_to_le32(ft->stype);
|
||||
buf[1] = cpu_to_le32(ft->ttype);
|
||||
buf[2] = cpu_to_le32(ft->tclass);
|
||||
buf[3] = cpu_to_le32(otype->otype);
|
||||
buf[0] = cpu_to_le32(bit + 1);
|
||||
buf[1] = cpu_to_le32(ft->ttype);
|
||||
buf[2] = cpu_to_le32(ft->tclass);
|
||||
buf[3] = cpu_to_le32(datum->otype);
|
||||
|
||||
rc = put_entry(buf, sizeof(u32), 4, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = put_entry(buf, sizeof(u32), 4, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
datum = datum->next;
|
||||
} while (unlikely(datum));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int filename_trans_write(struct policydb *p, void *fp)
|
||||
{
|
||||
u32 nel;
|
||||
__le32 buf[1];
|
||||
int rc;
|
||||
|
||||
if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
|
||||
return 0;
|
||||
|
||||
nel = 0;
|
||||
rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
buf[0] = cpu_to_le32(nel);
|
||||
buf[0] = cpu_to_le32(p->filename_trans_count);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -3483,7 +3481,7 @@ int policydb_write(struct policydb *p, void *fp)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = cond_write_list(p, p->cond_list, fp);
|
||||
rc = cond_write_list(p, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -89,15 +89,16 @@ struct role_trans {
|
||||
struct role_trans *next;
|
||||
};
|
||||
|
||||
struct filename_trans {
|
||||
u32 stype; /* current process */
|
||||
struct filename_trans_key {
|
||||
u32 ttype; /* parent dir context */
|
||||
u16 tclass; /* class of new object */
|
||||
const char *name; /* last path component */
|
||||
};
|
||||
|
||||
struct filename_trans_datum {
|
||||
u32 otype; /* expected of new object */
|
||||
struct ebitmap stypes; /* bitmap of source types for this otype */
|
||||
u32 otype; /* resulting type of new object */
|
||||
struct filename_trans_datum *next; /* record for next otype*/
|
||||
};
|
||||
|
||||
struct role_allow {
|
||||
@ -267,13 +268,15 @@ struct policydb {
|
||||
struct ebitmap filename_trans_ttypes;
|
||||
/* actual set of filename_trans rules */
|
||||
struct hashtab *filename_trans;
|
||||
u32 filename_trans_count;
|
||||
|
||||
/* bools indexed by (value - 1) */
|
||||
struct cond_bool_datum **bool_val_to_struct;
|
||||
/* type enforcement conditional access vectors and transitions */
|
||||
struct avtab te_cond_avtab;
|
||||
/* linked list indexing te_cond_avtab by conditional */
|
||||
/* array indexing te_cond_avtab by conditional */
|
||||
struct cond_node *cond_list;
|
||||
u32 cond_list_len;
|
||||
|
||||
/* role allows */
|
||||
struct role_allow *role_allow;
|
||||
@ -318,8 +321,6 @@ extern int policydb_role_isvalid(struct policydb *p, unsigned int role);
|
||||
extern int policydb_read(struct policydb *p, void *fp);
|
||||
extern int policydb_write(struct policydb *p, void *fp);
|
||||
|
||||
#define PERM_SYMTAB_SIZE 32
|
||||
|
||||
#define POLICYDB_CONFIG_MLS 1
|
||||
|
||||
/* the config flags related to unknown classes/perms are bits 2 and 3 */
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include <linux/in.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/audit.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <net/netlabel.h>
|
||||
|
||||
@ -73,7 +72,8 @@ const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
|
||||
"extended_socket_class",
|
||||
"always_check_network",
|
||||
"cgroup_seclabel",
|
||||
"nnp_nosuid_transition"
|
||||
"nnp_nosuid_transition",
|
||||
"genfs_seclabel_symlinks"
|
||||
};
|
||||
|
||||
static struct selinux_ss selinux_ss;
|
||||
@ -81,7 +81,6 @@ static struct selinux_ss selinux_ss;
|
||||
void selinux_ss_init(struct selinux_ss **ss)
|
||||
{
|
||||
rwlock_init(&selinux_ss.policy_rwlock);
|
||||
mutex_init(&selinux_ss.status_lock);
|
||||
*ss = &selinux_ss;
|
||||
}
|
||||
|
||||
@ -1323,23 +1322,22 @@ static int security_sid_to_context_core(struct selinux_state *state,
|
||||
if (!selinux_initialized(state)) {
|
||||
if (sid <= SECINITSID_NUM) {
|
||||
char *scontextp;
|
||||
const char *s = initial_sid_to_string[sid];
|
||||
|
||||
*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
*scontext_len = strlen(s) + 1;
|
||||
if (!scontext)
|
||||
goto out;
|
||||
scontextp = kmemdup(initial_sid_to_string[sid],
|
||||
*scontext_len, GFP_ATOMIC);
|
||||
if (!scontextp) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
return 0;
|
||||
scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC);
|
||||
if (!scontextp)
|
||||
return -ENOMEM;
|
||||
*scontext = scontextp;
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
pr_err("SELinux: %s: called before initial "
|
||||
"load_policy on unknown SID %d\n", __func__, sid);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
read_lock(&state->ss->policy_rwlock);
|
||||
policydb = &state->ss->policydb;
|
||||
@ -1363,7 +1361,6 @@ static int security_sid_to_context_core(struct selinux_state *state,
|
||||
|
||||
out_unlock:
|
||||
read_unlock(&state->ss->policy_rwlock);
|
||||
out:
|
||||
return rc;
|
||||
|
||||
}
|
||||
@ -1553,7 +1550,9 @@ static int security_context_to_sid_core(struct selinux_state *state,
|
||||
int i;
|
||||
|
||||
for (i = 1; i < SECINITSID_NUM; i++) {
|
||||
if (!strcmp(initial_sid_to_string[i], scontext2)) {
|
||||
const char *s = initial_sid_to_string[i];
|
||||
|
||||
if (s && !strcmp(s, scontext2)) {
|
||||
*sid = i;
|
||||
goto out;
|
||||
}
|
||||
@ -1693,8 +1692,8 @@ static void filename_compute_type(struct policydb *policydb,
|
||||
u32 stype, u32 ttype, u16 tclass,
|
||||
const char *objname)
|
||||
{
|
||||
struct filename_trans ft;
|
||||
struct filename_trans_datum *otype;
|
||||
struct filename_trans_key ft;
|
||||
struct filename_trans_datum *datum;
|
||||
|
||||
/*
|
||||
* Most filename trans rules are going to live in specific directories
|
||||
@ -1704,14 +1703,18 @@ static void filename_compute_type(struct policydb *policydb,
|
||||
if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
|
||||
return;
|
||||
|
||||
ft.stype = stype;
|
||||
ft.ttype = ttype;
|
||||
ft.tclass = tclass;
|
||||
ft.name = objname;
|
||||
|
||||
otype = hashtab_search(policydb->filename_trans, &ft);
|
||||
if (otype)
|
||||
newcontext->type = otype->otype;
|
||||
datum = hashtab_search(policydb->filename_trans, &ft);
|
||||
while (datum) {
|
||||
if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
|
||||
newcontext->type = datum->otype;
|
||||
return;
|
||||
}
|
||||
datum = datum->next;
|
||||
}
|
||||
}
|
||||
|
||||
static int security_compute_sid(struct selinux_state *state,
|
||||
@ -2868,10 +2871,11 @@ out:
|
||||
}
|
||||
|
||||
int security_get_bools(struct selinux_state *state,
|
||||
int *len, char ***names, int **values)
|
||||
u32 *len, char ***names, int **values)
|
||||
{
|
||||
struct policydb *policydb;
|
||||
int i, rc;
|
||||
u32 i;
|
||||
int rc;
|
||||
|
||||
if (!selinux_initialized(state)) {
|
||||
*len = 0;
|
||||
@ -2925,12 +2929,11 @@ err:
|
||||
}
|
||||
|
||||
|
||||
int security_set_bools(struct selinux_state *state, int len, int *values)
|
||||
int security_set_bools(struct selinux_state *state, u32 len, int *values)
|
||||
{
|
||||
struct policydb *policydb;
|
||||
int i, rc;
|
||||
int lenp, seqno = 0;
|
||||
struct cond_node *cur;
|
||||
int rc;
|
||||
u32 i, lenp, seqno = 0;
|
||||
|
||||
write_lock_irq(&state->ss->policy_rwlock);
|
||||
|
||||
@ -2958,11 +2961,7 @@ int security_set_bools(struct selinux_state *state, int len, int *values)
|
||||
policydb->bool_val_to_struct[i]->state = 0;
|
||||
}
|
||||
|
||||
for (cur = policydb->cond_list; cur; cur = cur->next) {
|
||||
rc = evaluate_cond_node(policydb, cur);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
evaluate_cond_nodes(policydb);
|
||||
|
||||
seqno = ++state->ss->latest_granting;
|
||||
rc = 0;
|
||||
@ -2978,11 +2977,11 @@ out:
|
||||
}
|
||||
|
||||
int security_get_bool_value(struct selinux_state *state,
|
||||
int index)
|
||||
u32 index)
|
||||
{
|
||||
struct policydb *policydb;
|
||||
int rc;
|
||||
int len;
|
||||
u32 len;
|
||||
|
||||
read_lock(&state->ss->policy_rwlock);
|
||||
|
||||
@ -3002,10 +3001,10 @@ out:
|
||||
static int security_preserve_bools(struct selinux_state *state,
|
||||
struct policydb *policydb)
|
||||
{
|
||||
int rc, nbools = 0, *bvalues = NULL, i;
|
||||
int rc, *bvalues = NULL;
|
||||
char **bnames = NULL;
|
||||
struct cond_bool_datum *booldatum;
|
||||
struct cond_node *cur;
|
||||
u32 i, nbools = 0;
|
||||
|
||||
rc = security_get_bools(state, &nbools, &bnames, &bvalues);
|
||||
if (rc)
|
||||
@ -3015,11 +3014,7 @@ static int security_preserve_bools(struct selinux_state *state,
|
||||
if (booldatum)
|
||||
booldatum->state = bvalues[i];
|
||||
}
|
||||
for (cur = policydb->cond_list; cur; cur = cur->next) {
|
||||
rc = evaluate_cond_node(policydb, cur);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
evaluate_cond_nodes(policydb);
|
||||
|
||||
out:
|
||||
if (bnames) {
|
||||
|
@ -29,8 +29,6 @@ struct selinux_ss {
|
||||
rwlock_t policy_rwlock;
|
||||
u32 latest_granting;
|
||||
struct selinux_map map;
|
||||
struct page *status_page;
|
||||
struct mutex status_lock;
|
||||
} __randomize_layout;
|
||||
|
||||
void services_compute_xperms_drivers(struct extended_perms *xperms,
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "avc.h"
|
||||
#include "services.h"
|
||||
#include "security.h"
|
||||
|
||||
/*
|
||||
* The selinux_status_page shall be exposed to userspace applications
|
||||
@ -44,12 +44,12 @@ struct page *selinux_kernel_status_page(struct selinux_state *state)
|
||||
struct selinux_kernel_status *status;
|
||||
struct page *result = NULL;
|
||||
|
||||
mutex_lock(&state->ss->status_lock);
|
||||
if (!state->ss->status_page) {
|
||||
state->ss->status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
|
||||
mutex_lock(&state->status_lock);
|
||||
if (!state->status_page) {
|
||||
state->status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
|
||||
|
||||
if (state->ss->status_page) {
|
||||
status = page_address(state->ss->status_page);
|
||||
if (state->status_page) {
|
||||
status = page_address(state->status_page);
|
||||
|
||||
status->version = SELINUX_KERNEL_STATUS_VERSION;
|
||||
status->sequence = 0;
|
||||
@ -65,8 +65,8 @@ struct page *selinux_kernel_status_page(struct selinux_state *state)
|
||||
!security_get_allow_unknown(state);
|
||||
}
|
||||
}
|
||||
result = state->ss->status_page;
|
||||
mutex_unlock(&state->ss->status_lock);
|
||||
result = state->status_page;
|
||||
mutex_unlock(&state->status_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -81,9 +81,9 @@ void selinux_status_update_setenforce(struct selinux_state *state,
|
||||
{
|
||||
struct selinux_kernel_status *status;
|
||||
|
||||
mutex_lock(&state->ss->status_lock);
|
||||
if (state->ss->status_page) {
|
||||
status = page_address(state->ss->status_page);
|
||||
mutex_lock(&state->status_lock);
|
||||
if (state->status_page) {
|
||||
status = page_address(state->status_page);
|
||||
|
||||
status->sequence++;
|
||||
smp_wmb();
|
||||
@ -93,7 +93,7 @@ void selinux_status_update_setenforce(struct selinux_state *state,
|
||||
smp_wmb();
|
||||
status->sequence++;
|
||||
}
|
||||
mutex_unlock(&state->ss->status_lock);
|
||||
mutex_unlock(&state->status_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -107,9 +107,9 @@ void selinux_status_update_policyload(struct selinux_state *state,
|
||||
{
|
||||
struct selinux_kernel_status *status;
|
||||
|
||||
mutex_lock(&state->ss->status_lock);
|
||||
if (state->ss->status_page) {
|
||||
status = page_address(state->ss->status_page);
|
||||
mutex_lock(&state->status_lock);
|
||||
if (state->status_page) {
|
||||
status = page_address(state->status_page);
|
||||
|
||||
status->sequence++;
|
||||
smp_wmb();
|
||||
@ -120,5 +120,5 @@ void selinux_status_update_policyload(struct selinux_state *state,
|
||||
smp_wmb();
|
||||
status->sequence++;
|
||||
}
|
||||
mutex_unlock(&state->ss->status_lock);
|
||||
mutex_unlock(&state->status_lock);
|
||||
}
|
Loading…
Reference in New Issue
Block a user