#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);
struct selinux_avc;
struct selinux_ss;
+struct selinux_policy;
struct selinux_state {
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
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);
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);
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,
};
/* 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,
.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;
}
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_policy *newpolicy;
ssize_t length;
void *data = NULL;
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;
#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;
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;
}
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",
.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;
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;
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;
/* 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;
}
/* 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;
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,
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",
kfree(policy);
}
-static void selinux_policy_commit(struct selinux_state *state,
- struct selinux_policy *newpolicy)
+void selinux_policy_cancel(struct selinux_state *state,
+ struct selinux_policy *policy)
+{
+
+ sidtab_cancel_convert(&state->ss->policy->sidtab);
+ selinux_policy_free(policy);
+}
+
+void selinux_policy_commit(struct selinux_state *state,
+ struct selinux_policy *newpolicy)
{
struct selinux_policy *oldpolicy;
u32 seqno;
* This function will flush the access vector cache after
* loading the new policy.
*/
-int security_load_policy(struct selinux_state *state, void *data, size_t len)
+int security_load_policy(struct selinux_state *state, void *data, size_t len,
+ struct selinux_policy **newpolicyp)
{
struct selinux_policy *newpolicy;
struct sidtab_convert_params convert_params;
if (!selinux_initialized(state)) {
/* First policy load, so no need to preserve state from old policy */
- selinux_policy_commit(state, newpolicy);
+ *newpolicyp = newpolicy;
return 0;
}
goto err;
}
- selinux_policy_commit(state, newpolicy);
+ *newpolicyp = newpolicy;
return 0;
err:
selinux_policy_free(newpolicy);
* Obtain a SID to use for a file in a filesystem that
* cannot support xattr or use a fixed labeling behavior like
* transition SIDs or task SIDs.
- *
- * The caller must acquire the policy_rwlock before calling this function.
*/
-static inline int __security_genfs_sid(struct selinux_state *state,
+static inline int __security_genfs_sid(struct selinux_policy *policy,
const char *fstype,
char *path,
u16 orig_sclass,
u32 *sid)
{
- struct policydb *policydb = &state->ss->policy->policydb;
- struct sidtab *sidtab = &state->ss->policy->sidtab;
+ struct policydb *policydb = &policy->policydb;
+ struct sidtab *sidtab = &policy->sidtab;
int len;
u16 sclass;
struct genfs *genfs;
while (path[0] == '/' && path[1] == '/')
path++;
- sclass = unmap_class(&state->ss->policy->map, orig_sclass);
+ sclass = unmap_class(&policy->map, orig_sclass);
*sid = SECINITSID_UNLABELED;
for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
int retval;
read_lock(&state->ss->policy_rwlock);
- retval = __security_genfs_sid(state, fstype, path, orig_sclass, sid);
+ retval = __security_genfs_sid(state->ss->policy,
+ fstype, path, orig_sclass, sid);
read_unlock(&state->ss->policy_rwlock);
return retval;
}
+int selinux_policy_genfs_sid(struct selinux_policy *policy,
+ const char *fstype,
+ char *path,
+ u16 orig_sclass,
+ u32 *sid)
+{
+ /* no lock required, policy is not yet accessible by other threads */
+ return __security_genfs_sid(policy, fstype, path, orig_sclass, sid);
+}
+
/**
* security_fs_use - Determine how to handle labeling for a filesystem.
* @sb: superblock in question
}
sbsec->sid = c->sid[0];
} else {
- rc = __security_genfs_sid(state, fstype, "/", SECCLASS_DIR,
- &sbsec->sid);
+ rc = __security_genfs_sid(state->ss->policy, fstype, "/",
+ SECCLASS_DIR, &sbsec->sid);
if (rc) {
sbsec->behavior = SECURITY_FS_USE_NONE;
rc = 0;
return rc;
}
-int security_get_bools(struct selinux_state *state,
+int security_get_bools(struct selinux_policy *policy,
u32 *len, char ***names, int **values)
{
struct policydb *policydb;
u32 i;
int rc;
- if (!selinux_initialized(state)) {
- *len = 0;
- *names = NULL;
- *values = NULL;
- return 0;
- }
-
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
+ policydb = &policy->policydb;
*names = NULL;
*values = NULL;
}
rc = 0;
out:
- read_unlock(&state->ss->policy_rwlock);
return rc;
err:
if (*names) {
struct cond_bool_datum *booldatum;
u32 i, nbools = 0;
- rc = security_get_bools(state, &nbools, &bnames, &bvalues);
+ read_lock(&state->ss->policy_rwlock);
+ rc = security_get_bools(state->ss->policy, &nbools, &bnames, &bvalues);
+ read_unlock(&state->ss->policy_rwlock);
if (rc)
goto out;
for (i = 0; i < nbools; i++) {
return 0;
}
-int security_get_classes(struct selinux_state *state,
+int security_get_classes(struct selinux_policy *policy,
char ***classes, int *nclasses)
{
struct policydb *policydb;
int rc;
- if (!selinux_initialized(state)) {
- *nclasses = 0;
- *classes = NULL;
- return 0;
- }
-
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
+ policydb = &policy->policydb;
rc = -ENOMEM;
*nclasses = policydb->p_classes.nprim;
}
out:
- read_unlock(&state->ss->policy_rwlock);
return rc;
}
return 0;
}
-int security_get_permissions(struct selinux_state *state,
+int security_get_permissions(struct selinux_policy *policy,
char *class, char ***perms, int *nperms)
{
struct policydb *policydb;
int rc, i;
struct class_datum *match;
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
+ policydb = &policy->policydb;
rc = -EINVAL;
match = symtab_search(&policydb->p_classes, class);
goto err;
out:
- read_unlock(&state->ss->policy_rwlock);
return rc;
err:
- read_unlock(&state->ss->policy_rwlock);
for (i = 0; i < *nperms; i++)
kfree((*perms)[i]);
kfree(*perms);
return 0;
}
+void sidtab_cancel_convert(struct sidtab *s)
+{
+ unsigned long flags;
+
+ /* cancelling policy load - disable live convert of sidtab */
+ spin_lock_irqsave(&s->lock, flags);
+ s->convert = NULL;
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
static void sidtab_destroy_entry(struct sidtab_entry *entry)
{
context_destroy(&entry->context);
int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params);
+void sidtab_cancel_convert(struct sidtab *s);
+
int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
void sidtab_destroy(struct sidtab *s);