Skip to content

Commit 02a52c5

Browse files
stephensmalleypcmoore
authored andcommitted
selinux: move policy commit after updating selinuxfs
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]>
1 parent 4616980 commit 02a52c5

File tree

6 files changed

+104
-80
lines changed

6 files changed

+104
-80
lines changed

security/selinux/include/conditional.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
#include "security.h"
1515

16-
int security_get_bools(struct selinux_state *state,
16+
int security_get_bools(struct selinux_policy *policy,
1717
u32 *len, char ***names, int **values);
1818

1919
int security_set_bools(struct selinux_state *state, u32 len, int *values);

security/selinux/include/security.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ extern int selinux_enabled_boot;
8585

8686
struct selinux_avc;
8787
struct selinux_ss;
88+
struct selinux_policy;
8889

8990
struct selinux_state {
9091
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
@@ -210,7 +211,12 @@ static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
210211

211212
int security_mls_enabled(struct selinux_state *state);
212213
int security_load_policy(struct selinux_state *state,
213-
void *data, size_t len);
214+
void *data, size_t len,
215+
struct selinux_policy **newpolicyp);
216+
void selinux_policy_commit(struct selinux_state *state,
217+
struct selinux_policy *newpolicy);
218+
void selinux_policy_cancel(struct selinux_state *state,
219+
struct selinux_policy *policy);
214220
int security_read_policy(struct selinux_state *state,
215221
void **data, size_t *len);
216222
size_t security_policydb_len(struct selinux_state *state);
@@ -344,9 +350,9 @@ int security_net_peersid_resolve(struct selinux_state *state,
344350
u32 xfrm_sid,
345351
u32 *peer_sid);
346352

347-
int security_get_classes(struct selinux_state *state,
353+
int security_get_classes(struct selinux_policy *policy,
348354
char ***classes, int *nclasses);
349-
int security_get_permissions(struct selinux_state *state,
355+
int security_get_permissions(struct selinux_policy *policy,
350356
char *class, char ***perms, int *nperms);
351357
int security_get_reject_unknown(struct selinux_state *state);
352358
int security_get_allow_unknown(struct selinux_state *state);
@@ -366,6 +372,10 @@ int security_genfs_sid(struct selinux_state *state,
366372
const char *fstype, char *name, u16 sclass,
367373
u32 *sid);
368374

375+
int selinux_policy_genfs_sid(struct selinux_policy *policy,
376+
const char *fstype, char *name, u16 sclass,
377+
u32 *sid);
378+
369379
#ifdef CONFIG_NETLABEL
370380
int security_netlbl_secattr_to_sid(struct selinux_state *state,
371381
struct netlbl_lsm_secattr *secattr,

security/selinux/selinuxfs.c

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,10 @@ static const struct file_operations sel_policyvers_ops = {
346346
};
347347

348348
/* declaration for sel_write_load */
349-
static int sel_make_bools(struct selinux_fs_info *fsi);
350-
static int sel_make_classes(struct selinux_fs_info *fsi);
351-
static int sel_make_policycap(struct selinux_fs_info *fsi);
349+
static int sel_make_bools(struct selinux_fs_info *fsi,
350+
struct selinux_policy *newpolicy);
351+
static int sel_make_classes(struct selinux_fs_info *fsi,
352+
struct selinux_policy *newpolicy);
352353

353354
/* declaration for sel_make_class_dirs */
354355
static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
@@ -508,28 +509,23 @@ static const struct file_operations sel_policy_ops = {
508509
.llseek = generic_file_llseek,
509510
};
510511

511-
static int sel_make_policy_nodes(struct selinux_fs_info *fsi)
512+
static int sel_make_policy_nodes(struct selinux_fs_info *fsi,
513+
struct selinux_policy *newpolicy)
512514
{
513515
int ret;
514516

515-
ret = sel_make_bools(fsi);
517+
ret = sel_make_bools(fsi, newpolicy);
516518
if (ret) {
517519
pr_err("SELinux: failed to load policy booleans\n");
518520
return ret;
519521
}
520522

521-
ret = sel_make_classes(fsi);
523+
ret = sel_make_classes(fsi, newpolicy);
522524
if (ret) {
523525
pr_err("SELinux: failed to load policy classes\n");
524526
return ret;
525527
}
526528

527-
ret = sel_make_policycap(fsi);
528-
if (ret) {
529-
pr_err("SELinux: failed to load policy capabilities\n");
530-
return ret;
531-
}
532-
533529
return 0;
534530
}
535531

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

539535
{
540536
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
537+
struct selinux_policy *newpolicy;
541538
ssize_t length;
542539
void *data = NULL;
543540

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

566-
length = security_load_policy(fsi->state, data, count);
563+
length = security_load_policy(fsi->state, data, count, &newpolicy);
567564
if (length) {
568565
pr_warn_ratelimited("SELinux: failed to load policy\n");
569566
goto out;
570567
}
571568

572-
length = sel_make_policy_nodes(fsi);
573-
if (length)
569+
length = sel_make_policy_nodes(fsi, newpolicy);
570+
if (length) {
571+
selinux_policy_cancel(fsi->state, newpolicy);
574572
goto out1;
573+
}
574+
575+
selinux_policy_commit(fsi->state, newpolicy);
575576

576577
length = count;
577578

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

13341335
#define BOOL_DIR_NAME "booleans"
13351336

1336-
static int sel_make_bools(struct selinux_fs_info *fsi)
1337+
static int sel_make_bools(struct selinux_fs_info *fsi,
1338+
struct selinux_policy *newpolicy)
13371339
{
13381340
int ret;
13391341
ssize_t len;
@@ -1362,7 +1364,7 @@ static int sel_make_bools(struct selinux_fs_info *fsi)
13621364
if (!page)
13631365
goto out;
13641366

1365-
ret = security_get_bools(fsi->state, &num, &names, &values);
1367+
ret = security_get_bools(newpolicy, &num, &names, &values);
13661368
if (ret)
13671369
goto out;
13681370

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

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

1794-
static int sel_make_perm_files(char *objclass, int classvalue,
1795-
struct dentry *dir)
1796+
static int sel_make_perm_files(struct selinux_policy *newpolicy,
1797+
char *objclass, int classvalue,
1798+
struct dentry *dir)
17961799
{
1797-
struct selinux_fs_info *fsi = dir->d_sb->s_fs_info;
17981800
int i, rc, nperms;
17991801
char **perms;
18001802

1801-
rc = security_get_permissions(fsi->state, objclass, &perms, &nperms);
1803+
rc = security_get_permissions(newpolicy, objclass, &perms, &nperms);
18021804
if (rc)
18031805
return rc;
18041806

@@ -1831,8 +1833,9 @@ static int sel_make_perm_files(char *objclass, int classvalue,
18311833
return rc;
18321834
}
18331835

1834-
static int sel_make_class_dir_entries(char *classname, int index,
1835-
struct dentry *dir)
1836+
static int sel_make_class_dir_entries(struct selinux_policy *newpolicy,
1837+
char *classname, int index,
1838+
struct dentry *dir)
18361839
{
18371840
struct super_block *sb = dir->d_sb;
18381841
struct selinux_fs_info *fsi = sb->s_fs_info;
@@ -1858,12 +1861,13 @@ static int sel_make_class_dir_entries(char *classname, int index,
18581861
if (IS_ERR(dentry))
18591862
return PTR_ERR(dentry);
18601863

1861-
rc = sel_make_perm_files(classname, index, dentry);
1864+
rc = sel_make_perm_files(newpolicy, classname, index, dentry);
18621865

18631866
return rc;
18641867
}
18651868

1866-
static int sel_make_classes(struct selinux_fs_info *fsi)
1869+
static int sel_make_classes(struct selinux_fs_info *fsi,
1870+
struct selinux_policy *newpolicy)
18671871
{
18681872

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

1875-
rc = security_get_classes(fsi->state, &classes, &nclasses);
1879+
rc = security_get_classes(newpolicy, &classes, &nclasses);
18761880
if (rc)
18771881
return rc;
18781882

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

18921896
/* i+1 since class values are 1-indexed */
1893-
rc = sel_make_class_dir_entries(classes[i], i + 1,
1897+
rc = sel_make_class_dir_entries(newpolicy, classes[i], i + 1,
18941898
class_name_dir);
18951899
if (rc)
18961900
goto out;
@@ -1909,8 +1913,6 @@ static int sel_make_policycap(struct selinux_fs_info *fsi)
19091913
struct dentry *dentry = NULL;
19101914
struct inode *inode = NULL;
19111915

1912-
sel_remove_entries(fsi->policycap_dir);
1913-
19141916
for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
19151917
if (iter < ARRAY_SIZE(selinux_policycap_names))
19161918
dentry = d_alloc_name(fsi->policycap_dir,
@@ -2075,9 +2077,12 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
20752077
goto err;
20762078
}
20772079

2078-
ret = sel_make_policy_nodes(fsi);
2079-
if (ret)
2080+
ret = sel_make_policycap(fsi);
2081+
if (ret) {
2082+
pr_err("SELinux: failed to load policy capabilities\n");
20802083
goto err;
2084+
}
2085+
20812086
return 0;
20822087
err:
20832088
pr_err("SELinux: %s: failed while creating inodes\n",

0 commit comments

Comments
 (0)