Commit 84196390 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'selinux-pr-20210322' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

Pull selinux fixes from Paul Moore:
 "Three SELinux patches:

   - Fix a problem where a local variable is used outside its associated
     function. Thankfully this can only be triggered by reloading the
     SELinux policy, which is a restricted operation for other obvious
     reasons.

   - Fix some incorrect, and inconsistent, audit and printk messages
     when loading the SELinux policy.

  All three patches are relatively minor and have been through our
  testing with no failures"

* tag 'selinux-pr-20210322' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinuxfs: unify policy load error reporting
  selinux: fix variable scope issue in live sidtab conversion
  selinux: don't log MAC_POLICY_LOAD record on failed policy load
parents 0d02ec6b ee5de60a
...@@ -219,14 +219,21 @@ static inline bool selinux_policycap_genfs_seclabel_symlinks(void) ...@@ -219,14 +219,21 @@ static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]); return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]);
} }
struct selinux_policy_convert_data;
struct selinux_load_state {
struct selinux_policy *policy;
struct selinux_policy_convert_data *convert_data;
};
int security_mls_enabled(struct selinux_state *state); int security_mls_enabled(struct selinux_state *state);
int security_load_policy(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); struct selinux_load_state *load_state);
void selinux_policy_commit(struct selinux_state *state, void selinux_policy_commit(struct selinux_state *state,
struct selinux_policy *newpolicy); struct selinux_load_state *load_state);
void selinux_policy_cancel(struct selinux_state *state, void selinux_policy_cancel(struct selinux_state *state,
struct selinux_policy *policy); struct selinux_load_state *load_state);
int security_read_policy(struct selinux_state *state, int security_read_policy(struct selinux_state *state,
void **data, size_t *len); void **data, size_t *len);
int security_read_state_kernel(struct selinux_state *state, int security_read_state_kernel(struct selinux_state *state,
......
...@@ -563,17 +563,13 @@ static int sel_make_policy_nodes(struct selinux_fs_info *fsi, ...@@ -563,17 +563,13 @@ static int sel_make_policy_nodes(struct selinux_fs_info *fsi,
ret = sel_make_bools(newpolicy, tmp_bool_dir, &tmp_bool_num, ret = sel_make_bools(newpolicy, tmp_bool_dir, &tmp_bool_num,
&tmp_bool_names, &tmp_bool_values); &tmp_bool_names, &tmp_bool_values);
if (ret) { if (ret)
pr_err("SELinux: failed to load policy booleans\n");
goto out; goto out;
}
ret = sel_make_classes(newpolicy, tmp_class_dir, ret = sel_make_classes(newpolicy, tmp_class_dir,
&fsi->last_class_ino); &fsi->last_class_ino);
if (ret) { if (ret)
pr_err("SELinux: failed to load policy classes\n");
goto out; goto out;
}
/* booleans */ /* booleans */
old_dentry = fsi->bool_dir; old_dentry = fsi->bool_dir;
...@@ -616,7 +612,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, ...@@ -616,7 +612,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_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_policy *newpolicy; struct selinux_load_state load_state;
ssize_t length; ssize_t length;
void *data = NULL; void *data = NULL;
...@@ -642,23 +638,23 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, ...@@ -642,23 +638,23 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
if (copy_from_user(data, buf, count) != 0) if (copy_from_user(data, buf, count) != 0)
goto out; goto out;
length = security_load_policy(fsi->state, data, count, &newpolicy); length = security_load_policy(fsi->state, data, count, &load_state);
if (length) { if (length) {
pr_warn_ratelimited("SELinux: failed to load policy\n"); pr_warn_ratelimited("SELinux: failed to load policy\n");
goto out; goto out;
} }
length = sel_make_policy_nodes(fsi, newpolicy); length = sel_make_policy_nodes(fsi, load_state.policy);
if (length) { if (length) {
selinux_policy_cancel(fsi->state, newpolicy); pr_warn_ratelimited("SELinux: failed to initialize selinuxfs\n");
goto out1; selinux_policy_cancel(fsi->state, &load_state);
goto out;
} }
selinux_policy_commit(fsi->state, newpolicy); selinux_policy_commit(fsi->state, &load_state);
length = count; length = count;
out1:
audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
"auid=%u ses=%u lsm=selinux res=1", "auid=%u ses=%u lsm=selinux res=1",
from_kuid(&init_user_ns, audit_get_loginuid(current)), from_kuid(&init_user_ns, audit_get_loginuid(current)),
......
...@@ -67,6 +67,17 @@ ...@@ -67,6 +67,17 @@
#include "policycap_names.h" #include "policycap_names.h"
#include "ima.h" #include "ima.h"
struct convert_context_args {
struct selinux_state *state;
struct policydb *oldp;
struct policydb *newp;
};
struct selinux_policy_convert_data {
struct convert_context_args args;
struct sidtab_convert_params sidtab_params;
};
/* Forward declaration. */ /* Forward declaration. */
static int context_struct_to_string(struct policydb *policydb, static int context_struct_to_string(struct policydb *policydb,
struct context *context, struct context *context,
...@@ -1974,12 +1985,6 @@ static inline int convert_context_handle_invalid_context( ...@@ -1974,12 +1985,6 @@ static inline int convert_context_handle_invalid_context(
return 0; return 0;
} }
struct convert_context_args {
struct selinux_state *state;
struct policydb *oldp;
struct policydb *newp;
};
/* /*
* Convert the values in the security context * Convert the values in the security context
* structure `oldc' from the values specified * structure `oldc' from the values specified
...@@ -2159,7 +2164,7 @@ static void selinux_policy_cond_free(struct selinux_policy *policy) ...@@ -2159,7 +2164,7 @@ static void selinux_policy_cond_free(struct selinux_policy *policy)
} }
void selinux_policy_cancel(struct selinux_state *state, void selinux_policy_cancel(struct selinux_state *state,
struct selinux_policy *policy) struct selinux_load_state *load_state)
{ {
struct selinux_policy *oldpolicy; struct selinux_policy *oldpolicy;
...@@ -2167,7 +2172,8 @@ void selinux_policy_cancel(struct selinux_state *state, ...@@ -2167,7 +2172,8 @@ void selinux_policy_cancel(struct selinux_state *state,
lockdep_is_held(&state->policy_mutex)); lockdep_is_held(&state->policy_mutex));
sidtab_cancel_convert(oldpolicy->sidtab); sidtab_cancel_convert(oldpolicy->sidtab);
selinux_policy_free(policy); selinux_policy_free(load_state->policy);
kfree(load_state->convert_data);
} }
static void selinux_notify_policy_change(struct selinux_state *state, static void selinux_notify_policy_change(struct selinux_state *state,
...@@ -2183,9 +2189,9 @@ static void selinux_notify_policy_change(struct selinux_state *state, ...@@ -2183,9 +2189,9 @@ static void selinux_notify_policy_change(struct selinux_state *state,
} }
void selinux_policy_commit(struct selinux_state *state, void selinux_policy_commit(struct selinux_state *state,
struct selinux_policy *newpolicy) struct selinux_load_state *load_state)
{ {
struct selinux_policy *oldpolicy; struct selinux_policy *oldpolicy, *newpolicy = load_state->policy;
u32 seqno; u32 seqno;
oldpolicy = rcu_dereference_protected(state->policy, oldpolicy = rcu_dereference_protected(state->policy,
...@@ -2225,6 +2231,7 @@ void selinux_policy_commit(struct selinux_state *state, ...@@ -2225,6 +2231,7 @@ void selinux_policy_commit(struct selinux_state *state,
/* Free the old policy */ /* Free the old policy */
synchronize_rcu(); synchronize_rcu();
selinux_policy_free(oldpolicy); selinux_policy_free(oldpolicy);
kfree(load_state->convert_data);
/* Notify others of the policy change */ /* Notify others of the policy change */
selinux_notify_policy_change(state, seqno); selinux_notify_policy_change(state, seqno);
...@@ -2241,11 +2248,10 @@ void selinux_policy_commit(struct selinux_state *state, ...@@ -2241,11 +2248,10 @@ void selinux_policy_commit(struct selinux_state *state,
* loading the new policy. * 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_load_state *load_state)
{ {
struct selinux_policy *newpolicy, *oldpolicy; struct selinux_policy *newpolicy, *oldpolicy;
struct sidtab_convert_params convert_params; struct selinux_policy_convert_data *convert_data;
struct convert_context_args args;
int rc = 0; int rc = 0;
struct policy_file file = { data, len }, *fp = &file; struct policy_file file = { data, len }, *fp = &file;
...@@ -2275,10 +2281,10 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len, ...@@ -2275,10 +2281,10 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
goto err_mapping; goto err_mapping;
} }
if (!selinux_initialized(state)) { if (!selinux_initialized(state)) {
/* First policy load, so no need to preserve state from old policy */ /* First policy load, so no need to preserve state from old policy */
*newpolicyp = newpolicy; load_state->policy = newpolicy;
load_state->convert_data = NULL;
return 0; return 0;
} }
...@@ -2292,29 +2298,38 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len, ...@@ -2292,29 +2298,38 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
goto err_free_isids; goto err_free_isids;
} }
convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL);
if (!convert_data) {
rc = -ENOMEM;
goto err_free_isids;
}
/* /*
* Convert the internal representations of contexts * Convert the internal representations of contexts
* in the new SID table. * in the new SID table.
*/ */
args.state = state; convert_data->args.state = state;
args.oldp = &oldpolicy->policydb; convert_data->args.oldp = &oldpolicy->policydb;
args.newp = &newpolicy->policydb; convert_data->args.newp = &newpolicy->policydb;
convert_params.func = convert_context; convert_data->sidtab_params.func = convert_context;
convert_params.args = &args; convert_data->sidtab_params.args = &convert_data->args;
convert_params.target = newpolicy->sidtab; convert_data->sidtab_params.target = newpolicy->sidtab;
rc = sidtab_convert(oldpolicy->sidtab, &convert_params); rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params);
if (rc) { if (rc) {
pr_err("SELinux: unable to convert the internal" pr_err("SELinux: unable to convert the internal"
" representation of contexts in the new SID" " representation of contexts in the new SID"
" table\n"); " table\n");
goto err_free_isids; goto err_free_convert_data;
} }
*newpolicyp = newpolicy; load_state->policy = newpolicy;
load_state->convert_data = convert_data;
return 0; return 0;
err_free_convert_data:
kfree(convert_data);
err_free_isids: err_free_isids:
sidtab_destroy(newpolicy->sidtab); sidtab_destroy(newpolicy->sidtab);
err_mapping: err_mapping:
......
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