Commit b3aa112d authored by Linus Torvalds's avatar Linus Torvalds

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
parents 674d85eb c753924b
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 @@ int nfs_get_tree_common(struct fs_context *fc)
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
/* 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);
......
This diff is collapsed.
......@@ -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.
......
This diff is collapsed.
......@@ -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 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
}
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 @@ int security_get_bools(struct selinux_state *state,
}
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 @@ int security_set_bools(struct selinux_state *state, int len, int *values)
}
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 @@ int security_get_bool_value(struct selinux_state *state,
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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment