Skip to content

Commit

Permalink
selinux: move policy commit after updating selinuxfs
Browse files Browse the repository at this point in the history
With the refactoring of the policy load logic in the security
server from the previous change, it is now possible to split out
the committing of the new policy from security_load_policy() and
perform it only after successful updating of selinuxfs.  Change
security_load_policy() to return the newly populated policy
data structures to the caller, export selinux_policy_commit()
for external callers, and introduce selinux_policy_cancel() to
provide a way to cancel the policy load in the event of an error
during updating of the selinuxfs directory tree.  Further, rework
the interfaces used by selinuxfs to get information from the policy
when creating the new directory tree to take and act upon the
new policy data structure rather than the current/active policy.
Update selinuxfs to use these updated and new interfaces.  While
we are here, stop re-creating the policy_capabilities directory
on each policy load since it does not depend on the policy, and
stop trying to create the booleans and classes directories during
the initial creation of selinuxfs since no information is available
until first policy load.

After this change, a failure while updating the booleans and class
directories will cause the entire policy load to be canceled, leaving
the original policy intact, and policy load notifications to userspace
will only happen after a successful completion of updating those
directories.  This does not (yet) provide full atomicity with respect
to the updating of the directory trees themselves.

Signed-off-by: Stephen Smalley <[email protected]>
Signed-off-by: Paul Moore <[email protected]>
  • Loading branch information
stephensmalley authored and pcmoore committed Aug 18, 2020
1 parent 4616980 commit 02a52c5
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 80 deletions.
2 changes: 1 addition & 1 deletion security/selinux/include/conditional.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

#include "security.h"

int security_get_bools(struct selinux_state *state,
int security_get_bools(struct selinux_policy *policy,
u32 *len, char ***names, int **values);

int security_set_bools(struct selinux_state *state, u32 len, int *values);
Expand Down
16 changes: 13 additions & 3 deletions security/selinux/include/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ extern int selinux_enabled_boot;

struct selinux_avc;
struct selinux_ss;
struct selinux_policy;

struct selinux_state {
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Expand Down Expand Up @@ -210,7 +211,12 @@ static inline bool selinux_policycap_genfs_seclabel_symlinks(void)

int security_mls_enabled(struct selinux_state *state);
int security_load_policy(struct selinux_state *state,
void *data, size_t len);
void *data, size_t len,
struct selinux_policy **newpolicyp);
void selinux_policy_commit(struct selinux_state *state,
struct selinux_policy *newpolicy);
void selinux_policy_cancel(struct selinux_state *state,
struct selinux_policy *policy);
int security_read_policy(struct selinux_state *state,
void **data, size_t *len);
size_t security_policydb_len(struct selinux_state *state);
Expand Down Expand Up @@ -344,9 +350,9 @@ int security_net_peersid_resolve(struct selinux_state *state,
u32 xfrm_sid,
u32 *peer_sid);

int security_get_classes(struct selinux_state *state,
int security_get_classes(struct selinux_policy *policy,
char ***classes, int *nclasses);
int security_get_permissions(struct selinux_state *state,
int security_get_permissions(struct selinux_policy *policy,
char *class, char ***perms, int *nperms);
int security_get_reject_unknown(struct selinux_state *state);
int security_get_allow_unknown(struct selinux_state *state);
Expand All @@ -366,6 +372,10 @@ int security_genfs_sid(struct selinux_state *state,
const char *fstype, char *name, u16 sclass,
u32 *sid);

int selinux_policy_genfs_sid(struct selinux_policy *policy,
const char *fstype, char *name, u16 sclass,
u32 *sid);

#ifdef CONFIG_NETLABEL
int security_netlbl_secattr_to_sid(struct selinux_state *state,
struct netlbl_lsm_secattr *secattr,
Expand Down
69 changes: 37 additions & 32 deletions security/selinux/selinuxfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,10 @@ static const struct file_operations sel_policyvers_ops = {
};

/* declaration for sel_write_load */
static int sel_make_bools(struct selinux_fs_info *fsi);
static int sel_make_classes(struct selinux_fs_info *fsi);
static int sel_make_policycap(struct selinux_fs_info *fsi);
static int sel_make_bools(struct selinux_fs_info *fsi,
struct selinux_policy *newpolicy);
static int sel_make_classes(struct selinux_fs_info *fsi,
struct selinux_policy *newpolicy);

/* declaration for sel_make_class_dirs */
static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
Expand Down Expand Up @@ -508,28 +509,23 @@ static const struct file_operations sel_policy_ops = {
.llseek = generic_file_llseek,
};

static int sel_make_policy_nodes(struct selinux_fs_info *fsi)
static int sel_make_policy_nodes(struct selinux_fs_info *fsi,
struct selinux_policy *newpolicy)
{
int ret;

ret = sel_make_bools(fsi);
ret = sel_make_bools(fsi, newpolicy);
if (ret) {
pr_err("SELinux: failed to load policy booleans\n");
return ret;
}

ret = sel_make_classes(fsi);
ret = sel_make_classes(fsi, newpolicy);
if (ret) {
pr_err("SELinux: failed to load policy classes\n");
return ret;
}

ret = sel_make_policycap(fsi);
if (ret) {
pr_err("SELinux: failed to load policy capabilities\n");
return ret;
}

return 0;
}

Expand All @@ -538,6 +534,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,

{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_policy *newpolicy;
ssize_t length;
void *data = NULL;

Expand All @@ -563,15 +560,19 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
if (copy_from_user(data, buf, count) != 0)
goto out;

length = security_load_policy(fsi->state, data, count);
length = security_load_policy(fsi->state, data, count, &newpolicy);
if (length) {
pr_warn_ratelimited("SELinux: failed to load policy\n");
goto out;
}

length = sel_make_policy_nodes(fsi);
if (length)
length = sel_make_policy_nodes(fsi, newpolicy);
if (length) {
selinux_policy_cancel(fsi->state, newpolicy);
goto out1;
}

selinux_policy_commit(fsi->state, newpolicy);

length = count;

Expand Down Expand Up @@ -1333,7 +1334,8 @@ static void sel_remove_entries(struct dentry *de)

#define BOOL_DIR_NAME "booleans"

static int sel_make_bools(struct selinux_fs_info *fsi)
static int sel_make_bools(struct selinux_fs_info *fsi,
struct selinux_policy *newpolicy)
{
int ret;
ssize_t len;
Expand Down Expand Up @@ -1362,7 +1364,7 @@ static int sel_make_bools(struct selinux_fs_info *fsi)
if (!page)
goto out;

ret = security_get_bools(fsi->state, &num, &names, &values);
ret = security_get_bools(newpolicy, &num, &names, &values);
if (ret)
goto out;

Expand All @@ -1388,7 +1390,7 @@ static int sel_make_bools(struct selinux_fs_info *fsi)
}

isec = selinux_inode(inode);
ret = security_genfs_sid(fsi->state, "selinuxfs", page,
ret = selinux_policy_genfs_sid(newpolicy, "selinuxfs", page,
SECCLASS_FILE, &sid);
if (ret) {
pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n",
Expand Down Expand Up @@ -1791,14 +1793,14 @@ static const struct file_operations sel_policycap_ops = {
.llseek = generic_file_llseek,
};

static int sel_make_perm_files(char *objclass, int classvalue,
struct dentry *dir)
static int sel_make_perm_files(struct selinux_policy *newpolicy,
char *objclass, int classvalue,
struct dentry *dir)
{
struct selinux_fs_info *fsi = dir->d_sb->s_fs_info;
int i, rc, nperms;
char **perms;

rc = security_get_permissions(fsi->state, objclass, &perms, &nperms);
rc = security_get_permissions(newpolicy, objclass, &perms, &nperms);
if (rc)
return rc;

Expand Down Expand Up @@ -1831,8 +1833,9 @@ static int sel_make_perm_files(char *objclass, int classvalue,
return rc;
}

static int sel_make_class_dir_entries(char *classname, int index,
struct dentry *dir)
static int sel_make_class_dir_entries(struct selinux_policy *newpolicy,
char *classname, int index,
struct dentry *dir)
{
struct super_block *sb = dir->d_sb;
struct selinux_fs_info *fsi = sb->s_fs_info;
Expand All @@ -1858,12 +1861,13 @@ static int sel_make_class_dir_entries(char *classname, int index,
if (IS_ERR(dentry))
return PTR_ERR(dentry);

rc = sel_make_perm_files(classname, index, dentry);
rc = sel_make_perm_files(newpolicy, classname, index, dentry);

return rc;
}

static int sel_make_classes(struct selinux_fs_info *fsi)
static int sel_make_classes(struct selinux_fs_info *fsi,
struct selinux_policy *newpolicy)
{

int rc, nclasses, i;
Expand All @@ -1872,7 +1876,7 @@ static int sel_make_classes(struct selinux_fs_info *fsi)
/* delete any existing entries */
sel_remove_entries(fsi->class_dir);

rc = security_get_classes(fsi->state, &classes, &nclasses);
rc = security_get_classes(newpolicy, &classes, &nclasses);
if (rc)
return rc;

Expand All @@ -1890,7 +1894,7 @@ static int sel_make_classes(struct selinux_fs_info *fsi)
}

/* i+1 since class values are 1-indexed */
rc = sel_make_class_dir_entries(classes[i], i + 1,
rc = sel_make_class_dir_entries(newpolicy, classes[i], i + 1,
class_name_dir);
if (rc)
goto out;
Expand All @@ -1909,8 +1913,6 @@ static int sel_make_policycap(struct selinux_fs_info *fsi)
struct dentry *dentry = NULL;
struct inode *inode = NULL;

sel_remove_entries(fsi->policycap_dir);

for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
if (iter < ARRAY_SIZE(selinux_policycap_names))
dentry = d_alloc_name(fsi->policycap_dir,
Expand Down Expand Up @@ -2075,9 +2077,12 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
goto err;
}

ret = sel_make_policy_nodes(fsi);
if (ret)
ret = sel_make_policycap(fsi);
if (ret) {
pr_err("SELinux: failed to load policy capabilities\n");
goto err;
}

return 0;
err:
pr_err("SELinux: %s: failed while creating inodes\n",
Expand Down
Loading

0 comments on commit 02a52c5

Please sign in to comment.