aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/apparmor/apparmorfs.c49
-rw-r--r--security/apparmor/audit.c75
-rw-r--r--security/apparmor/capability.c33
-rw-r--r--security/apparmor/domain.c193
-rw-r--r--security/apparmor/file.c217
-rw-r--r--security/apparmor/include/apparmor.h3
-rw-r--r--security/apparmor/include/audit.h44
-rw-r--r--security/apparmor/include/capability.h3
-rw-r--r--security/apparmor/include/file.h54
-rw-r--r--security/apparmor/include/ipc.h4
-rw-r--r--security/apparmor/include/lib.h2
-rw-r--r--security/apparmor/include/match.h6
-rw-r--r--security/apparmor/include/mount.h26
-rw-r--r--security/apparmor/include/net.h25
-rw-r--r--security/apparmor/include/perms.h7
-rw-r--r--security/apparmor/include/policy.h68
-rw-r--r--security/apparmor/include/policy_ns.h14
-rw-r--r--security/apparmor/include/resource.h3
-rw-r--r--security/apparmor/include/task.h11
-rw-r--r--security/apparmor/ipc.c53
-rw-r--r--security/apparmor/label.c46
-rw-r--r--security/apparmor/lib.c54
-rw-r--r--security/apparmor/lsm.c414
-rw-r--r--security/apparmor/match.c48
-rw-r--r--security/apparmor/mount.c186
-rw-r--r--security/apparmor/net.c65
-rw-r--r--security/apparmor/policy.c133
-rw-r--r--security/apparmor/policy_compat.c1
-rw-r--r--security/apparmor/policy_ns.c37
-rw-r--r--security/apparmor/policy_unpack.c152
-rw-r--r--security/apparmor/resource.c54
-rw-r--r--security/apparmor/task.c104
32 files changed, 1336 insertions, 848 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 53a0070ff5df7..38650e52ef578 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -423,7 +423,7 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
/* high level check about policy management - fine grained in
* below after unpack
*/
- error = aa_may_manage_policy(label, ns, mask);
+ error = aa_may_manage_policy(current_cred(), label, ns, mask);
if (error)
goto end_section;
@@ -486,7 +486,8 @@ static ssize_t profile_remove(struct file *f, const char __user *buf,
/* high level check about policy management - fine grained in
* below after unpack
*/
- error = aa_may_manage_policy(label, ns, AA_MAY_REMOVE_POLICY);
+ error = aa_may_manage_policy(current_cred(), label, ns,
+ AA_MAY_REMOVE_POLICY);
if (error)
goto out;
@@ -618,23 +619,23 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,
if (profile_unconfined(profile))
return;
- if (rules->file.dfa && *match_str == AA_CLASS_FILE) {
- state = aa_dfa_match_len(rules->file.dfa,
- rules->file.start[AA_CLASS_FILE],
+ if (rules->file->dfa && *match_str == AA_CLASS_FILE) {
+ state = aa_dfa_match_len(rules->file->dfa,
+ rules->file->start[AA_CLASS_FILE],
match_str + 1, match_len - 1);
if (state) {
struct path_cond cond = { };
- tmp = *(aa_lookup_fperms(&(rules->file), state, &cond));
+ tmp = *(aa_lookup_fperms(rules->file, state, &cond));
}
- } else if (rules->policy.dfa) {
+ } else if (rules->policy->dfa) {
if (!RULE_MEDIATES(rules, *match_str))
return; /* no change to current perms */
- state = aa_dfa_match_len(rules->policy.dfa,
- rules->policy.start[0],
+ state = aa_dfa_match_len(rules->policy->dfa,
+ rules->policy->start[0],
match_str, match_len);
if (state)
- tmp = *aa_lookup_perms(&rules->policy, state);
+ tmp = *aa_lookup_perms(rules->policy, state);
}
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum_raw(perms, &tmp);
@@ -1095,7 +1096,7 @@ static int seq_profile_attach_show(struct seq_file *seq, void *v)
struct aa_profile *profile = labels_profile(label);
if (profile->attach.xmatch_str)
seq_printf(seq, "%s\n", profile->attach.xmatch_str);
- else if (profile->attach.xmatch.dfa)
+ else if (profile->attach.xmatch->dfa)
seq_puts(seq, "<unknown>\n");
else
seq_printf(seq, "%s\n", profile->base.name);
@@ -1314,7 +1315,6 @@ SEQ_RAWDATA_FOPS(compressed_size);
static int decompress_zstd(char *src, size_t slen, char *dst, size_t dlen)
{
-#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
if (slen < dlen) {
const size_t wksp_len = zstd_dctx_workspace_bound();
zstd_dctx *ctx;
@@ -1341,7 +1341,6 @@ cleanup:
kvfree(wksp);
return ret;
}
-#endif
if (dlen < slen)
return -EINVAL;
@@ -1806,7 +1805,8 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir,
int error;
label = begin_current_label_crit_section();
- error = aa_may_manage_policy(label, NULL, AA_MAY_LOAD_POLICY);
+ error = aa_may_manage_policy(current_cred(), label, NULL,
+ AA_MAY_LOAD_POLICY);
end_current_label_crit_section(label);
if (error)
return error;
@@ -1855,7 +1855,8 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry)
int error;
label = begin_current_label_crit_section();
- error = aa_may_manage_policy(label, NULL, AA_MAY_LOAD_POLICY);
+ error = aa_may_manage_policy(current_cred(), label, NULL,
+ AA_MAY_LOAD_POLICY);
end_current_label_crit_section(label);
if (error)
return error;
@@ -2339,10 +2340,16 @@ static struct aa_sfs_entry aa_sfs_entry_domain[] = {
AA_SFS_FILE_BOOLEAN("post_nnp_subset", 1),
AA_SFS_FILE_BOOLEAN("computed_longest_left", 1),
AA_SFS_DIR("attach_conditions", aa_sfs_entry_attach),
+ AA_SFS_FILE_BOOLEAN("disconnected.path", 1),
AA_SFS_FILE_STRING("version", "1.2"),
{ }
};
+static struct aa_sfs_entry aa_sfs_entry_unconfined[] = {
+ AA_SFS_FILE_BOOLEAN("change_profile", 1),
+ { }
+};
+
static struct aa_sfs_entry aa_sfs_entry_versions[] = {
AA_SFS_FILE_BOOLEAN("v5", 1),
AA_SFS_FILE_BOOLEAN("v6", 1),
@@ -2352,11 +2359,15 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = {
{ }
};
+#define PERMS32STR "allow deny subtree cond kill complain prompt audit quiet hide xindex tag label"
static struct aa_sfs_entry aa_sfs_entry_policy[] = {
AA_SFS_DIR("versions", aa_sfs_entry_versions),
AA_SFS_FILE_BOOLEAN("set_load", 1),
/* number of out of band transitions supported */
AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED),
+ AA_SFS_FILE_U64("permstable32_version", 1),
+ AA_SFS_FILE_STRING("permstable32", PERMS32STR),
+ AA_SFS_DIR("unconfined_restrictions", aa_sfs_entry_unconfined),
{ }
};
@@ -2368,6 +2379,7 @@ static struct aa_sfs_entry aa_sfs_entry_mount[] = {
static struct aa_sfs_entry aa_sfs_entry_ns[] = {
AA_SFS_FILE_BOOLEAN("profile", 1),
AA_SFS_FILE_BOOLEAN("pivot_root", 0),
+ AA_SFS_FILE_STRING("mask", "userns_create"),
{ }
};
@@ -2382,6 +2394,12 @@ static struct aa_sfs_entry aa_sfs_entry_query[] = {
AA_SFS_DIR("label", aa_sfs_entry_query_label),
{ }
};
+
+static struct aa_sfs_entry aa_sfs_entry_io_uring[] = {
+ AA_SFS_FILE_STRING("mask", "sqpoll override_creds"),
+ { }
+};
+
static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("policy", aa_sfs_entry_policy),
AA_SFS_DIR("domain", aa_sfs_entry_domain),
@@ -2395,6 +2413,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace),
AA_SFS_DIR("signal", aa_sfs_entry_signal),
AA_SFS_DIR("query", aa_sfs_entry_query),
+ AA_SFS_DIR("io_uring", aa_sfs_entry_io_uring),
{ }
};
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 5a7978aa4b19e..45beb1c5f747a 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -58,8 +58,8 @@ static const char *const aa_class_names[] = {
"io_uring",
"module",
"lsm",
- "unknown",
- "unknown",
+ "namespace",
+ "io_uring",
"unknown",
"unknown",
"unknown",
@@ -85,37 +85,36 @@ static const char *const aa_class_names[] = {
/**
* audit_pre() - core AppArmor function.
* @ab: audit buffer to fill (NOT NULL)
- * @ca: audit structure containing data to audit (NOT NULL)
+ * @va: audit structure containing data to audit (NOT NULL)
*
- * Record common AppArmor audit data from @sa
+ * Record common AppArmor audit data from @va
*/
-static void audit_pre(struct audit_buffer *ab, void *ca)
+static void audit_pre(struct audit_buffer *ab, void *va)
{
- struct common_audit_data *sa = ca;
+ struct apparmor_audit_data *ad = aad_of_va(va);
if (aa_g_audit_header) {
audit_log_format(ab, "apparmor=\"%s\"",
- aa_audit_type[aad(sa)->type]);
+ aa_audit_type[ad->type]);
}
- if (aad(sa)->op) {
- audit_log_format(ab, " operation=\"%s\"", aad(sa)->op);
- }
+ if (ad->op)
+ audit_log_format(ab, " operation=\"%s\"", ad->op);
- if (aad(sa)->class)
+ if (ad->class)
audit_log_format(ab, " class=\"%s\"",
- aad(sa)->class <= AA_CLASS_LAST ?
- aa_class_names[aad(sa)->class] :
+ ad->class <= AA_CLASS_LAST ?
+ aa_class_names[ad->class] :
"unknown");
- if (aad(sa)->info) {
- audit_log_format(ab, " info=\"%s\"", aad(sa)->info);
- if (aad(sa)->error)
- audit_log_format(ab, " error=%d", aad(sa)->error);
+ if (ad->info) {
+ audit_log_format(ab, " info=\"%s\"", ad->info);
+ if (ad->error)
+ audit_log_format(ab, " error=%d", ad->error);
}
- if (aad(sa)->label) {
- struct aa_label *label = aad(sa)->label;
+ if (ad->subj_label) {
+ struct aa_label *label = ad->subj_label;
if (label_isprofile(label)) {
struct aa_profile *profile = labels_profile(label);
@@ -134,42 +133,44 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
}
}
- if (aad(sa)->name) {
+ if (ad->name) {
audit_log_format(ab, " name=");
- audit_log_untrustedstring(ab, aad(sa)->name);
+ audit_log_untrustedstring(ab, ad->name);
}
}
/**
* aa_audit_msg - Log a message to the audit subsystem
- * @sa: audit event structure (NOT NULL)
+ * @type: audit type for the message
+ * @ad: audit event structure (NOT NULL)
* @cb: optional callback fn for type specific fields (MAYBE NULL)
*/
-void aa_audit_msg(int type, struct common_audit_data *sa,
+void aa_audit_msg(int type, struct apparmor_audit_data *ad,
void (*cb) (struct audit_buffer *, void *))
{
- aad(sa)->type = type;
- common_lsm_audit(sa, audit_pre, cb);
+ ad->type = type;
+ common_lsm_audit(&ad->common, audit_pre, cb);
}
/**
* aa_audit - Log a profile based audit event to the audit subsystem
* @type: audit type for the message
* @profile: profile to check against (NOT NULL)
- * @sa: audit event (NOT NULL)
+ * @ad: audit event (NOT NULL)
* @cb: optional callback fn for type specific fields (MAYBE NULL)
*
* Handle default message switching based off of audit mode flags
*
* Returns: error on failure
*/
-int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
+int aa_audit(int type, struct aa_profile *profile,
+ struct apparmor_audit_data *ad,
void (*cb) (struct audit_buffer *, void *))
{
AA_BUG(!profile);
if (type == AUDIT_APPARMOR_AUTO) {
- if (likely(!aad(sa)->error)) {
+ if (likely(!ad->error)) {
if (AUDIT_MODE(profile) != AUDIT_ALL)
return 0;
type = AUDIT_APPARMOR_AUDIT;
@@ -181,24 +182,24 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
if (AUDIT_MODE(profile) == AUDIT_QUIET ||
(type == AUDIT_APPARMOR_DENIED &&
AUDIT_MODE(profile) == AUDIT_QUIET_DENIED))
- return aad(sa)->error;
+ return ad->error;
if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
type = AUDIT_APPARMOR_KILL;
- aad(sa)->label = &profile->label;
+ ad->subj_label = &profile->label;
- aa_audit_msg(type, sa, cb);
+ aa_audit_msg(type, ad, cb);
- if (aad(sa)->type == AUDIT_APPARMOR_KILL)
+ if (ad->type == AUDIT_APPARMOR_KILL)
(void)send_sig_info(SIGKILL, NULL,
- sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ?
- sa->u.tsk : current);
+ ad->common.type == LSM_AUDIT_DATA_TASK &&
+ ad->common.u.tsk ? ad->common.u.tsk : current);
- if (aad(sa)->type == AUDIT_APPARMOR_ALLOWED)
- return complain_error(aad(sa)->error);
+ if (ad->type == AUDIT_APPARMOR_ALLOWED)
+ return complain_error(ad->error);
- return aad(sa)->error;
+ return ad->error;
}
struct aa_audit_rule {
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
index 326a51838ef28..9934df16c8431 100644
--- a/security/apparmor/capability.c
+++ b/security/apparmor/capability.c
@@ -38,8 +38,8 @@ static DEFINE_PER_CPU(struct audit_cache, audit_cache);
/**
* audit_cb - call back for capability components of audit struct
- * @ab - audit buffer (NOT NULL)
- * @va - audit struct to audit data from (NOT NULL)
+ * @ab: audit buffer (NOT NULL)
+ * @va: audit struct to audit data from (NOT NULL)
*/
static void audit_cb(struct audit_buffer *ab, void *va)
{
@@ -51,7 +51,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
/**
* audit_caps - audit a capability
- * @sa: audit data
+ * @ad: audit data
* @profile: profile being tested for confinement (NOT NULL)
* @cap: capability tested
* @error: error code returned by test
@@ -59,9 +59,9 @@ static void audit_cb(struct audit_buffer *ab, void *va)
* Do auditing of capability and handle, audit/complain/kill modes switching
* and duplicate message elimination.
*
- * Returns: 0 or sa->error on success, error code on failure
+ * Returns: 0 or ad->error on success, error code on failure
*/
-static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
+static int audit_caps(struct apparmor_audit_data *ad, struct aa_profile *profile,
int cap, int error)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
@@ -69,7 +69,7 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
struct audit_cache *ent;
int type = AUDIT_APPARMOR_AUTO;
- aad(sa)->error = error;
+ ad->error = error;
if (likely(!error)) {
/* test if auditing is being forced */
@@ -101,7 +101,7 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
}
put_cpu_var(audit_cache);
- return aa_audit(type, profile, sa, audit_cb);
+ return aa_audit(type, profile, ad, audit_cb);
}
/**
@@ -109,12 +109,12 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
* @profile: profile being enforced (NOT NULL, NOT unconfined)
* @cap: capability to test if allowed
* @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated
- * @sa: audit data (MAY BE NULL indicating no auditing)
+ * @ad: audit data (MAY BE NULL indicating no auditing)
*
* Returns: 0 if allowed else -EPERM
*/
static int profile_capable(struct aa_profile *profile, int cap,
- unsigned int opts, struct common_audit_data *sa)
+ unsigned int opts, struct apparmor_audit_data *ad)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
@@ -132,14 +132,15 @@ static int profile_capable(struct aa_profile *profile, int cap,
/* audit the cap request in complain mode but note that it
* should be optional.
*/
- aad(sa)->info = "optional: no audit";
+ ad->info = "optional: no audit";
}
- return audit_caps(sa, profile, cap, error);
+ return audit_caps(ad, profile, cap, error);
}
/**
* aa_capable - test permission to use capability
+ * @subj_cred: cred we are testing capability against
* @label: label being tested for capability (NOT NULL)
* @cap: capability to be tested
* @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated
@@ -148,15 +149,17 @@ static int profile_capable(struct aa_profile *profile, int cap,
*
* Returns: 0 on success, or else an error code.
*/
-int aa_capable(struct aa_label *label, int cap, unsigned int opts)
+int aa_capable(const struct cred *subj_cred, struct aa_label *label,
+ int cap, unsigned int opts)
{
struct aa_profile *profile;
int error = 0;
- DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, AA_CLASS_CAP, OP_CAPABLE);
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_CAP, AA_CLASS_CAP, OP_CAPABLE);
- sa.u.cap = cap;
+ ad.subj_cred = subj_cred;
+ ad.common.u.cap = cap;
error = fn_for_each_confined(label, profile,
- profile_capable(profile, cap, opts, &sa));
+ profile_capable(profile, cap, opts, &ad));
return error;
}
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index f3715cda59c52..89fbeab4b33bd 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -31,6 +31,7 @@
/**
* may_change_ptraced_domain - check if can change profile on ptraced task
+ * @to_cred: cred of task changing domain
* @to_label: profile to change to (NOT NULL)
* @info: message if there is an error
*
@@ -39,28 +40,34 @@
*
* Returns: %0 or error if change not allowed
*/
-static int may_change_ptraced_domain(struct aa_label *to_label,
+static int may_change_ptraced_domain(const struct cred *to_cred,
+ struct aa_label *to_label,
const char **info)
{
struct task_struct *tracer;
struct aa_label *tracerl = NULL;
+ const struct cred *tracer_cred = NULL;
+
int error = 0;
rcu_read_lock();
tracer = ptrace_parent(current);
- if (tracer)
+ if (tracer) {
/* released below */
tracerl = aa_get_task_label(tracer);
-
+ tracer_cred = get_task_cred(tracer);
+ }
/* not ptraced */
if (!tracer || unconfined(tracerl))
goto out;
- error = aa_may_ptrace(tracerl, to_label, PTRACE_MODE_ATTACH);
+ error = aa_may_ptrace(tracer_cred, tracerl, to_cred, to_label,
+ PTRACE_MODE_ATTACH);
out:
rcu_read_unlock();
aa_put_label(tracerl);
+ put_cred(tracer_cred);
if (error)
*info = "ptrace prevents transition";
@@ -70,7 +77,7 @@ out:
/**** TODO: dedup to aa_label_match - needs perm and dfa, merging
* specifically this is an exact copy of aa_label_match except
* aa_compute_perms is replaced with aa_compute_fperms
- * and policy.dfa with file.dfa
+ * and policy->dfa with file->dfa
****/
/* match a profile and its associated ns component if needed
* Assumes visibility test has already been done.
@@ -86,16 +93,16 @@ static inline aa_state_t match_component(struct aa_profile *profile,
const char *ns_name;
if (stack)
- state = aa_dfa_match(rules->file.dfa, state, "&");
+ state = aa_dfa_match(rules->file->dfa, state, "&");
if (profile->ns == tp->ns)
- return aa_dfa_match(rules->file.dfa, state, tp->base.hname);
+ return aa_dfa_match(rules->file->dfa, state, tp->base.hname);
/* try matching with namespace name and then profile */
ns_name = aa_ns_name(profile->ns, tp->ns, true);
- state = aa_dfa_match_len(rules->file.dfa, state, ":", 1);
- state = aa_dfa_match(rules->file.dfa, state, ns_name);
- state = aa_dfa_match_len(rules->file.dfa, state, ":", 1);
- return aa_dfa_match(rules->file.dfa, state, tp->base.hname);
+ state = aa_dfa_match_len(rules->file->dfa, state, ":", 1);
+ state = aa_dfa_match(rules->file->dfa, state, ns_name);
+ state = aa_dfa_match_len(rules->file->dfa, state, ":", 1);
+ return aa_dfa_match(rules->file->dfa, state, tp->base.hname);
}
/**
@@ -143,12 +150,12 @@ next:
label_for_each_cont(i, label, tp) {
if (!aa_ns_visible(profile->ns, tp->ns, subns))
continue;
- state = aa_dfa_match(rules->file.dfa, state, "//&");
+ state = aa_dfa_match(rules->file->dfa, state, "//&");
state = match_component(profile, tp, false, state);
if (!state)
goto fail;
}
- *perms = *(aa_lookup_fperms(&(rules->file), state, &cond));
+ *perms = *(aa_lookup_fperms(rules->file, state, &cond));
aa_apply_modes_to_perms(profile, perms);
if ((perms->allow & request) != request)
return -EACCES;
@@ -203,7 +210,7 @@ static int label_components_match(struct aa_profile *profile,
return 0;
next:
- tmp = *(aa_lookup_fperms(&(rules->file), state, &cond));
+ tmp = *(aa_lookup_fperms(rules->file, state, &cond));
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
label_for_each_cont(i, label, tp) {
@@ -212,7 +219,7 @@ next:
state = match_component(profile, tp, stack, start);
if (!state)
goto fail;
- tmp = *(aa_lookup_fperms(&(rules->file), state, &cond));
+ tmp = *(aa_lookup_fperms(rules->file, state, &cond));
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
}
@@ -265,6 +272,7 @@ static int label_match(struct aa_profile *profile, struct aa_label *label,
* @stack: whether this is a stacking request
* @request: requested perms
* @start: state to start matching in
+ * @perms: Returns computed perms (NOT NULL)
*
*
* Returns: permission set
@@ -309,7 +317,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
might_sleep();
/* transition from exec match to xattr set */
- state = aa_dfa_outofband_transition(attach->xmatch.dfa, state);
+ state = aa_dfa_outofband_transition(attach->xmatch->dfa, state);
d = bprm->file->f_path.dentry;
for (i = 0; i < attach->xattr_count; i++) {
@@ -323,20 +331,20 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
* that not present xattr can be distinguished from a 0
* length value or rule that matches any value
*/
- state = aa_dfa_null_transition(attach->xmatch.dfa,
+ state = aa_dfa_null_transition(attach->xmatch->dfa,
state);
/* Check xattr value */
- state = aa_dfa_match_len(attach->xmatch.dfa, state,
+ state = aa_dfa_match_len(attach->xmatch->dfa, state,
value, size);
- index = ACCEPT_TABLE(attach->xmatch.dfa)[state];
- perm = attach->xmatch.perms[index].allow;
+ index = ACCEPT_TABLE(attach->xmatch->dfa)[state];
+ perm = attach->xmatch->perms[index].allow;
if (!(perm & MAY_EXEC)) {
ret = -EINVAL;
goto out;
}
}
/* transition to next element */
- state = aa_dfa_outofband_transition(attach->xmatch.dfa, state);
+ state = aa_dfa_outofband_transition(attach->xmatch->dfa, state);
if (size < 0) {
/*
* No xattr match, so verify if transition to
@@ -359,11 +367,11 @@ out:
/**
* find_attach - do attachment search for unconfined processes
- * @bprm - binprm structure of transitioning task
+ * @bprm: binprm structure of transitioning task
* @ns: the current namespace (NOT NULL)
- * @head - profile list to walk (NOT NULL)
- * @name - to match against (NOT NULL)
- * @info - info message if there was an error (NOT NULL)
+ * @head: profile list to walk (NOT NULL)
+ * @name: to match against (NOT NULL)
+ * @info: info message if there was an error (NOT NULL)
*
* Do a linear search on the profiles in the list. There is a matching
* preference where an exact match is preferred over a name which uses
@@ -405,16 +413,16 @@ restart:
* as another profile, signal a conflict and refuse to
* match.
*/
- if (attach->xmatch.dfa) {
+ if (attach->xmatch->dfa) {
unsigned int count;
aa_state_t state;
u32 index, perm;
- state = aa_dfa_leftmatch(attach->xmatch.dfa,
- attach->xmatch.start[AA_CLASS_XMATCH],
+ state = aa_dfa_leftmatch(attach->xmatch->dfa,
+ attach->xmatch->start[AA_CLASS_XMATCH],
name, &count);
- index = ACCEPT_TABLE(attach->xmatch.dfa)[state];
- perm = attach->xmatch.perms[index].allow;
+ index = ACCEPT_TABLE(attach->xmatch->dfa)[state];
+ perm = attach->xmatch->perms[index].allow;
/* any accepting state means a valid match. */
if (perm & MAY_EXEC) {
int ret = 0;
@@ -517,7 +525,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
/* TODO: move lookup parsing to unpack time so this is a straight
* index into the resultant label
*/
- for (*name = rules->file.trans.table[index]; !label && *name;
+ for (*name = rules->file->trans.table[index]; !label && *name;
*name = next_name(xtype, *name)) {
if (xindex & AA_X_CHILD) {
struct aa_profile *new_profile;
@@ -545,6 +553,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
* @name: name to lookup (NOT NULL)
* @xindex: index into x transition table
* @lookupname: returns: name used in lookup if one was specified (NOT NULL)
+ * @info: info message if there was an error (NOT NULL)
*
* find label for a transition index
*
@@ -570,7 +579,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
break;
case AA_X_TABLE:
/* TODO: fix when perm mapping done at unload */
- stack = rules->file.trans.table[xindex & AA_X_INDEX_MASK];
+ stack = rules->file->trans.table[xindex & AA_X_INDEX_MASK];
if (*stack != '&') {
/* released by caller */
new = x_table_lookup(profile, xindex, lookupname);
@@ -619,7 +628,8 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
return new;
}
-static struct aa_label *profile_transition(struct aa_profile *profile,
+static struct aa_label *profile_transition(const struct cred *subj_cred,
+ struct aa_profile *profile,
const struct linux_binprm *bprm,
char *buffer, struct path_cond *cond,
bool *secure_exec)
@@ -628,7 +638,7 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
typeof(*rules), list);
struct aa_label *new = NULL;
const char *info = NULL, *name = NULL, *target = NULL;
- aa_state_t state = rules->file.start[AA_CLASS_FILE];
+ aa_state_t state = rules->file->start[AA_CLASS_FILE];
struct aa_perms perms = {};
bool nonewprivs = false;
int error = 0;
@@ -662,7 +672,7 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
}
/* find exec permissions for name */
- state = aa_str_perms(&(rules->file), state, name, cond, &perms);
+ state = aa_str_perms(rules->file, state, name, cond, &perms);
if (perms.allow & MAY_EXEC) {
/* exec permission determine how to transition */
new = x_to_label(profile, bprm, name, perms.xindex, &target,
@@ -709,7 +719,8 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
}
audit:
- aa_audit_file(profile, &perms, OP_EXEC, MAY_EXEC, name, target, new,
+ aa_audit_file(subj_cred, profile, &perms, OP_EXEC, MAY_EXEC, name,
+ target, new,
cond->uid, info, error);
if (!new || nonewprivs) {
aa_put_label(new);
@@ -719,14 +730,15 @@ audit:
return new;
}
-static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec,
+static int profile_onexec(const struct cred *subj_cred,
+ struct aa_profile *profile, struct aa_label *onexec,
bool stack, const struct linux_binprm *bprm,
char *buffer, struct path_cond *cond,
bool *secure_exec)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
- aa_state_t state = rules->file.start[AA_CLASS_FILE];
+ aa_state_t state = rules->file->start[AA_CLASS_FILE];
struct aa_perms perms = {};
const char *xname = NULL, *info = "change_profile onexec";
int error = -EACCES;
@@ -759,7 +771,7 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec,
}
/* find exec permissions for name */
- state = aa_str_perms(&(rules->file), state, xname, cond, &perms);
+ state = aa_str_perms(rules->file, state, xname, cond, &perms);
if (!(perms.allow & AA_MAY_ONEXEC)) {
info = "no change_onexec valid for executable";
goto audit;
@@ -768,7 +780,7 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec,
* onexec permission is linked to exec with a standard pairing
* exec\0change_profile
*/
- state = aa_dfa_null_transition(rules->file.dfa, state);
+ state = aa_dfa_null_transition(rules->file->dfa, state);
error = change_profile_perms(profile, onexec, stack, AA_MAY_ONEXEC,
state, &perms);
if (error) {
@@ -787,13 +799,15 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec,
}
audit:
- return aa_audit_file(profile, &perms, OP_EXEC, AA_MAY_ONEXEC, xname,
+ return aa_audit_file(subj_cred, profile, &perms, OP_EXEC,
+ AA_MAY_ONEXEC, xname,
NULL, onexec, cond->uid, info, error);
}
/* ensure none ns domain transitions are correctly applied with onexec */
-static struct aa_label *handle_onexec(struct aa_label *label,
+static struct aa_label *handle_onexec(const struct cred *subj_cred,
+ struct aa_label *label,
struct aa_label *onexec, bool stack,
const struct linux_binprm *bprm,
char *buffer, struct path_cond *cond,
@@ -810,26 +824,28 @@ static struct aa_label *handle_onexec(struct aa_label *label,
if (!stack) {
error = fn_for_each_in_ns(label, profile,
- profile_onexec(profile, onexec, stack,
+ profile_onexec(subj_cred, profile, onexec, stack,
bprm, buffer, cond, unsafe));
if (error)
return ERR_PTR(error);
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
aa_get_newest_label(onexec),
- profile_transition(profile, bprm, buffer,
+ profile_transition(subj_cred, profile, bprm,
+ buffer,
cond, unsafe));
} else {
/* TODO: determine how much we want to loosen this */
error = fn_for_each_in_ns(label, profile,
- profile_onexec(profile, onexec, stack, bprm,
+ profile_onexec(subj_cred, profile, onexec, stack, bprm,
buffer, cond, unsafe));
if (error)
return ERR_PTR(error);
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
aa_label_merge(&profile->label, onexec,
GFP_KERNEL),
- profile_transition(profile, bprm, buffer,
+ profile_transition(subj_cred, profile, bprm,
+ buffer,
cond, unsafe));
}
@@ -838,7 +854,8 @@ static struct aa_label *handle_onexec(struct aa_label *label,
/* TODO: get rid of GLOBAL_ROOT_UID */
error = fn_for_each_in_ns(label, profile,
- aa_audit_file(profile, &nullperms, OP_CHANGE_ONEXEC,
+ aa_audit_file(subj_cred, profile, &nullperms,
+ OP_CHANGE_ONEXEC,
AA_MAY_ONEXEC, bprm->filename, NULL,
onexec, GLOBAL_ROOT_UID,
"failed to build target label", -ENOMEM));
@@ -857,6 +874,7 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
{
struct aa_task_ctx *ctx;
struct aa_label *label, *new = NULL;
+ const struct cred *subj_cred;
struct aa_profile *profile;
char *buffer = NULL;
const char *info = NULL;
@@ -869,6 +887,7 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
file_inode(bprm->file)->i_mode
};
+ subj_cred = current_cred();
ctx = task_ctx(current);
AA_BUG(!cred_label(bprm->cred));
AA_BUG(!ctx);
@@ -895,11 +914,12 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
/* Test for onexec first as onexec override other x transitions. */
if (ctx->onexec)
- new = handle_onexec(label, ctx->onexec, ctx->token,
+ new = handle_onexec(subj_cred, label, ctx->onexec, ctx->token,
bprm, buffer, &cond, &unsafe);
else
new = fn_label_build(label, profile, GFP_KERNEL,
- profile_transition(profile, bprm, buffer,
+ profile_transition(subj_cred, profile, bprm,
+ buffer,
&cond, &unsafe));
AA_BUG(!new);
@@ -934,7 +954,7 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
if (bprm->unsafe & (LSM_UNSAFE_PTRACE)) {
/* TODO: test needs to be profile of label to new */
- error = may_change_ptraced_domain(new, &info);
+ error = may_change_ptraced_domain(bprm->cred, new, &info);
if (error)
goto audit;
}
@@ -971,7 +991,8 @@ done:
audit:
error = fn_for_each(label, profile,
- aa_audit_file(profile, &nullperms, OP_EXEC, MAY_EXEC,
+ aa_audit_file(current_cred(), profile, &nullperms,
+ OP_EXEC, MAY_EXEC,
bprm->filename, NULL, new,
vfsuid_into_kuid(vfsuid), info, error));
aa_put_label(new);
@@ -987,7 +1008,8 @@ audit:
*
* Returns: label for hat transition OR ERR_PTR. Does NOT return NULL
*/
-static struct aa_label *build_change_hat(struct aa_profile *profile,
+static struct aa_label *build_change_hat(const struct cred *subj_cred,
+ struct aa_profile *profile,
const char *name, bool sibling)
{
struct aa_profile *root, *hat = NULL;
@@ -1019,7 +1041,8 @@ static struct aa_label *build_change_hat(struct aa_profile *profile,
aa_put_profile(root);
audit:
- aa_audit_file(profile, &nullperms, OP_CHANGE_HAT, AA_MAY_CHANGEHAT,
+ aa_audit_file(subj_cred, profile, &nullperms, OP_CHANGE_HAT,
+ AA_MAY_CHANGEHAT,
name, hat ? hat->base.hname : NULL,
hat ? &hat->label : NULL, GLOBAL_ROOT_UID, info,
error);
@@ -1035,7 +1058,8 @@ audit:
*
* Returns: label for hat transition or ERR_PTR. Does not return NULL
*/
-static struct aa_label *change_hat(struct aa_label *label, const char *hats[],
+static struct aa_label *change_hat(const struct cred *subj_cred,
+ struct aa_label *label, const char *hats[],
int count, int flags)
{
struct aa_profile *profile, *root, *hat = NULL;
@@ -1111,7 +1135,8 @@ fail:
*/
/* TODO: get rid of GLOBAL_ROOT_UID */
if (count > 1 || COMPLAIN_MODE(profile)) {
- aa_audit_file(profile, &nullperms, OP_CHANGE_HAT,
+ aa_audit_file(subj_cred, profile, &nullperms,
+ OP_CHANGE_HAT,
AA_MAY_CHANGEHAT, name, NULL, NULL,
GLOBAL_ROOT_UID, info, error);
}
@@ -1120,7 +1145,8 @@ fail:
build:
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
- build_change_hat(profile, name, sibling),
+ build_change_hat(subj_cred, profile, name,
+ sibling),
aa_get_label(&profile->label));
if (!new) {
info = "label build failed";
@@ -1150,7 +1176,7 @@ build:
*/
int aa_change_hat(const char *hats[], int count, u64 token, int flags)
{
- const struct cred *cred;
+ const struct cred *subj_cred;
struct aa_task_ctx *ctx = task_ctx(current);
struct aa_label *label, *previous, *new = NULL, *target = NULL;
struct aa_profile *profile;
@@ -1159,8 +1185,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
int error = 0;
/* released below */
- cred = get_current_cred();
- label = aa_get_newest_cred_label(cred);
+ subj_cred = get_current_cred();
+ label = aa_get_newest_cred_label(subj_cred);
previous = aa_get_newest_label(ctx->previous);
/*
@@ -1180,7 +1206,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
}
if (count) {
- new = change_hat(label, hats, count, flags);
+ new = change_hat(subj_cred, label, hats, count, flags);
AA_BUG(!new);
if (IS_ERR(new)) {
error = PTR_ERR(new);
@@ -1189,7 +1215,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
goto out;
}
- error = may_change_ptraced_domain(new, &info);
+ /* target cred is the same as current except new label */
+ error = may_change_ptraced_domain(subj_cred, new, &info);
if (error)
goto fail;
@@ -1242,7 +1269,7 @@ out:
aa_put_label(new);
aa_put_label(previous);
aa_put_label(label);
- put_cred(cred);
+ put_cred(subj_cred);
return error;
@@ -1252,7 +1279,7 @@ kill:
fail:
fn_for_each_in_ns(label, profile,
- aa_audit_file(profile, &perms, OP_CHANGE_HAT,
+ aa_audit_file(subj_cred, profile, &perms, OP_CHANGE_HAT,
AA_MAY_CHANGEHAT, NULL, NULL, target,
GLOBAL_ROOT_UID, info, error));
@@ -1261,6 +1288,7 @@ fail:
static int change_profile_perms_wrapper(const char *op, const char *name,
+ const struct cred *subj_cred,
struct aa_profile *profile,
struct aa_label *target, bool stack,
u32 request, struct aa_perms *perms)
@@ -1272,16 +1300,19 @@ static int change_profile_perms_wrapper(const char *op, const char *name,
if (!error)
error = change_profile_perms(profile, target, stack, request,
- rules->file.start[AA_CLASS_FILE],
+ rules->file->start[AA_CLASS_FILE],
perms);
if (error)
- error = aa_audit_file(profile, perms, op, request, name,
+ error = aa_audit_file(subj_cred, profile, perms, op, request,
+ name,
NULL, target, GLOBAL_ROOT_UID, info,
error);
return error;
}
+const char *stack_msg = "change_profile unprivileged unconfined converted to stacking";
+
/**
* aa_change_profile - perform a one-way profile transition
* @fqname: name of profile may include namespace (NOT NULL)
@@ -1304,6 +1335,7 @@ int aa_change_profile(const char *fqname, int flags)
const char *auditname = fqname; /* retain leading & if stack */
bool stack = flags & AA_CHANGE_STACK;
struct aa_task_ctx *ctx = task_ctx(current);
+ const struct cred *subj_cred = get_current_cred();
int error = 0;
char *op;
u32 request;
@@ -1340,6 +1372,28 @@ int aa_change_profile(const char *fqname, int flags)
op = OP_CHANGE_PROFILE;
}
+ /* This should move to a per profile test. Requires pushing build
+ * into callback
+ */
+ if (!stack && unconfined(label) &&
+ label == &labels_ns(label)->unconfined->label &&
+ aa_unprivileged_unconfined_restricted &&
+ /* TODO: refactor so this check is a fn */
+ cap_capable(current_cred(), &init_user_ns, CAP_MAC_OVERRIDE,
+ CAP_OPT_NOAUDIT)) {
+ /* regardless of the request in this case apparmor
+ * stacks against unconfined so admin set policy can't be
+ * by-passed
+ */
+ stack = true;
+ perms.audit = request;
+ (void) fn_for_each_in_ns(label, profile,
+ aa_audit_file(subj_cred, profile, &perms, op,
+ request, auditname, NULL, target,
+ GLOBAL_ROOT_UID, stack_msg, 0));
+ perms.audit = 0;
+ }
+
if (*fqname == '&') {
stack = true;
/* don't have label_parse() do stacking */
@@ -1381,6 +1435,7 @@ int aa_change_profile(const char *fqname, int flags)
*/
error = fn_for_each_in_ns(label, profile,
change_profile_perms_wrapper(op, auditname,
+ subj_cred,
profile, target, stack,
request, &perms));
if (error)
@@ -1391,7 +1446,7 @@ int aa_change_profile(const char *fqname, int flags)
check:
/* check if tracing task is allowed to trace target domain */
- error = may_change_ptraced_domain(target, &info);
+ error = may_change_ptraced_domain(subj_cred, target, &info);
if (error && !fn_for_each_in_ns(label, profile,
COMPLAIN_MODE(profile)))
goto audit;
@@ -1446,12 +1501,13 @@ check:
}
/* full transition will be built in exec path */
- error = aa_set_current_onexec(target, stack);
+ aa_set_current_onexec(target, stack);
}
audit:
error = fn_for_each_in_ns(label, profile,
- aa_audit_file(profile, &perms, op, request, auditname,
+ aa_audit_file(subj_cred,
+ profile, &perms, op, request, auditname,
NULL, new ? new : target,
GLOBAL_ROOT_UID, info, error));
@@ -1459,6 +1515,7 @@ out:
aa_put_label(new);
aa_put_label(target);
aa_put_label(label);
+ put_cred(subj_cred);
return error;
}
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index 698b124e649f6..c03eb7c19f162 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -44,38 +44,40 @@ static u32 map_mask_to_chr_mask(u32 mask)
static void file_audit_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
- kuid_t fsuid = current_fsuid();
+ struct apparmor_audit_data *ad = aad(sa);
+ kuid_t fsuid = ad->subj_cred ? ad->subj_cred->fsuid : current_fsuid();
char str[10];
- if (aad(sa)->request & AA_AUDIT_FILE_MASK) {
+ if (ad->request & AA_AUDIT_FILE_MASK) {
aa_perm_mask_to_str(str, sizeof(str), aa_file_perm_chrs,
- map_mask_to_chr_mask(aad(sa)->request));
+ map_mask_to_chr_mask(ad->request));
audit_log_format(ab, " requested_mask=\"%s\"", str);
}
- if (aad(sa)->denied & AA_AUDIT_FILE_MASK) {
+ if (ad->denied & AA_AUDIT_FILE_MASK) {
aa_perm_mask_to_str(str, sizeof(str), aa_file_perm_chrs,
- map_mask_to_chr_mask(aad(sa)->denied));
+ map_mask_to_chr_mask(ad->denied));
audit_log_format(ab, " denied_mask=\"%s\"", str);
}
- if (aad(sa)->request & AA_AUDIT_FILE_MASK) {
+ if (ad->request & AA_AUDIT_FILE_MASK) {
audit_log_format(ab, " fsuid=%d",
from_kuid(&init_user_ns, fsuid));
audit_log_format(ab, " ouid=%d",
- from_kuid(&init_user_ns, aad(sa)->fs.ouid));
+ from_kuid(&init_user_ns, ad->fs.ouid));
}
- if (aad(sa)->peer) {
+ if (ad->peer) {
audit_log_format(ab, " target=");
- aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+ aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
FLAG_VIEW_SUBNS, GFP_KERNEL);
- } else if (aad(sa)->fs.target) {
+ } else if (ad->fs.target) {
audit_log_format(ab, " target=");
- audit_log_untrustedstring(ab, aad(sa)->fs.target);
+ audit_log_untrustedstring(ab, ad->fs.target);
}
}
/**
* aa_audit_file - handle the auditing of file operations
+ * @subj_cred: cred of the subject
* @profile: the profile being enforced (NOT NULL)
* @perms: the permissions computed for the request (NOT NULL)
* @op: operation being mediated
@@ -89,59 +91,74 @@ static void file_audit_cb(struct audit_buffer *ab, void *va)
*
* Returns: %0 or error on failure
*/
-int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms,
+int aa_audit_file(const struct cred *subj_cred,
+ struct aa_profile *profile, struct aa_perms *perms,
const char *op, u32 request, const char *name,
const char *target, struct aa_label *tlabel,
kuid_t ouid, const char *info, int error)
{
int type = AUDIT_APPARMOR_AUTO;
- DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_TASK, AA_CLASS_FILE, op);
-
- sa.u.tsk = NULL;
- aad(&sa)->request = request;
- aad(&sa)->name = name;
- aad(&sa)->fs.target = target;
- aad(&sa)->peer = tlabel;
- aad(&sa)->fs.ouid = ouid;
- aad(&sa)->info = info;
- aad(&sa)->error = error;
- sa.u.tsk = NULL;
-
- if (likely(!aad(&sa)->error)) {
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_TASK, AA_CLASS_FILE, op);
+
+ ad.subj_cred = subj_cred;
+ ad.request = request;
+ ad.name = name;
+ ad.fs.target = target;
+ ad.peer = tlabel;
+ ad.fs.ouid = ouid;
+ ad.info = info;
+ ad.error = error;
+ ad.common.u.tsk = NULL;
+
+ if (likely(!ad.error)) {
u32 mask = perms->audit;
if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
mask = 0xffff;
/* mask off perms that are not being force audited */
- aad(&sa)->request &= mask;
+ ad.request &= mask;
- if (likely(!aad(&sa)->request))
+ if (likely(!ad.request))
return 0;
type = AUDIT_APPARMOR_AUDIT;
} else {
/* only report permissions that were denied */
- aad(&sa)->request = aad(&sa)->request & ~perms->allow;
- AA_BUG(!aad(&sa)->request);
+ ad.request = ad.request & ~perms->allow;
+ AA_BUG(!ad.request);
- if (aad(&sa)->request & perms->kill)
+ if (ad.request & perms->kill)
type = AUDIT_APPARMOR_KILL;
/* quiet known rejects, assumes quiet and kill do not overlap */
- if ((aad(&sa)->request & perms->quiet) &&
+ if ((ad.request & perms->quiet) &&
AUDIT_MODE(profile) != AUDIT_NOQUIET &&
AUDIT_MODE(profile) != AUDIT_ALL)
- aad(&sa)->request &= ~perms->quiet;
+ ad.request &= ~perms->quiet;
- if (!aad(&sa)->request)
- return aad(&sa)->error;
+ if (!ad.request)
+ return ad.error;
}
- aad(&sa)->denied = aad(&sa)->request & ~perms->allow;
- return aa_audit(type, profile, &sa, file_audit_cb);
+ ad.denied = ad.request & ~perms->allow;
+ return aa_audit(type, profile, &ad, file_audit_cb);
}
-static int path_name(const char *op, struct aa_label *label,
+/**
+ * is_deleted - test if a file has been completely unlinked
+ * @dentry: dentry of file to test for deletion (NOT NULL)
+ *
+ * Returns: true if deleted else false
+ */
+static inline bool is_deleted(struct dentry *dentry)
+{
+ if (d_unlinked(dentry) && d_backing_inode(dentry)->i_nlink == 0)
+ return true;
+ return false;
+}
+
+static int path_name(const char *op, const struct cred *subj_cred,
+ struct aa_label *label,
const struct path *path, int flags, char *buffer,
const char **name, struct path_cond *cond, u32 request)
{
@@ -153,7 +170,8 @@ static int path_name(const char *op, struct aa_label *label,
labels_profile(label)->disconnected);
if (error) {
fn_for_each_confined(label, profile,
- aa_audit_file(profile, &nullperms, op, request, *name,
+ aa_audit_file(subj_cred,
+ profile, &nullperms, op, request, *name,
NULL, NULL, cond->uid, info, error));
return error;
}
@@ -164,7 +182,7 @@ static int path_name(const char *op, struct aa_label *label,
struct aa_perms default_perms = {};
/**
* aa_lookup_fperms - convert dfa compressed perms to internal perms
- * @dfa: dfa to lookup perms for (NOT NULL)
+ * @file_rules: the aa_policydb to lookup perms for (NOT NULL)
* @state: state in dfa
* @cond: conditions to consider (NOT NULL)
*
@@ -188,8 +206,8 @@ struct aa_perms *aa_lookup_fperms(struct aa_policydb *file_rules,
/**
* aa_str_perms - find permission that match @name
- * @dfa: to match against (MAYBE NULL)
- * @state: state to start matching in
+ * @file_rules: the aa_policydb to match against (NOT NULL)
+ * @start: state to start matching in
* @name: string to match against dfa (NOT NULL)
* @cond: conditions to consider for permission set computation (NOT NULL)
* @perms: Returns - the permissions found when matching @name
@@ -207,9 +225,9 @@ aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start,
return state;
}
-static int __aa_path_perm(const char *op, struct aa_profile *profile,
- const char *name, u32 request,
- struct path_cond *cond, int flags,
+static int __aa_path_perm(const char *op, const struct cred *subj_cred,
+ struct aa_profile *profile, const char *name,
+ u32 request, struct path_cond *cond, int flags,
struct aa_perms *perms)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
@@ -218,16 +236,18 @@ static int __aa_path_perm(const char *op, struct aa_profile *profile,
if (profile_unconfined(profile))
return 0;
- aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE],
+ aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE],
name, cond, perms);
if (request & ~perms->allow)
e = -EACCES;
- return aa_audit_file(profile, perms, op, request, name, NULL, NULL,
+ return aa_audit_file(subj_cred,
+ profile, perms, op, request, name, NULL, NULL,
cond->uid, NULL, e);
}
-static int profile_path_perm(const char *op, struct aa_profile *profile,
+static int profile_path_perm(const char *op, const struct cred *subj_cred,
+ struct aa_profile *profile,
const struct path *path, char *buffer, u32 request,
struct path_cond *cond, int flags,
struct aa_perms *perms)
@@ -238,18 +258,19 @@ static int profile_path_perm(const char *op, struct aa_profile *profile,
if (profile_unconfined(profile))
return 0;
- error = path_name(op, &profile->label, path,
+ error = path_name(op, subj_cred, &profile->label, path,
flags | profile->path_flags, buffer, &name, cond,
request);
if (error)
return error;
- return __aa_path_perm(op, profile, name, request, cond, flags,
- perms);
+ return __aa_path_perm(op, subj_cred, profile, name, request, cond,
+ flags, perms);
}
/**
* aa_path_perm - do permissions check & audit for @path
* @op: operation being checked
+ * @subj_cred: subject cred
* @label: profile being enforced (NOT NULL)
* @path: path to check permissions of (NOT NULL)
* @flags: any additional path flags beyond what the profile specifies
@@ -258,7 +279,8 @@ static int profile_path_perm(const char *op, struct aa_profile *profile,
*
* Returns: %0 else error if access denied or other error
*/
-int aa_path_perm(const char *op, struct aa_label *label,
+int aa_path_perm(const char *op, const struct cred *subj_cred,
+ struct aa_label *label,
const struct path *path, int flags, u32 request,
struct path_cond *cond)
{
@@ -273,8 +295,8 @@ int aa_path_perm(const char *op, struct aa_label *label,
if (!buffer)
return -ENOMEM;
error = fn_for_each_confined(label, profile,
- profile_path_perm(op, profile, path, buffer, request,
- cond, flags, &perms));
+ profile_path_perm(op, subj_cred, profile, path, buffer,
+ request, cond, flags, &perms));
aa_put_buffer(buffer);
@@ -301,7 +323,8 @@ static inline bool xindex_is_subset(u32 link, u32 target)
return true;
}
-static int profile_path_link(struct aa_profile *profile,
+static int profile_path_link(const struct cred *subj_cred,
+ struct aa_profile *profile,
const struct path *link, char *buffer,
const struct path *target, char *buffer2,
struct path_cond *cond)
@@ -315,29 +338,31 @@ static int profile_path_link(struct aa_profile *profile,
aa_state_t state;
int error;
- error = path_name(OP_LINK, &profile->label, link, profile->path_flags,
+ error = path_name(OP_LINK, subj_cred, &profile->label, link,
+ profile->path_flags,
buffer, &lname, cond, AA_MAY_LINK);
if (error)
goto audit;
/* buffer2 freed below, tname is pointer in buffer2 */
- error = path_name(OP_LINK, &profile->label, target, profile->path_flags,
+ error = path_name(OP_LINK, subj_cred, &profile->label, target,
+ profile->path_flags,
buffer2, &tname, cond, AA_MAY_LINK);
if (error)
goto audit;
error = -EACCES;
/* aa_str_perms - handles the case of the dfa being NULL */
- state = aa_str_perms(&(rules->file),
- rules->file.start[AA_CLASS_FILE], lname,
+ state = aa_str_perms(rules->file,
+ rules->file->start[AA_CLASS_FILE], lname,
cond, &lperms);
if (!(lperms.allow & AA_MAY_LINK))
goto audit;
/* test to see if target can be paired with link */
- state = aa_dfa_null_transition(rules->file.dfa, state);
- aa_str_perms(&(rules->file), state, tname, cond, &perms);
+ state = aa_dfa_null_transition(rules->file->dfa, state);
+ aa_str_perms(rules->file, state, tname, cond, &perms);
/* force audit/quiet masks for link are stored in the second entry
* in the link pair.
@@ -359,7 +384,7 @@ static int profile_path_link(struct aa_profile *profile,
/* Do link perm subset test requiring allowed permission on link are
* a subset of the allowed permissions on target.
*/
- aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE],
+ aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE],
tname, cond, &perms);
/* AA_MAY_LINK is not considered in the subset test */
@@ -381,12 +406,14 @@ done_tests:
error = 0;
audit:
- return aa_audit_file(profile, &lperms, OP_LINK, request, lname, tname,
+ return aa_audit_file(subj_cred,
+ profile, &lperms, OP_LINK, request, lname, tname,
NULL, cond->uid, info, error);
}
/**
* aa_path_link - Handle hard link permission check
+ * @subj_cred: subject cred
* @label: the label being enforced (NOT NULL)
* @old_dentry: the target dentry (NOT NULL)
* @new_dir: directory the new link will be created in (NOT NULL)
@@ -403,7 +430,8 @@ audit:
*
* Returns: %0 if allowed else error
*/
-int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
+int aa_path_link(const struct cred *subj_cred,
+ struct aa_label *label, struct dentry *old_dentry,
const struct path *new_dir, struct dentry *new_dentry)
{
struct path link = { .mnt = new_dir->mnt, .dentry = new_dentry };
@@ -424,8 +452,8 @@ int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
goto out;
error = fn_for_each_confined(label, profile,
- profile_path_link(profile, &link, buffer, &target,
- buffer2, &cond));
+ profile_path_link(subj_cred, profile, &link, buffer,
+ &target, buffer2, &cond));
out:
aa_put_buffer(buffer);
aa_put_buffer(buffer2);
@@ -453,7 +481,8 @@ static void update_file_ctx(struct aa_file_ctx *fctx, struct aa_label *label,
spin_unlock(&fctx->lock);
}
-static int __file_path_perm(const char *op, struct aa_label *label,
+static int __file_path_perm(const char *op, const struct cred *subj_cred,
+ struct aa_label *label,
struct aa_label *flabel, struct file *file,
u32 request, u32 denied, bool in_atomic)
{
@@ -480,7 +509,8 @@ static int __file_path_perm(const char *op, struct aa_label *label,
/* check every profile in task label not in current cache */
error = fn_for_each_not_in_set(flabel, label, profile,
- profile_path_perm(op, profile, &file->f_path, buffer,
+ profile_path_perm(op, subj_cred, profile,
+ &file->f_path, buffer,
request, &cond, flags, &perms));
if (denied && !error) {
/*
@@ -493,12 +523,14 @@ static int __file_path_perm(const char *op, struct aa_label *label,
*/
if (label == flabel)
error = fn_for_each(label, profile,
- profile_path_perm(op, profile, &file->f_path,
+ profile_path_perm(op, subj_cred,
+ profile, &file->f_path,
buffer, request, &cond, flags,
&perms));
else
error = fn_for_each_not_in_set(label, flabel, profile,
- profile_path_perm(op, profile, &file->f_path,
+ profile_path_perm(op, subj_cred,
+ profile, &file->f_path,
buffer, request, &cond, flags,
&perms));
}
@@ -510,7 +542,8 @@ static int __file_path_perm(const char *op, struct aa_label *label,
return error;
}
-static int __file_sock_perm(const char *op, struct aa_label *label,
+static int __file_sock_perm(const char *op, const struct cred *subj_cred,
+ struct aa_label *label,
struct aa_label *flabel, struct file *file,
u32 request, u32 denied)
{
@@ -524,11 +557,12 @@ static int __file_sock_perm(const char *op, struct aa_label *label,
return 0;
/* TODO: improve to skip profiles cached in flabel */
- error = aa_sock_file_perm(label, op, request, sock);
+ error = aa_sock_file_perm(subj_cred, label, op, request, sock);
if (denied) {
/* TODO: improve to skip profiles checked above */
/* check every profile in file label to is cached */
- last_error(error, aa_sock_file_perm(flabel, op, request, sock));
+ last_error(error, aa_sock_file_perm(subj_cred, flabel, op,
+ request, sock));
}
if (!error)
update_file_ctx(file_ctx(file), label, request);
@@ -539,6 +573,7 @@ static int __file_sock_perm(const char *op, struct aa_label *label,
/**
* aa_file_perm - do permission revalidation check & audit for @file
* @op: operation being checked
+ * @subj_cred: subject cred
* @label: label being enforced (NOT NULL)
* @file: file to revalidate access permissions on (NOT NULL)
* @request: requested permissions
@@ -546,7 +581,8 @@ static int __file_sock_perm(const char *op, struct aa_label *label,
*
* Returns: %0 if access allowed else error
*/
-int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
+int aa_file_perm(const char *op, const struct cred *subj_cred,
+ struct aa_label *label, struct file *file,
u32 request, bool in_atomic)
{
struct aa_file_ctx *fctx;
@@ -582,19 +618,19 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
/* TODO: label cross check */
if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
- error = __file_path_perm(op, label, flabel, file, request,
- denied, in_atomic);
+ error = __file_path_perm(op, subj_cred, label, flabel, file,
+ request, denied, in_atomic);
else if (S_ISSOCK(file_inode(file)->i_mode))
- error = __file_sock_perm(op, label, flabel, file, request,
- denied);
+ error = __file_sock_perm(op, subj_cred, label, flabel, file,
+ request, denied);
aa_put_label(flabel);
done:
return error;
}
-static void revalidate_tty(struct aa_label *label)
+static void revalidate_tty(const struct cred *subj_cred, struct aa_label *label)
{
struct tty_struct *tty;
int drop_tty = 0;
@@ -612,8 +648,8 @@ static void revalidate_tty(struct aa_label *label)
struct tty_file_private, list);
file = file_priv->file;
- if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE,
- IN_ATOMIC))
+ if (aa_file_perm(OP_INHERIT, subj_cred, label, file,
+ MAY_READ | MAY_WRITE, IN_ATOMIC))
drop_tty = 1;
}
spin_unlock(&tty->files_lock);
@@ -623,12 +659,17 @@ static void revalidate_tty(struct aa_label *label)
no_tty();
}
+struct cred_label {
+ const struct cred *cred;
+ struct aa_label *label;
+};
+
static int match_file(const void *p, struct file *file, unsigned int fd)
{
- struct aa_label *label = (struct aa_label *)p;
+ struct cred_label *cl = (struct cred_label *)p;
- if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file),
- IN_ATOMIC))
+ if (aa_file_perm(OP_INHERIT, cl->cred, cl->label, file,
+ aa_map_file_to_perms(file), IN_ATOMIC))
return fd + 1;
return 0;
}
@@ -638,13 +679,17 @@ static int match_file(const void *p, struct file *file, unsigned int fd)
void aa_inherit_files(const struct cred *cred, struct files_struct *files)
{
struct aa_label *label = aa_get_newest_cred_label(cred);
+ struct cred_label cl = {
+ .cred = cred,
+ .label = label,
+ };
struct file *devnull = NULL;
unsigned int n;
- revalidate_tty(label);
+ revalidate_tty(cred, label);
/* Revalidate access to inherited open files. */
- n = iterate_fd(files, 0, match_file, label);
+ n = iterate_fd(files, 0, match_file, &cl);
if (!n) /* none found? */
goto out;
@@ -654,7 +699,7 @@ void aa_inherit_files(const struct cred *cred, struct files_struct *files)
/* replace all the matching ones with this */
do {
replace_fd(n - 1, devnull, 0);
- } while ((n = iterate_fd(files, n, match_file, label)) != 0);
+ } while ((n = iterate_fd(files, n, match_file, &cl)) != 0);
if (devnull)
fput(devnull);
out:
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 8a81557c9d59b..f83934913b0fd 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -30,9 +30,10 @@
#define AA_CLASS_NET 14
#define AA_CLASS_LABEL 16
#define AA_CLASS_POSIX_MQUEUE 17
-#define AA_CLASS_IO_URING 18
#define AA_CLASS_MODULE 19
#define AA_CLASS_DISPLAY_LSM 20
+#define AA_CLASS_NS 21
+#define AA_CLASS_IO_URING 22
#define AA_CLASS_X 31
#define AA_CLASS_DBUS 32
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index c328f07f11cd8..acbb03b9bd25c 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -103,13 +103,18 @@ enum audit_type {
#define OP_PROF_LOAD "profile_load"
#define OP_PROF_RM "profile_remove"
+#define OP_USERNS_CREATE "userns_create"
+
+#define OP_URING_OVERRIDE "uring_override"
+#define OP_URING_SQPOLL "uring_sqpoll"
struct apparmor_audit_data {
int error;
int type;
u16 class;
const char *op;
- struct aa_label *label;
+ const struct cred *subj_cred;
+ struct aa_label *subj_label;
const char *name;
const char *info;
u32 request;
@@ -151,34 +156,39 @@ struct apparmor_audit_data {
const char *data;
unsigned long flags;
} mnt;
+ struct {
+ struct aa_label *target;
+ } uring;
};
+
+ struct common_audit_data common;
};
/* macros for dealing with apparmor_audit_data structure */
-#define aad(SA) ((SA)->apparmor_audit_data)
+#define aad(SA) (container_of(SA, struct apparmor_audit_data, common))
+#define aad_of_va(VA) aad((struct common_audit_data *)(VA))
+
#define DEFINE_AUDIT_DATA(NAME, T, C, X) \
/* TODO: cleanup audit init so we don't need _aad = {0,} */ \
- struct apparmor_audit_data NAME ## _aad = { \
+ struct apparmor_audit_data NAME = { \
.class = (C), \
.op = (X), \
- }; \
- struct common_audit_data NAME = \
- { \
- .type = (T), \
- .u.tsk = NULL, \
- }; \
- NAME.apparmor_audit_data = &(NAME ## _aad)
-
-void aa_audit_msg(int type, struct common_audit_data *sa,
+ .common.type = (T), \
+ .common.u.tsk = NULL, \
+ .common.apparmor_audit_data = &NAME, \
+ };
+
+void aa_audit_msg(int type, struct apparmor_audit_data *ad,
void (*cb) (struct audit_buffer *, void *));
-int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
+int aa_audit(int type, struct aa_profile *profile,
+ struct apparmor_audit_data *ad,
void (*cb) (struct audit_buffer *, void *));
-#define aa_audit_error(ERROR, SA, CB) \
+#define aa_audit_error(ERROR, AD, CB) \
({ \
- aad((SA))->error = (ERROR); \
- aa_audit_msg(AUDIT_APPARMOR_ERROR, (SA), (CB)); \
- aad((SA))->error; \
+ (AD)->error = (ERROR); \
+ aa_audit_msg(AUDIT_APPARMOR_ERROR, (AD), (CB)); \
+ (AD)->error; \
})
diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h
index d420e2d10b31b..d6dcc604ec0cc 100644
--- a/security/apparmor/include/capability.h
+++ b/security/apparmor/include/capability.h
@@ -36,7 +36,8 @@ struct aa_caps {
extern struct aa_sfs_entry aa_sfs_entry_caps[];
-int aa_capable(struct aa_label *label, int cap, unsigned int opts);
+int aa_capable(const struct cred *subj_cred, struct aa_label *label,
+ int cap, unsigned int opts);
static inline void aa_free_cap_rules(struct aa_caps *caps)
{
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
index 5be620af33ba0..6e8f2aa66cd63 100644
--- a/security/apparmor/include/file.h
+++ b/security/apparmor/include/file.h
@@ -45,43 +45,6 @@ struct aa_file_ctx {
u32 allow;
};
-/**
- * aa_alloc_file_ctx - allocate file_ctx
- * @label: initial label of task creating the file
- * @gfp: gfp flags for allocation
- *
- * Returns: file_ctx or NULL on failure
- */
-static inline struct aa_file_ctx *aa_alloc_file_ctx(struct aa_label *label,
- gfp_t gfp)
-{
- struct aa_file_ctx *ctx;
-
- ctx = kzalloc(sizeof(struct aa_file_ctx), gfp);
- if (ctx) {
- spin_lock_init(&ctx->lock);
- rcu_assign_pointer(ctx->label, aa_get_label(label));
- }
- return ctx;
-}
-
-/**
- * aa_free_file_ctx - free a file_ctx
- * @ctx: file_ctx to free (MAYBE_NULL)
- */
-static inline void aa_free_file_ctx(struct aa_file_ctx *ctx)
-{
- if (ctx) {
- aa_put_label(rcu_access_pointer(ctx->label));
- kfree_sensitive(ctx);
- }
-}
-
-static inline struct aa_label *aa_get_file_label(struct aa_file_ctx *ctx)
-{
- return aa_get_label_rcu(&ctx->label);
-}
-
/*
* The xindex is broken into 3 parts
* - index - an index into either the exec name table or the variable table
@@ -108,7 +71,8 @@ struct path_cond {
#define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill)
-int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms,
+int aa_audit_file(const struct cred *cred,
+ struct aa_profile *profile, struct aa_perms *perms,
const char *op, u32 request, const char *name,
const char *target, struct aa_label *tlabel, kuid_t ouid,
const char *info, int error);
@@ -119,14 +83,16 @@ aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start,
const char *name, struct path_cond *cond,
struct aa_perms *perms);
-int aa_path_perm(const char *op, struct aa_label *label,
- const struct path *path, int flags, u32 request,
- struct path_cond *cond);
+int aa_path_perm(const char *op, const struct cred *subj_cred,
+ struct aa_label *label, const struct path *path,
+ int flags, u32 request, struct path_cond *cond);
-int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
- const struct path *new_dir, struct dentry *new_dentry);
+int aa_path_link(const struct cred *subj_cred, struct aa_label *label,
+ struct dentry *old_dentry, const struct path *new_dir,
+ struct dentry *new_dentry);
-int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
+int aa_file_perm(const char *op, const struct cred *subj_cred,
+ struct aa_label *label, struct file *file,
u32 request, bool in_atomic);
void aa_inherit_files(const struct cred *cred, struct files_struct *files);
diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h
index a1ac6ffb95e9c..74d17052f76bc 100644
--- a/security/apparmor/include/ipc.h
+++ b/security/apparmor/include/ipc.h
@@ -13,6 +13,8 @@
#include <linux/sched.h>
-int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig);
+int aa_may_signal(const struct cred *subj_cred, struct aa_label *sender,
+ const struct cred *target_cred, struct aa_label *target,
+ int sig);
#endif /* __AA_IPC_H */
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
index 73c8a32c68613..d7a894b1031ff 100644
--- a/security/apparmor/include/lib.h
+++ b/security/apparmor/include/lib.h
@@ -16,6 +16,8 @@
#include "match.h"
+extern struct aa_dfa *stacksplitdfa;
+
/*
* DEBUG remains global (no per profile flag) since it is mostly used in sysctl
* which is not related to profile accesses.
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
index 58fbf67139b9c..4bb0405c91908 100644
--- a/security/apparmor/include/match.h
+++ b/security/apparmor/include/match.h
@@ -102,9 +102,6 @@ struct aa_dfa {
struct table_header *tables[YYTD_ID_TSIZE];
};
-extern struct aa_dfa *nulldfa;
-extern struct aa_dfa *stacksplitdfa;
-
#define byte_to_byte(X) (X)
#define UNPACK_ARRAY(TABLE, BLOB, LEN, TTYPE, BTYPE, NTOHX) \
@@ -122,9 +119,6 @@ static inline size_t table_size(size_t len, size_t el_size)
return ALIGN(sizeof(struct table_header) + len * el_size, 8);
}
-int aa_setup_dfa_engine(void);
-void aa_teardown_dfa_engine(void);
-
#define aa_state_t unsigned int
struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
index a710683b24965..46834f8281794 100644
--- a/security/apparmor/include/mount.h
+++ b/security/apparmor/include/mount.h
@@ -25,26 +25,36 @@
#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
-int aa_remount(struct aa_label *label, const struct path *path,
+int aa_remount(const struct cred *subj_cred,
+ struct aa_label *label, const struct path *path,
unsigned long flags, void *data);
-int aa_bind_mount(struct aa_label *label, const struct path *path,
+int aa_bind_mount(const struct cred *subj_cred,
+ struct aa_label *label, const struct path *path,
const char *old_name, unsigned long flags);
-int aa_mount_change_type(struct aa_label *label, const struct path *path,
+int aa_mount_change_type(const struct cred *subj_cred,
+ struct aa_label *label, const struct path *path,
unsigned long flags);
-int aa_move_mount(struct aa_label *label, const struct path *path,
- const char *old_name);
+int aa_move_mount_old(const struct cred *subj_cred,
+ struct aa_label *label, const struct path *path,
+ const char *old_name);
+int aa_move_mount(const struct cred *subj_cred,
+ struct aa_label *label, const struct path *from_path,
+ const struct path *to_path);
-int aa_new_mount(struct aa_label *label, const char *dev_name,
+int aa_new_mount(const struct cred *subj_cred,
+ struct aa_label *label, const char *dev_name,
const struct path *path, const char *type, unsigned long flags,
void *data);
-int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags);
+int aa_umount(const struct cred *subj_cred,
+ struct aa_label *label, struct vfsmount *mnt, int flags);
-int aa_pivotroot(struct aa_label *label, const struct path *old_path,
+int aa_pivotroot(const struct cred *subj_cred,
+ struct aa_label *label, const struct path *old_path,
const struct path *new_path);
#endif /* __AA_MOUNT_H */
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
index 6fa440b5daed8..67bf888c3bd6b 100644
--- a/security/apparmor/include/net.h
+++ b/security/apparmor/include/net.h
@@ -52,7 +52,11 @@ struct aa_sk_ctx {
};
#define SK_CTX(X) ((X)->sk_security)
-#define SOCK_ctx(X) SOCK_INODE(X)->i_security
+static inline struct aa_sk_ctx *aa_sock(const struct sock *sk)
+{
+ return sk->sk_security;
+}
+
#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \
struct lsm_network_audit NAME ## _net = { .sk = (SK), \
.family = (F)}; \
@@ -61,9 +65,9 @@ struct aa_sk_ctx {
LSM_AUDIT_DATA_NONE, \
AA_CLASS_NET, \
OP); \
- NAME.u.net = &(NAME ## _net); \
- aad(&NAME)->net.type = (T); \
- aad(&NAME)->net.protocol = (P)
+ NAME.common.u.net = &(NAME ## _net); \
+ NAME.net.type = (T); \
+ NAME.net.protocol = (P)
#define DEFINE_AUDIT_SK(NAME, OP, SK) \
DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \
@@ -90,21 +94,24 @@ struct aa_secmark {
extern struct aa_sfs_entry aa_sfs_entry_network[];
void audit_net_cb(struct audit_buffer *ab, void *va);
-int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
+int aa_profile_af_perm(struct aa_profile *profile,
+ struct apparmor_audit_data *ad,
u32 request, u16 family, int type);
-int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
+int aa_af_perm(const struct cred *subj_cred, struct aa_label *label,
+ const char *op, u32 request, u16 family,
int type, int protocol);
static inline int aa_profile_af_sk_perm(struct aa_profile *profile,
- struct common_audit_data *sa,
+ struct apparmor_audit_data *ad,
u32 request,
struct sock *sk)
{
- return aa_profile_af_perm(profile, sa, request, sk->sk_family,
+ return aa_profile_af_perm(profile, ad, request, sk->sk_family,
sk->sk_type);
}
int aa_sk_perm(const char *op, u32 request, struct sock *sk);
-int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
+int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label,
+ const char *op, u32 request,
struct socket *sock);
int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h
index 797a7a00644d2..0f7e913c3fc21 100644
--- a/security/apparmor/include/perms.h
+++ b/security/apparmor/include/perms.h
@@ -48,6 +48,9 @@
#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */
+#define AA_MAY_CREATE_SQPOLL AA_MAY_CREATE
+#define AA_MAY_OVERRIDE_CRED AA_MAY_APPEND
+#define AA_URING_PERM_MASK (AA_MAY_OVERRIDE_CRED | AA_MAY_CREATE_SQPOLL)
#define PERMS_CHRS_MASK (MAY_READ | MAY_WRITE | AA_MAY_CREATE | \
AA_MAY_DELETE | AA_MAY_LINK | AA_MAY_LOCK | \
@@ -212,8 +215,8 @@ void aa_profile_match_label(struct aa_profile *profile,
int type, u32 request, struct aa_perms *perms);
int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
u32 request, int type, u32 *deny,
- struct common_audit_data *sa);
+ struct apparmor_audit_data *ad);
int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
- u32 request, struct common_audit_data *sa,
+ u32 request, struct apparmor_audit_data *ad,
void (*cb)(struct audit_buffer *, void *));
#endif /* __AA_PERM_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 545f791cabdae..75088cc310b67 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -34,6 +34,7 @@
struct aa_ns;
extern int unprivileged_userns_apparmor_policy;
+extern int aa_unprivileged_unconfined_restricted;
extern const char *const aa_profile_mode_names[];
#define APPARMOR_MODE_NAMES_MAX_INDEX 4
@@ -74,12 +75,14 @@ enum profile_mode {
/* struct aa_policydb - match engine for a policy
+ * count: refcount for the pdb
* dfa: dfa pattern match
* perms: table of permissions
* strs: table of strings, index by x
* start: set of start states for the different classes of data
*/
struct aa_policydb {
+ struct kref count;
struct aa_dfa *dfa;
struct {
struct aa_perms *perms;
@@ -89,13 +92,36 @@ struct aa_policydb {
aa_state_t start[AA_CLASS_LAST + 1];
};
-static inline void aa_destroy_policydb(struct aa_policydb *policy)
+extern struct aa_policydb *nullpdb;
+
+struct aa_policydb *aa_alloc_pdb(gfp_t gfp);
+void aa_pdb_free_kref(struct kref *kref);
+
+/**
+ * aa_get_pdb - increment refcount on @pdb
+ * @pdb: policydb (MAYBE NULL)
+ *
+ * Returns: pointer to @pdb if @pdb is NULL will return NULL
+ * Requires: @pdb must be held with valid refcount when called
+ */
+static inline struct aa_policydb *aa_get_pdb(struct aa_policydb *pdb)
{
- aa_put_dfa(policy->dfa);
- if (policy->perms)
- kvfree(policy->perms);
- aa_free_str_table(&policy->trans);
+ if (pdb)
+ kref_get(&(pdb->count));
+
+ return pdb;
+}
+/**
+ * aa_put_pdb - put a pdb refcount
+ * @pdb: pdb to put refcount (MAYBE NULL)
+ *
+ * Requires: if @pdb != NULL that a valid refcount be held
+ */
+static inline void aa_put_pdb(struct aa_policydb *pdb)
+{
+ if (pdb)
+ kref_put(&pdb->count, aa_pdb_free_kref);
}
static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy,
@@ -139,8 +165,8 @@ struct aa_ruleset {
int size;
/* TODO: merge policy and file */
- struct aa_policydb policy;
- struct aa_policydb file;
+ struct aa_policydb *policy;
+ struct aa_policydb *file;
struct aa_caps caps;
struct aa_rlimit rlimits;
@@ -159,7 +185,7 @@ struct aa_ruleset {
*/
struct aa_attachment {
const char *xmatch_str;
- struct aa_policydb xmatch;
+ struct aa_policydb *xmatch;
unsigned int xmatch_len;
int xattr_count;
char **xattrs;
@@ -227,10 +253,6 @@ extern enum profile_mode aa_g_profile_mode;
#define profiles_ns(P) ((P)->ns)
#define name_is_shared(A, B) ((A)->hname && (A)->hname == (B)->hname)
-void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
-
-
-void aa_free_proxy_kref(struct kref *kref);
struct aa_ruleset *aa_alloc_ruleset(gfp_t gfp);
struct aa_profile *aa_alloc_profile(const char *name, struct aa_proxy *proxy,
gfp_t gfp);
@@ -239,14 +261,12 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
const char *base, gfp_t gfp);
void aa_free_profile(struct aa_profile *profile);
-void aa_free_profile_kref(struct kref *kref);
struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname,
size_t n);
struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name);
struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
const char *fqname, size_t n);
-struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name);
ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_label *label,
u32 mask, struct aa_loaddata *udata);
@@ -254,9 +274,6 @@ ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_label *label,
char *name, size_t size);
void __aa_profile_list_release(struct list_head *head);
-#define PROF_ADD 1
-#define PROF_REPLACE 0
-
#define profile_unconfined(X) ((X)->mode == APPARMOR_UNCONFINED)
/**
@@ -276,10 +293,10 @@ static inline aa_state_t RULE_MEDIATES(struct aa_ruleset *rules,
unsigned char class)
{
if (class <= AA_CLASS_LAST)
- return rules->policy.start[class];
+ return rules->policy->start[class];
else
- return aa_dfa_match_len(rules->policy.dfa,
- rules->policy.start[0], &class, 1);
+ return aa_dfa_match_len(rules->policy->dfa,
+ rules->policy->start[0], &class, 1);
}
static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF)
@@ -289,7 +306,7 @@ static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF)
if (!state)
return DFA_NOMATCH;
- return aa_dfa_match_len(rules->policy.dfa, state, (char *) &be_af, 2);
+ return aa_dfa_match_len(rules->policy->dfa, state, (char *) &be_af, 2);
}
static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head,
@@ -370,9 +387,12 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
return profile->audit;
}
-bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns);
-bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns);
-int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns,
+bool aa_policy_view_capable(const struct cred *subj_cred,
+ struct aa_label *label, struct aa_ns *ns);
+bool aa_policy_admin_capable(const struct cred *subj_cred,
+ struct aa_label *label, struct aa_ns *ns);
+int aa_may_manage_policy(const struct cred *subj_cred,
+ struct aa_label *label, struct aa_ns *ns,
u32 mask);
bool aa_current_policy_view_capable(struct aa_ns *ns);
bool aa_current_policy_admin_capable(struct aa_ns *ns);
diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h
index 33d665516fc11..d646070fd966b 100644
--- a/security/apparmor/include/policy_ns.h
+++ b/security/apparmor/include/policy_ns.h
@@ -86,10 +86,7 @@ const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child, bool subns);
void aa_free_ns(struct aa_ns *ns);
int aa_alloc_root_ns(void);
void aa_free_root_ns(void);
-void aa_free_ns_kref(struct kref *kref);
-struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name);
-struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n);
struct aa_ns *__aa_lookupn_ns(struct aa_ns *view, const char *hname, size_t n);
struct aa_ns *aa_lookupn_ns(struct aa_ns *view, const char *name, size_t n);
struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,
@@ -151,15 +148,4 @@ static inline struct aa_ns *__aa_find_ns(struct list_head *head,
return __aa_findn_ns(head, name, strlen(name));
}
-static inline struct aa_ns *__aa_lookup_ns(struct aa_ns *base,
- const char *hname)
-{
- return __aa_lookupn_ns(base, hname, strlen(hname));
-}
-
-static inline struct aa_ns *aa_lookup_ns(struct aa_ns *view, const char *name)
-{
- return aa_lookupn_ns(view, name, strlen(name));
-}
-
#endif /* AA_NAMESPACE_H */
diff --git a/security/apparmor/include/resource.h b/security/apparmor/include/resource.h
index 961d85d328ea9..ad2c0da8e64fc 100644
--- a/security/apparmor/include/resource.h
+++ b/security/apparmor/include/resource.h
@@ -33,7 +33,8 @@ struct aa_rlimit {
extern struct aa_sfs_entry aa_sfs_entry_rlimit[];
int aa_map_resource(int resource);
-int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
+int aa_task_setrlimit(const struct cred *subj_cred, struct aa_label *label,
+ struct task_struct *task,
unsigned int resource, struct rlimit *new_rlim);
void __aa_transition_rlimits(struct aa_label *old, struct aa_label *new);
diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h
index 13437d62c70f4..b1aaaf60fa8b8 100644
--- a/security/apparmor/include/task.h
+++ b/security/apparmor/include/task.h
@@ -30,7 +30,7 @@ struct aa_task_ctx {
};
int aa_replace_current_label(struct aa_label *label);
-int aa_set_current_onexec(struct aa_label *label, bool stack);
+void aa_set_current_onexec(struct aa_label *label, bool stack);
int aa_set_current_hat(struct aa_label *label, u64 token);
int aa_restore_previous_label(u64 cookie);
struct aa_label *aa_get_task_label(struct task_struct *task);
@@ -91,8 +91,15 @@ static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx)
"segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
"xcpu xfsz vtalrm prof winch io pwr sys emt lost"
-int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
+int aa_may_ptrace(const struct cred *tracer_cred, struct aa_label *tracer,
+ const struct cred *tracee_cred, struct aa_label *tracee,
u32 request);
+
+#define AA_USERNS_CREATE 8
+
+int aa_profile_ns_perm(struct aa_profile *profile,
+ struct apparmor_audit_data *ad, u32 request);
+
#endif /* __AA_TASK_H */
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
index 5acde746775f7..0cdf4340b02d5 100644
--- a/security/apparmor/ipc.c
+++ b/security/apparmor/ipc.c
@@ -52,31 +52,33 @@ static const char *audit_signal_mask(u32 mask)
static void audit_signal_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
+ struct apparmor_audit_data *ad = aad(sa);
- if (aad(sa)->request & AA_SIGNAL_PERM_MASK) {
+ if (ad->request & AA_SIGNAL_PERM_MASK) {
audit_log_format(ab, " requested_mask=\"%s\"",
- audit_signal_mask(aad(sa)->request));
- if (aad(sa)->denied & AA_SIGNAL_PERM_MASK) {
+ audit_signal_mask(ad->request));
+ if (ad->denied & AA_SIGNAL_PERM_MASK) {
audit_log_format(ab, " denied_mask=\"%s\"",
- audit_signal_mask(aad(sa)->denied));
+ audit_signal_mask(ad->denied));
}
}
- if (aad(sa)->signal == SIGUNKNOWN)
+ if (ad->signal == SIGUNKNOWN)
audit_log_format(ab, "signal=unknown(%d)",
- aad(sa)->unmappedsig);
- else if (aad(sa)->signal < MAXMAPPED_SIGNAME)
- audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]);
+ ad->unmappedsig);
+ else if (ad->signal < MAXMAPPED_SIGNAME)
+ audit_log_format(ab, " signal=%s", sig_names[ad->signal]);
else
audit_log_format(ab, " signal=rtmin+%d",
- aad(sa)->signal - SIGRT_BASE);
+ ad->signal - SIGRT_BASE);
audit_log_format(ab, " peer=");
- aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+ aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
FLAGS_NONE, GFP_ATOMIC);
}
-static int profile_signal_perm(struct aa_profile *profile,
+static int profile_signal_perm(const struct cred *cred,
+ struct aa_profile *profile,
struct aa_label *peer, u32 request,
- struct common_audit_data *sa)
+ struct apparmor_audit_data *ad)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
@@ -87,24 +89,29 @@ static int profile_signal_perm(struct aa_profile *profile,
!ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_SIGNAL))
return 0;
- aad(sa)->peer = peer;
+ ad->subj_cred = cred;
+ ad->peer = peer;
/* TODO: secondary cache check <profile, profile, perm> */
- state = aa_dfa_next(rules->policy.dfa,
- rules->policy.start[AA_CLASS_SIGNAL],
- aad(sa)->signal);
+ state = aa_dfa_next(rules->policy->dfa,
+ rules->policy->start[AA_CLASS_SIGNAL],
+ ad->signal);
aa_label_match(profile, rules, peer, state, false, request, &perms);
aa_apply_modes_to_perms(profile, &perms);
- return aa_check_perms(profile, &perms, request, sa, audit_signal_cb);
+ return aa_check_perms(profile, &perms, request, ad, audit_signal_cb);
}
-int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig)
+int aa_may_signal(const struct cred *subj_cred, struct aa_label *sender,
+ const struct cred *target_cred, struct aa_label *target,
+ int sig)
{
struct aa_profile *profile;
- DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_SIGNAL, OP_SIGNAL);
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_SIGNAL, OP_SIGNAL);
- aad(&sa)->signal = map_signal_num(sig);
- aad(&sa)->unmappedsig = sig;
+ ad.signal = map_signal_num(sig);
+ ad.unmappedsig = sig;
return xcheck_labels(sender, target, profile,
- profile_signal_perm(profile, target, MAY_WRITE, &sa),
- profile_signal_perm(profile, sender, MAY_READ, &sa));
+ profile_signal_perm(subj_cred, profile, target,
+ MAY_WRITE, &ad),
+ profile_signal_perm(target_cred, profile, sender,
+ MAY_READ, &ad));
}
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index 8a2af96f4da57..c71e4615dd460 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -154,13 +154,14 @@ static int profile_cmp(struct aa_profile *a, struct aa_profile *b)
/**
* vec_cmp - label comparison for set ordering
- * @a: label to compare (NOT NULL)
- * @vec: vector of profiles to compare (NOT NULL)
- * @n: length of @vec
- *
- * Returns: <0 if a < vec
- * ==0 if a == vec
- * >0 if a > vec
+ * @a: aa_profile to compare (NOT NULL)
+ * @an: length of @a
+ * @b: aa_profile to compare (NOT NULL)
+ * @bn: length of @b
+ *
+ * Returns: <0 if @a < @b
+ * ==0 if @a == @b
+ * >0 if @a > @b
*/
static int vec_cmp(struct aa_profile **a, int an, struct aa_profile **b, int bn)
{
@@ -256,6 +257,7 @@ static inline int unique(struct aa_profile **vec, int n)
* aa_vec_unique - canonical sort and unique a list of profiles
* @n: number of refcounted profiles in the list (@n > 0)
* @vec: list of profiles to sort and merge
+ * @flags: null terminator flags of @vec
*
* Returns: the number of duplicates eliminated == references put
*
@@ -584,7 +586,7 @@ bool aa_label_is_unconfined_subset(struct aa_label *set, struct aa_label *sub)
/**
* __label_remove - remove @label from the label set
- * @l: label to remove
+ * @label: label to remove
* @new: label to redirect to
*
* Requires: labels_set(@label)->lock write_lock
@@ -917,8 +919,8 @@ struct aa_label *aa_label_find(struct aa_label *label)
/**
* aa_label_insert - insert label @label into @ls or return existing label
- * @ls - labelset to insert @label into
- * @label - label to insert
+ * @ls: labelset to insert @label into
+ * @label: label to insert
*
* Requires: caller to hold a valid ref on @label
*
@@ -1204,7 +1206,6 @@ struct aa_label *aa_label_find_merge(struct aa_label *a, struct aa_label *b)
/**
* aa_label_merge - attempt to insert new merged label of @a and @b
- * @ls: set of labels to insert label into (NOT NULL)
* @a: label to merge with @b (NOT NULL)
* @b: label to merge with @a (NOT NULL)
* @gfp: memory allocation type
@@ -1269,21 +1270,22 @@ static inline aa_state_t match_component(struct aa_profile *profile,
const char *ns_name;
if (profile->ns == tp->ns)
- return aa_dfa_match(rules->policy.dfa, state, tp->base.hname);
+ return aa_dfa_match(rules->policy->dfa, state, tp->base.hname);
/* try matching with namespace name and then profile */
ns_name = aa_ns_name(profile->ns, tp->ns, true);
- state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1);
- state = aa_dfa_match(rules->policy.dfa, state, ns_name);
- state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1);
- return aa_dfa_match(rules->policy.dfa, state, tp->base.hname);
+ state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1);
+ state = aa_dfa_match(rules->policy->dfa, state, ns_name);
+ state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1);
+ return aa_dfa_match(rules->policy->dfa, state, tp->base.hname);
}
/**
* label_compound_match - find perms for full compound label
* @profile: profile to find perms for
+ * @rules: ruleset to search
* @label: label to check access permissions for
- * @start: state to start match in
+ * @state: state to start match in
* @subns: whether to do permission checks on components in a subns
* @request: permissions to request
* @perms: perms struct to set
@@ -1321,12 +1323,12 @@ next:
label_for_each_cont(i, label, tp) {
if (!aa_ns_visible(profile->ns, tp->ns, subns))
continue;
- state = aa_dfa_match(rules->policy.dfa, state, "//&");
+ state = aa_dfa_match(rules->policy->dfa, state, "//&");
state = match_component(profile, rules, tp, state);
if (!state)
goto fail;
}
- *perms = *aa_lookup_perms(&rules->policy, state);
+ *perms = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, perms);
if ((perms->allow & request) != request)
return -EACCES;
@@ -1379,7 +1381,7 @@ static int label_components_match(struct aa_profile *profile,
return 0;
next:
- tmp = *aa_lookup_perms(&rules->policy, state);
+ tmp = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
label_for_each_cont(i, label, tp) {
@@ -1388,7 +1390,7 @@ next:
state = match_component(profile, rules, tp, start);
if (!state)
goto fail;
- tmp = *aa_lookup_perms(&rules->policy, state);
+ tmp = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
}
@@ -2037,7 +2039,7 @@ out:
/**
* __label_update - insert updated version of @label into labelset
- * @label - the label to update/replace
+ * @label: the label to update/replace
*
* Returns: new label that is up to date
* else NULL on failure
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index a630c951bb3b8..4c198d273f091 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -27,7 +27,7 @@ struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
/**
* aa_free_str_table - free entries str table
- * @str: the string table to free (MAYBE NULL)
+ * @t: the string table to free (MAYBE NULL)
*/
void aa_free_str_table(struct aa_str_table *t)
{
@@ -85,6 +85,7 @@ char *aa_split_fqname(char *fqname, char **ns_name)
/**
* skipn_spaces - Removes leading whitespace from @str.
* @str: The string to be stripped.
+ * @n: length of str to parse, will stop at \0 if encountered before n
*
* Returns a pointer to the first non-whitespace character in @str.
* if all whitespace will return NULL
@@ -143,10 +144,10 @@ const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
void aa_info_message(const char *str)
{
if (audit_enabled) {
- DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
- aad(&sa)->info = str;
- aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
+ ad.info = str;
+ aa_audit_msg(AUDIT_APPARMOR_STATUS, &ad, NULL);
}
printk(KERN_INFO "AppArmor: %s\n", str);
}
@@ -281,21 +282,22 @@ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
+ struct apparmor_audit_data *ad = aad(sa);
- if (aad(sa)->request) {
+ if (ad->request) {
audit_log_format(ab, " requested_mask=");
- aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
+ aa_audit_perm_mask(ab, ad->request, aa_file_perm_chrs,
PERMS_CHRS_MASK, aa_file_perm_names,
PERMS_NAMES_MASK);
}
- if (aad(sa)->denied) {
+ if (ad->denied) {
audit_log_format(ab, "denied_mask=");
- aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
+ aa_audit_perm_mask(ab, ad->denied, aa_file_perm_chrs,
PERMS_CHRS_MASK, aa_file_perm_names,
PERMS_NAMES_MASK);
}
audit_log_format(ab, " peer=");
- aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+ aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
FLAGS_NONE, GFP_ATOMIC);
}
@@ -339,8 +341,8 @@ void aa_profile_match_label(struct aa_profile *profile,
/* TODO: doesn't yet handle extended types */
aa_state_t state;
- state = aa_dfa_next(rules->policy.dfa,
- rules->policy.start[AA_CLASS_LABEL],
+ state = aa_dfa_next(rules->policy->dfa,
+ rules->policy->start[AA_CLASS_LABEL],
type);
aa_label_match(profile, rules, label, state, false, request, perms);
}
@@ -349,21 +351,20 @@ void aa_profile_match_label(struct aa_profile *profile,
/* currently unused */
int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
u32 request, int type, u32 *deny,
- struct common_audit_data *sa)
+ struct apparmor_audit_data *ad)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_perms perms;
- aad(sa)->label = &profile->label;
- aad(sa)->peer = &target->label;
- aad(sa)->request = request;
+ ad->peer = &target->label;
+ ad->request = request;
aa_profile_match_label(profile, rules, &target->label, type, request,
&perms);
aa_apply_modes_to_perms(profile, &perms);
*deny |= request & perms.deny;
- return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
+ return aa_check_perms(profile, &perms, request, ad, aa_audit_perms_cb);
}
/**
@@ -371,8 +372,7 @@ int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
* @profile: profile being checked
* @perms: perms computed for the request
* @request: requested perms
- * @deny: Returns: explicit deny set
- * @sa: initialized audit structure (MAY BE NULL if not auditing)
+ * @ad: initialized audit structure (MAY BE NULL if not auditing)
* @cb: callback fn for type specific fields (MAY BE NULL)
*
* Returns: 0 if permission else error code
@@ -385,7 +385,7 @@ int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
* with a positive value.
*/
int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
- u32 request, struct common_audit_data *sa,
+ u32 request, struct apparmor_audit_data *ad,
void (*cb)(struct audit_buffer *, void *))
{
int type, error;
@@ -394,7 +394,7 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
if (likely(!denied)) {
/* mask off perms that are not being force audited */
request &= perms->audit;
- if (!request || !sa)
+ if (!request || !ad)
return 0;
type = AUDIT_APPARMOR_AUDIT;
@@ -413,16 +413,16 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
error = -ENOENT;
denied &= ~perms->quiet;
- if (!sa || !denied)
+ if (!ad || !denied)
return error;
}
- if (sa) {
- aad(sa)->label = &profile->label;
- aad(sa)->request = request;
- aad(sa)->denied = denied;
- aad(sa)->error = error;
- aa_audit_msg(type, sa, cb);
+ if (ad) {
+ ad->subj_label = &profile->label;
+ ad->request = request;
+ ad->denied = denied;
+ ad->error = error;
+ aa_audit_msg(type, ad, cb);
}
if (type == AUDIT_APPARMOR_ALLOWED)
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 3fa325d5efac7..4981bdf029931 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -49,12 +49,19 @@ union aa_buffer {
DECLARE_FLEX_ARRAY(char, buffer);
};
+struct aa_local_cache {
+ unsigned int hold;
+ unsigned int count;
+ struct list_head head;
+};
+
#define RESERVE_COUNT 2
static int reserve_count = RESERVE_COUNT;
static int buffer_count;
static LIST_HEAD(aa_global_buffers);
static DEFINE_SPINLOCK(aa_buffers_lock);
+static DEFINE_PER_CPU(struct aa_local_cache, aa_local_buffers);
/*
* LSM hook functions
@@ -116,15 +123,17 @@ static int apparmor_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
struct aa_label *tracer, *tracee;
+ const struct cred *cred;
int error;
+ cred = get_task_cred(child);
+ tracee = cred_label(cred); /* ref count on cred */
tracer = __begin_current_label_crit_section();
- tracee = aa_get_task_label(child);
- error = aa_may_ptrace(tracer, tracee,
+ error = aa_may_ptrace(current_cred(), tracer, cred, tracee,
(mode & PTRACE_MODE_READ) ? AA_PTRACE_READ
: AA_PTRACE_TRACE);
- aa_put_label(tracee);
__end_current_label_crit_section(tracer);
+ put_cred(cred);
return error;
}
@@ -132,12 +141,15 @@ static int apparmor_ptrace_access_check(struct task_struct *child,
static int apparmor_ptrace_traceme(struct task_struct *parent)
{
struct aa_label *tracer, *tracee;
+ const struct cred *cred;
int error;
tracee = __begin_current_label_crit_section();
- tracer = aa_get_task_label(parent);
- error = aa_may_ptrace(tracer, tracee, AA_PTRACE_TRACE);
- aa_put_label(tracer);
+ cred = get_task_cred(parent);
+ tracer = cred_label(cred); /* ref count on cred */
+ error = aa_may_ptrace(cred, tracer, current_cred(), tracee,
+ AA_PTRACE_TRACE);
+ put_cred(cred);
__end_current_label_crit_section(tracee);
return error;
@@ -188,7 +200,7 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
label = aa_get_newest_cred_label(cred);
if (!unconfined(label))
- error = aa_capable(label, cap, opts);
+ error = aa_capable(cred, label, cap, opts);
aa_put_label(label);
return error;
@@ -211,7 +223,8 @@ static int common_perm(const char *op, const struct path *path, u32 mask,
label = __begin_current_label_crit_section();
if (!unconfined(label))
- error = aa_path_perm(op, label, path, 0, mask, cond);
+ error = aa_path_perm(op, current_cred(), label, path, 0, mask,
+ cond);
__end_current_label_crit_section(label);
return error;
@@ -357,7 +370,8 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_
label = begin_current_label_crit_section();
if (!unconfined(label))
- error = aa_path_link(label, old_dentry, new_dir, new_dentry);
+ error = aa_path_link(current_cred(), label, old_dentry, new_dir,
+ new_dentry);
end_current_label_crit_section(label);
return error;
@@ -396,23 +410,27 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
vfsuid = i_uid_into_vfsuid(idmap, d_backing_inode(old_dentry));
cond_exchange.uid = vfsuid_into_kuid(vfsuid);
- error = aa_path_perm(OP_RENAME_SRC, label, &new_path, 0,
+ error = aa_path_perm(OP_RENAME_SRC, current_cred(),
+ label, &new_path, 0,
MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
AA_MAY_SETATTR | AA_MAY_DELETE,
&cond_exchange);
if (!error)
- error = aa_path_perm(OP_RENAME_DEST, label, &old_path,
+ error = aa_path_perm(OP_RENAME_DEST, current_cred(),
+ label, &old_path,
0, MAY_WRITE | AA_MAY_SETATTR |
AA_MAY_CREATE, &cond_exchange);
}
if (!error)
- error = aa_path_perm(OP_RENAME_SRC, label, &old_path, 0,
+ error = aa_path_perm(OP_RENAME_SRC, current_cred(),
+ label, &old_path, 0,
MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
AA_MAY_SETATTR | AA_MAY_DELETE,
&cond);
if (!error)
- error = aa_path_perm(OP_RENAME_DEST, label, &new_path,
+ error = aa_path_perm(OP_RENAME_DEST, current_cred(),
+ label, &new_path,
0, MAY_WRITE | AA_MAY_SETATTR |
AA_MAY_CREATE, &cond);
@@ -467,7 +485,8 @@ static int apparmor_file_open(struct file *file)
vfsuid = i_uid_into_vfsuid(idmap, inode);
cond.uid = vfsuid_into_kuid(vfsuid);
- error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
+ error = aa_path_perm(OP_OPEN, file->f_cred,
+ label, &file->f_path, 0,
aa_map_file_to_perms(file), &cond);
/* todo cache full allowed permissions set and state */
fctx->allow = aa_map_file_to_perms(file);
@@ -507,7 +526,7 @@ static int common_file_perm(const char *op, struct file *file, u32 mask,
return -EACCES;
label = __begin_current_label_crit_section();
- error = aa_file_perm(op, label, file, mask, in_atomic);
+ error = aa_file_perm(op, current_cred(), label, file, mask, in_atomic);
__end_current_label_crit_section(label);
return error;
@@ -570,6 +589,114 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
false);
}
+#ifdef CONFIG_IO_URING
+static const char *audit_uring_mask(u32 mask)
+{
+ if (mask & AA_MAY_CREATE_SQPOLL)
+ return "sqpoll";
+ if (mask & AA_MAY_OVERRIDE_CRED)
+ return "override_creds";
+ return "";
+}
+
+static void audit_uring_cb(struct audit_buffer *ab, void *va)
+{
+ struct apparmor_audit_data *ad = aad_of_va(va);
+
+ if (ad->request & AA_URING_PERM_MASK) {
+ audit_log_format(ab, " requested=\"%s\"",
+ audit_uring_mask(ad->request));
+ if (ad->denied & AA_URING_PERM_MASK) {
+ audit_log_format(ab, " denied=\"%s\"",
+ audit_uring_mask(ad->denied));
+ }
+ }
+ if (ad->uring.target) {
+ audit_log_format(ab, " tcontext=");
+ aa_label_xaudit(ab, labels_ns(ad->subj_label),
+ ad->uring.target,
+ FLAGS_NONE, GFP_ATOMIC);
+ }
+}
+
+static int profile_uring(struct aa_profile *profile, u32 request,
+ struct aa_label *new, int cap,
+ struct apparmor_audit_data *ad)
+{
+ unsigned int state;
+ struct aa_ruleset *rules;
+ int error = 0;
+
+ AA_BUG(!profile);
+
+ rules = list_first_entry(&profile->rules, typeof(*rules), list);
+ state = RULE_MEDIATES(rules, AA_CLASS_IO_URING);
+ if (state) {
+ struct aa_perms perms = { };
+
+ if (new) {
+ aa_label_match(profile, rules, new, state,
+ false, request, &perms);
+ } else {
+ perms = *aa_lookup_perms(rules->policy, state);
+ }
+ aa_apply_modes_to_perms(profile, &perms);
+ error = aa_check_perms(profile, &perms, request, ad,
+ audit_uring_cb);
+ }
+
+ return error;
+}
+
+/**
+ * apparmor_uring_override_creds - check the requested cred override
+ * @new: the target creds
+ *
+ * Check to see if the current task is allowed to override it's credentials
+ * to service an io_uring operation.
+ */
+static int apparmor_uring_override_creds(const struct cred *new)
+{
+ struct aa_profile *profile;
+ struct aa_label *label;
+ int error;
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_IO_URING,
+ OP_URING_OVERRIDE);
+
+ ad.uring.target = cred_label(new);
+ label = __begin_current_label_crit_section();
+ error = fn_for_each(label, profile,
+ profile_uring(profile, AA_MAY_OVERRIDE_CRED,
+ cred_label(new), CAP_SYS_ADMIN, &ad));
+ __end_current_label_crit_section(label);
+
+ return error;
+}
+
+/**
+ * apparmor_uring_sqpoll - check if a io_uring polling thread can be created
+ *
+ * Check to see if the current task is allowed to create a new io_uring
+ * kernel polling thread.
+ */
+static int apparmor_uring_sqpoll(void)
+{
+ struct aa_profile *profile;
+ struct aa_label *label;
+ int error;
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_IO_URING,
+ OP_URING_SQPOLL);
+
+ label = __begin_current_label_crit_section();
+ error = fn_for_each(label, profile,
+ profile_uring(profile, AA_MAY_CREATE_SQPOLL,
+ NULL, CAP_SYS_ADMIN, &ad));
+ __end_current_label_crit_section(label);
+
+ return error;
+}
+#endif /* CONFIG_IO_URING */
+
static int apparmor_sb_mount(const char *dev_name, const struct path *path,
const char *type, unsigned long flags, void *data)
{
@@ -585,23 +712,42 @@ static int apparmor_sb_mount(const char *dev_name, const struct path *path,
label = __begin_current_label_crit_section();
if (!unconfined(label)) {
if (flags & MS_REMOUNT)
- error = aa_remount(label, path, flags, data);
+ error = aa_remount(current_cred(), label, path, flags,
+ data);
else if (flags & MS_BIND)
- error = aa_bind_mount(label, path, dev_name, flags);
+ error = aa_bind_mount(current_cred(), label, path,
+ dev_name, flags);
else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
MS_UNBINDABLE))
- error = aa_mount_change_type(label, path, flags);
+ error = aa_mount_change_type(current_cred(), label,
+ path, flags);
else if (flags & MS_MOVE)
- error = aa_move_mount(label, path, dev_name);
+ error = aa_move_mount_old(current_cred(), label, path,
+ dev_name);
else
- error = aa_new_mount(label, dev_name, path, type,
- flags, data);
+ error = aa_new_mount(current_cred(), label, dev_name,
+ path, type, flags, data);
}
__end_current_label_crit_section(label);
return error;
}
+static int apparmor_move_mount(const struct path *from_path,
+ const struct path *to_path)
+{
+ struct aa_label *label;
+ int error = 0;
+
+ label = __begin_current_label_crit_section();
+ if (!unconfined(label))
+ error = aa_move_mount(current_cred(), label, from_path,
+ to_path);
+ __end_current_label_crit_section(label);
+
+ return error;
+}
+
static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
{
struct aa_label *label;
@@ -609,7 +755,7 @@ static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
label = __begin_current_label_crit_section();
if (!unconfined(label))
- error = aa_umount(label, mnt, flags);
+ error = aa_umount(current_cred(), label, mnt, flags);
__end_current_label_crit_section(label);
return error;
@@ -623,7 +769,7 @@ static int apparmor_sb_pivotroot(const struct path *old_path,
label = aa_get_current_label();
if (!unconfined(label))
- error = aa_pivotroot(label, old_path, new_path);
+ error = aa_pivotroot(current_cred(), label, old_path, new_path);
aa_put_label(label);
return error;
@@ -662,7 +808,7 @@ static int apparmor_setprocattr(const char *name, void *value,
char *command, *largs = NULL, *args = value;
size_t arg_size;
int error;
- DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE,
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE,
OP_SETPROCATTR);
if (size == 0)
@@ -722,11 +868,11 @@ out:
return error;
fail:
- aad(&sa)->label = begin_current_label_crit_section();
- aad(&sa)->info = name;
- aad(&sa)->error = error = -EINVAL;
- aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL);
- end_current_label_crit_section(aad(&sa)->label);
+ ad.subj_label = begin_current_label_crit_section();
+ ad.info = name;
+ ad.error = error = -EINVAL;
+ aa_audit_msg(AUDIT_APPARMOR_DENIED, &ad, NULL);
+ end_current_label_crit_section(ad.subj_label);
goto out;
}
@@ -766,9 +912,9 @@ static void apparmor_bprm_committed_creds(const struct linux_binprm *bprm)
static void apparmor_current_getsecid_subj(u32 *secid)
{
- struct aa_label *label = aa_get_current_label();
+ struct aa_label *label = __begin_current_label_crit_section();
*secid = label->secid;
- aa_put_label(label);
+ __end_current_label_crit_section(label);
}
static void apparmor_task_getsecid_obj(struct task_struct *p, u32 *secid)
@@ -785,7 +931,8 @@ static int apparmor_task_setrlimit(struct task_struct *task,
int error = 0;
if (!unconfined(label))
- error = aa_task_setrlimit(label, task, resource, new_rlim);
+ error = aa_task_setrlimit(current_cred(), label, task,
+ resource, new_rlim);
__end_current_label_crit_section(label);
return error;
@@ -794,26 +941,48 @@ static int apparmor_task_setrlimit(struct task_struct *task,
static int apparmor_task_kill(struct task_struct *target, struct kernel_siginfo *info,
int sig, const struct cred *cred)
{
+ const struct cred *tc;
struct aa_label *cl, *tl;
int error;
+ tc = get_task_cred(target);
+ tl = aa_get_newest_cred_label(tc);
if (cred) {
/*
* Dealing with USB IO specific behavior
*/
cl = aa_get_newest_cred_label(cred);
- tl = aa_get_task_label(target);
- error = aa_may_signal(cl, tl, sig);
+ error = aa_may_signal(cred, cl, tc, tl, sig);
aa_put_label(cl);
- aa_put_label(tl);
return error;
+ } else {
+ cl = __begin_current_label_crit_section();
+ error = aa_may_signal(current_cred(), cl, tc, tl, sig);
+ __end_current_label_crit_section(cl);
}
-
- cl = __begin_current_label_crit_section();
- tl = aa_get_task_label(target);
- error = aa_may_signal(cl, tl, sig);
aa_put_label(tl);
- __end_current_label_crit_section(cl);
+ put_cred(tc);
+
+ return error;
+}
+
+static int apparmor_userns_create(const struct cred *cred)
+{
+ struct aa_label *label;
+ struct aa_profile *profile;
+ int error = 0;
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_TASK, AA_CLASS_NS,
+ OP_USERNS_CREATE);
+
+ ad.subj_cred = current_cred();
+
+ label = begin_current_label_crit_section();
+ if (!unconfined(label)) {
+ error = fn_for_each(label, profile,
+ aa_profile_ns_perm(profile, &ad,
+ AA_USERNS_CREATE));
+ }
+ end_current_label_crit_section(label);
return error;
}
@@ -829,7 +998,7 @@ static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags)
if (!ctx)
return -ENOMEM;
- SK_CTX(sk) = ctx;
+ sk->sk_security = ctx;
return 0;
}
@@ -839,9 +1008,9 @@ static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags)
*/
static void apparmor_sk_free_security(struct sock *sk)
{
- struct aa_sk_ctx *ctx = SK_CTX(sk);
+ struct aa_sk_ctx *ctx = aa_sock(sk);
- SK_CTX(sk) = NULL;
+ sk->sk_security = NULL;
aa_put_label(ctx->label);
aa_put_label(ctx->peer);
kfree(ctx);
@@ -853,8 +1022,8 @@ static void apparmor_sk_free_security(struct sock *sk)
static void apparmor_sk_clone_security(const struct sock *sk,
struct sock *newsk)
{
- struct aa_sk_ctx *ctx = SK_CTX(sk);
- struct aa_sk_ctx *new = SK_CTX(newsk);
+ struct aa_sk_ctx *ctx = aa_sock(sk);
+ struct aa_sk_ctx *new = aa_sock(newsk);
if (new->label)
aa_put_label(new->label);
@@ -879,7 +1048,8 @@ static int apparmor_socket_create(int family, int type, int protocol, int kern)
if (!(kern || unconfined(label)))
error = af_select(family,
create_perm(label, family, type, protocol),
- aa_af_perm(label, OP_CREATE, AA_MAY_CREATE,
+ aa_af_perm(current_cred(), label,
+ OP_CREATE, AA_MAY_CREATE,
family, type, protocol));
end_current_label_crit_section(label);
@@ -907,7 +1077,7 @@ static int apparmor_socket_post_create(struct socket *sock, int family,
label = aa_get_current_label();
if (sock->sk) {
- struct aa_sk_ctx *ctx = SK_CTX(sock->sk);
+ struct aa_sk_ctx *ctx = aa_sock(sock->sk);
aa_put_label(ctx->label);
ctx->label = aa_get_label(label);
@@ -1092,7 +1262,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
*/
static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
- struct aa_sk_ctx *ctx = SK_CTX(sk);
+ struct aa_sk_ctx *ctx = aa_sock(sk);
if (!skb->secmark)
return 0;
@@ -1105,7 +1275,7 @@ static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
static struct aa_label *sk_peer_label(struct sock *sk)
{
- struct aa_sk_ctx *ctx = SK_CTX(sk);
+ struct aa_sk_ctx *ctx = aa_sock(sk);
if (ctx->peer)
return ctx->peer;
@@ -1186,7 +1356,7 @@ static int apparmor_socket_getpeersec_dgram(struct socket *sock,
*/
static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
{
- struct aa_sk_ctx *ctx = SK_CTX(sk);
+ struct aa_sk_ctx *ctx = aa_sock(sk);
if (!ctx->label)
ctx->label = aa_get_current_label();
@@ -1196,7 +1366,7 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
static int apparmor_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req)
{
- struct aa_sk_ctx *ctx = SK_CTX(sk);
+ struct aa_sk_ctx *ctx = aa_sock(sk);
if (!skb->secmark)
return 0;
@@ -1221,6 +1391,7 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(capget, apparmor_capget),
LSM_HOOK_INIT(capable, apparmor_capable),
+ LSM_HOOK_INIT(move_mount, apparmor_move_mount),
LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
@@ -1294,6 +1465,7 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid_obj),
LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
LSM_HOOK_INIT(task_kill, apparmor_task_kill),
+ LSM_HOOK_INIT(userns_create, apparmor_userns_create),
#ifdef CONFIG_AUDIT
LSM_HOOK_INIT(audit_rule_init, aa_audit_rule_init),
@@ -1305,6 +1477,11 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx),
LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid),
LSM_HOOK_INIT(release_secctx, apparmor_release_secctx),
+
+#ifdef CONFIG_IO_URING
+ LSM_HOOK_INIT(uring_override_creds, apparmor_uring_override_creds),
+ LSM_HOOK_INIT(uring_sqpoll, apparmor_uring_sqpoll),
+#endif
};
/*
@@ -1635,11 +1812,32 @@ static int param_set_mode(const char *val, const struct kernel_param *kp)
char *aa_get_buffer(bool in_atomic)
{
union aa_buffer *aa_buf;
+ struct aa_local_cache *cache;
bool try_again = true;
gfp_t flags = (GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
+ /* use per cpu cached buffers first */
+ cache = get_cpu_ptr(&aa_local_buffers);
+ if (!list_empty(&cache->head)) {
+ aa_buf = list_first_entry(&cache->head, union aa_buffer, list);
+ list_del(&aa_buf->list);
+ cache->hold--;
+ cache->count--;
+ put_cpu_ptr(&aa_local_buffers);
+ return &aa_buf->buffer[0];
+ }
+ put_cpu_ptr(&aa_local_buffers);
+
+ if (!spin_trylock(&aa_buffers_lock)) {
+ cache = get_cpu_ptr(&aa_local_buffers);
+ cache->hold += 1;
+ put_cpu_ptr(&aa_local_buffers);
+ spin_lock(&aa_buffers_lock);
+ } else {
+ cache = get_cpu_ptr(&aa_local_buffers);
+ put_cpu_ptr(&aa_local_buffers);
+ }
retry:
- spin_lock(&aa_buffers_lock);
if (buffer_count > reserve_count ||
(in_atomic && !list_empty(&aa_global_buffers))) {
aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer,
@@ -1665,6 +1863,7 @@ retry:
if (!aa_buf) {
if (try_again) {
try_again = false;
+ spin_lock(&aa_buffers_lock);
goto retry;
}
pr_warn_once("AppArmor: Failed to allocate a memory buffer.\n");
@@ -1676,15 +1875,34 @@ retry:
void aa_put_buffer(char *buf)
{
union aa_buffer *aa_buf;
+ struct aa_local_cache *cache;
if (!buf)
return;
aa_buf = container_of(buf, union aa_buffer, buffer[0]);
- spin_lock(&aa_buffers_lock);
- list_add(&aa_buf->list, &aa_global_buffers);
- buffer_count++;
- spin_unlock(&aa_buffers_lock);
+ cache = get_cpu_ptr(&aa_local_buffers);
+ if (!cache->hold) {
+ put_cpu_ptr(&aa_local_buffers);
+
+ if (spin_trylock(&aa_buffers_lock)) {
+ /* put back on global list */
+ list_add(&aa_buf->list, &aa_global_buffers);
+ buffer_count++;
+ spin_unlock(&aa_buffers_lock);
+ cache = get_cpu_ptr(&aa_local_buffers);
+ put_cpu_ptr(&aa_local_buffers);
+ return;
+ }
+ /* contention on global list, fallback to percpu */
+ cache = get_cpu_ptr(&aa_local_buffers);
+ cache->hold += 1;
+ }
+
+ /* cache in percpu list */
+ list_add(&aa_buf->list, &cache->head);
+ cache->count++;
+ put_cpu_ptr(&aa_local_buffers);
}
/*
@@ -1727,6 +1945,15 @@ static int __init alloc_buffers(void)
int i, num;
/*
+ * per cpu set of cached allocated buffers used to help reduce
+ * lock contention
+ */
+ for_each_possible_cpu(i) {
+ per_cpu(aa_local_buffers, i).hold = 0;
+ per_cpu(aa_local_buffers, i).count = 0;
+ INIT_LIST_HEAD(&per_cpu(aa_local_buffers, i).head);
+ }
+ /*
* A function may require two buffers at once. Usually the buffers are
* used for a short period of time and are shared. On UP kernel buffers
* two should be enough, with more CPUs it is possible that more
@@ -1765,6 +1992,7 @@ static int apparmor_dointvec(struct ctl_table *table, int write,
}
static struct ctl_table apparmor_sysctl_table[] = {
+#ifdef CONFIG_USER_NS
{
.procname = "unprivileged_userns_apparmor_policy",
.data = &unprivileged_userns_apparmor_policy,
@@ -1772,6 +2000,7 @@ static struct ctl_table apparmor_sysctl_table[] = {
.mode = 0600,
.proc_handler = apparmor_dointvec,
},
+#endif /* CONFIG_USER_NS */
{
.procname = "apparmor_display_secid_mode",
.data = &apparmor_display_secid_mode,
@@ -1779,7 +2008,13 @@ static struct ctl_table apparmor_sysctl_table[] = {
.mode = 0600,
.proc_handler = apparmor_dointvec,
},
-
+ {
+ .procname = "apparmor_restrict_unprivileged_unconfined",
+ .data = &aa_unprivileged_unconfined_restricted,
+ .maxlen = sizeof(int),
+ .mode = 0600,
+ .proc_handler = apparmor_dointvec,
+ },
{ }
};
@@ -1809,7 +2044,7 @@ static unsigned int apparmor_ip_postroute(void *priv,
if (sk == NULL)
return NF_ACCEPT;
- ctx = SK_CTX(sk);
+ ctx = aa_sock(sk);
if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND,
skb->secmark, sk))
return NF_ACCEPT;
@@ -1868,6 +2103,69 @@ static int __init apparmor_nf_ip_init(void)
__initcall(apparmor_nf_ip_init);
#endif
+static char nulldfa_src[] = {
+ #include "nulldfa.in"
+};
+struct aa_dfa *nulldfa;
+
+static char stacksplitdfa_src[] = {
+ #include "stacksplitdfa.in"
+};
+struct aa_dfa *stacksplitdfa;
+struct aa_policydb *nullpdb;
+
+static int __init aa_setup_dfa_engine(void)
+{
+ int error = -ENOMEM;
+
+ nullpdb = aa_alloc_pdb(GFP_KERNEL);
+ if (!nullpdb)
+ return -ENOMEM;
+
+ nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src),
+ TO_ACCEPT1_FLAG(YYTD_DATA32) |
+ TO_ACCEPT2_FLAG(YYTD_DATA32));
+ if (IS_ERR(nulldfa)) {
+ error = PTR_ERR(nulldfa);
+ goto fail;
+ }
+ nullpdb->dfa = aa_get_dfa(nulldfa);
+ nullpdb->perms = kcalloc(2, sizeof(struct aa_perms), GFP_KERNEL);
+ if (!nullpdb->perms)
+ goto fail;
+ nullpdb->size = 2;
+
+ stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src,
+ sizeof(stacksplitdfa_src),
+ TO_ACCEPT1_FLAG(YYTD_DATA32) |
+ TO_ACCEPT2_FLAG(YYTD_DATA32));
+ if (IS_ERR(stacksplitdfa)) {
+ error = PTR_ERR(stacksplitdfa);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ aa_put_pdb(nullpdb);
+ aa_put_dfa(nulldfa);
+ nullpdb = NULL;
+ nulldfa = NULL;
+ stacksplitdfa = NULL;
+
+ return error;
+}
+
+static void __init aa_teardown_dfa_engine(void)
+{
+ aa_put_dfa(stacksplitdfa);
+ aa_put_dfa(nulldfa);
+ aa_put_pdb(nullpdb);
+ nullpdb = NULL;
+ stacksplitdfa = NULL;
+ nulldfa = NULL;
+}
+
static int __init apparmor_init(void)
{
int error;
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
index b97ef5e1db732..517d77d3c34cc 100644
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -21,50 +21,6 @@
#define base_idx(X) ((X) & 0xffffff)
-static char nulldfa_src[] = {
- #include "nulldfa.in"
-};
-struct aa_dfa *nulldfa;
-
-static char stacksplitdfa_src[] = {
- #include "stacksplitdfa.in"
-};
-struct aa_dfa *stacksplitdfa;
-
-int __init aa_setup_dfa_engine(void)
-{
- int error;
-
- nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src),
- TO_ACCEPT1_FLAG(YYTD_DATA32) |
- TO_ACCEPT2_FLAG(YYTD_DATA32));
- if (IS_ERR(nulldfa)) {
- error = PTR_ERR(nulldfa);
- nulldfa = NULL;
- return error;
- }
-
- stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src,
- sizeof(stacksplitdfa_src),
- TO_ACCEPT1_FLAG(YYTD_DATA32) |
- TO_ACCEPT2_FLAG(YYTD_DATA32));
- if (IS_ERR(stacksplitdfa)) {
- aa_put_dfa(nulldfa);
- nulldfa = NULL;
- error = PTR_ERR(stacksplitdfa);
- stacksplitdfa = NULL;
- return error;
- }
-
- return 0;
-}
-
-void __init aa_teardown_dfa_engine(void)
-{
- aa_put_dfa(stacksplitdfa);
- aa_put_dfa(nulldfa);
-}
-
/**
* unpack_table - unpack a dfa table (one of accept, default, base, next check)
* @blob: data to unpack (NOT NULL)
@@ -136,7 +92,7 @@ fail:
/**
* verify_table_headers - verify that the tables headers are as expected
- * @tables - array of dfa tables to check (NOT NULL)
+ * @tables: array of dfa tables to check (NOT NULL)
* @flags: flags controlling what type of accept table are acceptable
*
* Assumes dfa has gone through the first pass verification done by unpacking
@@ -283,7 +239,7 @@ static void dfa_free(struct aa_dfa *dfa)
/**
* aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa)
- * @kr: kref callback for freeing of a dfa (NOT NULL)
+ * @kref: kref callback for freeing of a dfa (NOT NULL)
*/
void aa_dfa_free_kref(struct kref *kref)
{
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
index cdfa430ae2161..fb30204c761ad 100644
--- a/security/apparmor/mount.c
+++ b/security/apparmor/mount.c
@@ -86,32 +86,34 @@ static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
static void audit_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
+ struct apparmor_audit_data *ad = aad(sa);
- if (aad(sa)->mnt.type) {
+ if (ad->mnt.type) {
audit_log_format(ab, " fstype=");
- audit_log_untrustedstring(ab, aad(sa)->mnt.type);
+ audit_log_untrustedstring(ab, ad->mnt.type);
}
- if (aad(sa)->mnt.src_name) {
+ if (ad->mnt.src_name) {
audit_log_format(ab, " srcname=");
- audit_log_untrustedstring(ab, aad(sa)->mnt.src_name);
+ audit_log_untrustedstring(ab, ad->mnt.src_name);
}
- if (aad(sa)->mnt.trans) {
+ if (ad->mnt.trans) {
audit_log_format(ab, " trans=");
- audit_log_untrustedstring(ab, aad(sa)->mnt.trans);
+ audit_log_untrustedstring(ab, ad->mnt.trans);
}
- if (aad(sa)->mnt.flags) {
+ if (ad->mnt.flags) {
audit_log_format(ab, " flags=\"");
- audit_mnt_flags(ab, aad(sa)->mnt.flags);
+ audit_mnt_flags(ab, ad->mnt.flags);
audit_log_format(ab, "\"");
}
- if (aad(sa)->mnt.data) {
+ if (ad->mnt.data) {
audit_log_format(ab, " options=");
- audit_log_untrustedstring(ab, aad(sa)->mnt.data);
+ audit_log_untrustedstring(ab, ad->mnt.data);
}
}
/**
* audit_mount - handle the auditing of mount operations
+ * @subj_cred: cred of the subject
* @profile: the profile being enforced (NOT NULL)
* @op: operation being mediated (NOT NULL)
* @name: name of object being mediated (MAYBE NULL)
@@ -127,14 +129,15 @@ static void audit_cb(struct audit_buffer *ab, void *va)
*
* Returns: %0 or error on failure
*/
-static int audit_mount(struct aa_profile *profile, const char *op,
+static int audit_mount(const struct cred *subj_cred,
+ struct aa_profile *profile, const char *op,
const char *name, const char *src_name,
const char *type, const char *trans,
unsigned long flags, const void *data, u32 request,
struct aa_perms *perms, const char *info, int error)
{
int audit_type = AUDIT_APPARMOR_AUTO;
- DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_MOUNT, op);
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_MOUNT, op);
if (likely(!error)) {
u32 mask = perms->audit;
@@ -165,17 +168,18 @@ static int audit_mount(struct aa_profile *profile, const char *op,
return error;
}
- aad(&sa)->name = name;
- aad(&sa)->mnt.src_name = src_name;
- aad(&sa)->mnt.type = type;
- aad(&sa)->mnt.trans = trans;
- aad(&sa)->mnt.flags = flags;
+ ad.subj_cred = subj_cred;
+ ad.name = name;
+ ad.mnt.src_name = src_name;
+ ad.mnt.type = type;
+ ad.mnt.trans = trans;
+ ad.mnt.flags = flags;
if (data && (perms->audit & AA_AUDIT_DATA))
- aad(&sa)->mnt.data = data;
- aad(&sa)->info = info;
- aad(&sa)->error = error;
+ ad.mnt.data = data;
+ ad.info = info;
+ ad.error = error;
- return aa_audit(audit_type, profile, &sa, audit_cb);
+ return aa_audit(audit_type, profile, &ad, audit_cb);
}
/**
@@ -283,6 +287,7 @@ static int path_flags(struct aa_profile *profile, const struct path *path)
/**
* match_mnt_path_str - handle path matching for mount
+ * @subj_cred: cred of confined subject
* @profile: the confining profile
* @mntpath: for the mntpnt (NOT NULL)
* @buffer: buffer to be used to lookup mntpath
@@ -295,7 +300,8 @@ static int path_flags(struct aa_profile *profile, const struct path *path)
*
* Returns: 0 on success else error
*/
-static int match_mnt_path_str(struct aa_profile *profile,
+static int match_mnt_path_str(const struct cred *subj_cred,
+ struct aa_profile *profile,
const struct path *mntpath, char *buffer,
const char *devname, const char *type,
unsigned long flags, void *data, bool binary,
@@ -326,8 +332,8 @@ static int match_mnt_path_str(struct aa_profile *profile,
}
error = -EACCES;
- pos = do_match_mnt(&rules->policy,
- rules->policy.start[AA_CLASS_MOUNT],
+ pos = do_match_mnt(rules->policy,
+ rules->policy->start[AA_CLASS_MOUNT],
mntpnt, devname, type, flags, data, binary, &perms);
if (pos) {
info = mnt_info_table[pos];
@@ -336,12 +342,14 @@ static int match_mnt_path_str(struct aa_profile *profile,
error = 0;
audit:
- return audit_mount(profile, OP_MOUNT, mntpnt, devname, type, NULL,
+ return audit_mount(subj_cred, profile, OP_MOUNT, mntpnt, devname,
+ type, NULL,
flags, data, AA_MAY_MOUNT, &perms, info, error);
}
/**
* match_mnt - handle path matching for mount
+ * @subj_cred: cred of the subject
* @profile: the confining profile
* @path: for the mntpnt (NOT NULL)
* @buffer: buffer to be used to lookup mntpath
@@ -354,7 +362,8 @@ audit:
*
* Returns: 0 on success else error
*/
-static int match_mnt(struct aa_profile *profile, const struct path *path,
+static int match_mnt(const struct cred *subj_cred,
+ struct aa_profile *profile, const struct path *path,
char *buffer, const struct path *devpath, char *devbuffer,
const char *type, unsigned long flags, void *data,
bool binary)
@@ -378,11 +387,12 @@ static int match_mnt(struct aa_profile *profile, const struct path *path,
devname = ERR_PTR(error);
}
- return match_mnt_path_str(profile, path, buffer, devname, type, flags,
- data, binary, info);
+ return match_mnt_path_str(subj_cred, profile, path, buffer, devname,
+ type, flags, data, binary, info);
}
-int aa_remount(struct aa_label *label, const struct path *path,
+int aa_remount(const struct cred *subj_cred,
+ struct aa_label *label, const struct path *path,
unsigned long flags, void *data)
{
struct aa_profile *profile;
@@ -399,14 +409,16 @@ int aa_remount(struct aa_label *label, const struct path *path,
if (!buffer)
return -ENOMEM;
error = fn_for_each_confined(label, profile,
- match_mnt(profile, path, buffer, NULL, NULL, NULL,
+ match_mnt(subj_cred, profile, path, buffer, NULL,
+ NULL, NULL,
flags, data, binary));
aa_put_buffer(buffer);
return error;
}
-int aa_bind_mount(struct aa_label *label, const struct path *path,
+int aa_bind_mount(const struct cred *subj_cred,
+ struct aa_label *label, const struct path *path,
const char *dev_name, unsigned long flags)
{
struct aa_profile *profile;
@@ -433,8 +445,8 @@ int aa_bind_mount(struct aa_label *label, const struct path *path,
goto out;
error = fn_for_each_confined(label, profile,
- match_mnt(profile, path, buffer, &old_path, old_buffer,
- NULL, flags, NULL, false));
+ match_mnt(subj_cred, profile, path, buffer, &old_path,
+ old_buffer, NULL, flags, NULL, false));
out:
aa_put_buffer(buffer);
aa_put_buffer(old_buffer);
@@ -443,7 +455,8 @@ out:
return error;
}
-int aa_mount_change_type(struct aa_label *label, const struct path *path,
+int aa_mount_change_type(const struct cred *subj_cred,
+ struct aa_label *label, const struct path *path,
unsigned long flags)
{
struct aa_profile *profile;
@@ -461,50 +474,63 @@ int aa_mount_change_type(struct aa_label *label, const struct path *path,
if (!buffer)
return -ENOMEM;
error = fn_for_each_confined(label, profile,
- match_mnt(profile, path, buffer, NULL, NULL, NULL,
+ match_mnt(subj_cred, profile, path, buffer, NULL,
+ NULL, NULL,
flags, NULL, false));
aa_put_buffer(buffer);
return error;
}
-int aa_move_mount(struct aa_label *label, const struct path *path,
- const char *orig_name)
+int aa_move_mount(const struct cred *subj_cred,
+ struct aa_label *label, const struct path *from_path,
+ const struct path *to_path)
{
struct aa_profile *profile;
- char *buffer = NULL, *old_buffer = NULL;
- struct path old_path;
+ char *to_buffer = NULL, *from_buffer = NULL;
int error;
AA_BUG(!label);
- AA_BUG(!path);
+ AA_BUG(!from_path);
+ AA_BUG(!to_path);
+
+ to_buffer = aa_get_buffer(false);
+ from_buffer = aa_get_buffer(false);
+ error = -ENOMEM;
+ if (!to_buffer || !from_buffer)
+ goto out;
+ error = fn_for_each_confined(label, profile,
+ match_mnt(subj_cred, profile, to_path, to_buffer,
+ from_path, from_buffer,
+ NULL, MS_MOVE, NULL, false));
+out:
+ aa_put_buffer(to_buffer);
+ aa_put_buffer(from_buffer);
+
+ return error;
+}
+
+int aa_move_mount_old(const struct cred *subj_cred, struct aa_label *label,
+ const struct path *path, const char *orig_name)
+{
+ struct path old_path;
+ int error;
if (!orig_name || !*orig_name)
return -EINVAL;
-
error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
if (error)
return error;
- buffer = aa_get_buffer(false);
- old_buffer = aa_get_buffer(false);
- error = -ENOMEM;
- if (!buffer || !old_buffer)
- goto out;
- error = fn_for_each_confined(label, profile,
- match_mnt(profile, path, buffer, &old_path, old_buffer,
- NULL, MS_MOVE, NULL, false));
-out:
- aa_put_buffer(buffer);
- aa_put_buffer(old_buffer);
+ error = aa_move_mount(subj_cred, label, &old_path, path);
path_put(&old_path);
return error;
}
-int aa_new_mount(struct aa_label *label, const char *dev_name,
- const struct path *path, const char *type, unsigned long flags,
- void *data)
+int aa_new_mount(const struct cred *subj_cred, struct aa_label *label,
+ const char *dev_name, const struct path *path,
+ const char *type, unsigned long flags, void *data)
{
struct aa_profile *profile;
char *buffer = NULL, *dev_buffer = NULL;
@@ -549,12 +575,14 @@ int aa_new_mount(struct aa_label *label, const char *dev_name,
goto out;
}
error = fn_for_each_confined(label, profile,
- match_mnt(profile, path, buffer, dev_path, dev_buffer,
+ match_mnt(subj_cred, profile, path, buffer,
+ dev_path, dev_buffer,
type, flags, data, binary));
} else {
error = fn_for_each_confined(label, profile,
- match_mnt_path_str(profile, path, buffer, dev_name,
- type, flags, data, binary, NULL));
+ match_mnt_path_str(subj_cred, profile, path,
+ buffer, dev_name,
+ type, flags, data, binary, NULL));
}
out:
@@ -566,7 +594,8 @@ out:
return error;
}
-static int profile_umount(struct aa_profile *profile, const struct path *path,
+static int profile_umount(const struct cred *subj_cred,
+ struct aa_profile *profile, const struct path *path,
char *buffer)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
@@ -587,19 +616,21 @@ static int profile_umount(struct aa_profile *profile, const struct path *path,
if (error)
goto audit;
- state = aa_dfa_match(rules->policy.dfa,
- rules->policy.start[AA_CLASS_MOUNT],
+ state = aa_dfa_match(rules->policy->dfa,
+ rules->policy->start[AA_CLASS_MOUNT],
name);
- perms = *aa_lookup_perms(&rules->policy, state);
+ perms = *aa_lookup_perms(rules->policy, state);
if (AA_MAY_UMOUNT & ~perms.allow)
error = -EACCES;
audit:
- return audit_mount(profile, OP_UMOUNT, name, NULL, NULL, NULL, 0, NULL,
+ return audit_mount(subj_cred, profile, OP_UMOUNT, name, NULL, NULL,
+ NULL, 0, NULL,
AA_MAY_UMOUNT, &perms, info, error);
}
-int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags)
+int aa_umount(const struct cred *subj_cred, struct aa_label *label,
+ struct vfsmount *mnt, int flags)
{
struct aa_profile *profile;
char *buffer = NULL;
@@ -614,7 +645,7 @@ int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags)
return -ENOMEM;
error = fn_for_each_confined(label, profile,
- profile_umount(profile, &path, buffer));
+ profile_umount(subj_cred, profile, &path, buffer));
aa_put_buffer(buffer);
return error;
@@ -624,7 +655,8 @@ int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags)
*
* Returns: label for transition or ERR_PTR. Does not return NULL
*/
-static struct aa_label *build_pivotroot(struct aa_profile *profile,
+static struct aa_label *build_pivotroot(const struct cred *subj_cred,
+ struct aa_profile *profile,
const struct path *new_path,
char *new_buffer,
const struct path *old_path,
@@ -658,18 +690,19 @@ static struct aa_label *build_pivotroot(struct aa_profile *profile,
goto audit;
error = -EACCES;
- state = aa_dfa_match(rules->policy.dfa,
- rules->policy.start[AA_CLASS_MOUNT],
+ state = aa_dfa_match(rules->policy->dfa,
+ rules->policy->start[AA_CLASS_MOUNT],
new_name);
- state = aa_dfa_null_transition(rules->policy.dfa, state);
- state = aa_dfa_match(rules->policy.dfa, state, old_name);
- perms = *aa_lookup_perms(&rules->policy, state);
+ state = aa_dfa_null_transition(rules->policy->dfa, state);
+ state = aa_dfa_match(rules->policy->dfa, state, old_name);
+ perms = *aa_lookup_perms(rules->policy, state);
if (AA_MAY_PIVOTROOT & perms.allow)
error = 0;
audit:
- error = audit_mount(profile, OP_PIVOTROOT, new_name, old_name,
+ error = audit_mount(subj_cred, profile, OP_PIVOTROOT, new_name,
+ old_name,
NULL, trans_name, 0, NULL, AA_MAY_PIVOTROOT,
&perms, info, error);
if (error)
@@ -678,7 +711,8 @@ audit:
return aa_get_newest_label(&profile->label);
}
-int aa_pivotroot(struct aa_label *label, const struct path *old_path,
+int aa_pivotroot(const struct cred *subj_cred, struct aa_label *label,
+ const struct path *old_path,
const struct path *new_path)
{
struct aa_profile *profile;
@@ -696,7 +730,8 @@ int aa_pivotroot(struct aa_label *label, const struct path *old_path,
if (!old_buffer || !new_buffer)
goto out;
target = fn_label_build(label, profile, GFP_KERNEL,
- build_pivotroot(profile, new_path, new_buffer,
+ build_pivotroot(subj_cred, profile, new_path,
+ new_buffer,
old_path, old_buffer));
if (!target) {
info = "label build failed";
@@ -722,7 +757,8 @@ out:
fail:
/* TODO: add back in auditing of new_name and old_name */
error = fn_for_each(label, profile,
- audit_mount(profile, OP_PIVOTROOT, NULL /*new_name */,
+ audit_mount(subj_cred, profile, OP_PIVOTROOT,
+ NULL /*new_name */,
NULL /* old_name */,
NULL, NULL,
0, NULL, AA_MAY_PIVOTROOT, &nullperms, info,
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
index 788be1609a865..87e934b2b5488 100644
--- a/security/apparmor/net.c
+++ b/security/apparmor/net.c
@@ -71,6 +71,7 @@ static const char * const net_mask_names[] = {
void audit_net_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
+ struct apparmor_audit_data *ad = aad(sa);
if (address_family_names[sa->u.net->family])
audit_log_format(ab, " family=\"%s\"",
@@ -78,35 +79,36 @@ void audit_net_cb(struct audit_buffer *ab, void *va)
else
audit_log_format(ab, " family=\"unknown(%d)\"",
sa->u.net->family);
- if (sock_type_names[aad(sa)->net.type])
+ if (sock_type_names[ad->net.type])
audit_log_format(ab, " sock_type=\"%s\"",
- sock_type_names[aad(sa)->net.type]);
+ sock_type_names[ad->net.type]);
else
audit_log_format(ab, " sock_type=\"unknown(%d)\"",
- aad(sa)->net.type);
- audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
+ ad->net.type);
+ audit_log_format(ab, " protocol=%d", ad->net.protocol);
- if (aad(sa)->request & NET_PERMS_MASK) {
+ if (ad->request & NET_PERMS_MASK) {
audit_log_format(ab, " requested_mask=");
- aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0,
+ aa_audit_perm_mask(ab, ad->request, NULL, 0,
net_mask_names, NET_PERMS_MASK);
- if (aad(sa)->denied & NET_PERMS_MASK) {
+ if (ad->denied & NET_PERMS_MASK) {
audit_log_format(ab, " denied_mask=");
- aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0,
+ aa_audit_perm_mask(ab, ad->denied, NULL, 0,
net_mask_names, NET_PERMS_MASK);
}
}
- if (aad(sa)->peer) {
+ if (ad->peer) {
audit_log_format(ab, " peer=");
- aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+ aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
FLAGS_NONE, GFP_ATOMIC);
}
}
/* Generic af perm */
-int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
- u32 request, u16 family, int type)
+int aa_profile_af_perm(struct aa_profile *profile,
+ struct apparmor_audit_data *ad, u32 request, u16 family,
+ int type)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
@@ -125,26 +127,28 @@ int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
buffer[0] = cpu_to_be16(family);
buffer[1] = cpu_to_be16((u16) type);
- state = aa_dfa_match_len(rules->policy.dfa, state, (char *) &buffer,
+ state = aa_dfa_match_len(rules->policy->dfa, state, (char *) &buffer,
4);
- perms = *aa_lookup_perms(&rules->policy, state);
+ perms = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, &perms);
- return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
+ return aa_check_perms(profile, &perms, request, ad, audit_net_cb);
}
-int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
- int type, int protocol)
+int aa_af_perm(const struct cred *subj_cred, struct aa_label *label,
+ const char *op, u32 request, u16 family, int type, int protocol)
{
struct aa_profile *profile;
- DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol);
+ DEFINE_AUDIT_NET(ad, op, NULL, family, type, protocol);
return fn_for_each_confined(label, profile,
- aa_profile_af_perm(profile, &sa, request, family,
+ aa_profile_af_perm(profile, &ad, request, family,
type));
}
-static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
+static int aa_label_sk_perm(const struct cred *subj_cred,
+ struct aa_label *label,
+ const char *op, u32 request,
struct sock *sk)
{
struct aa_sk_ctx *ctx = SK_CTX(sk);
@@ -155,10 +159,11 @@ static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
if (ctx->label != kernel_t && !unconfined(label)) {
struct aa_profile *profile;
- DEFINE_AUDIT_SK(sa, op, sk);
+ DEFINE_AUDIT_SK(ad, op, sk);
+ ad.subj_cred = subj_cred;
error = fn_for_each_confined(label, profile,
- aa_profile_af_sk_perm(profile, &sa, request, sk));
+ aa_profile_af_sk_perm(profile, &ad, request, sk));
}
return error;
@@ -174,21 +179,21 @@ int aa_sk_perm(const char *op, u32 request, struct sock *sk)
/* TODO: switch to begin_current_label ???? */
label = begin_current_label_crit_section();
- error = aa_label_sk_perm(label, op, request, sk);
+ error = aa_label_sk_perm(current_cred(), label, op, request, sk);
end_current_label_crit_section(label);
return error;
}
-int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
- struct socket *sock)
+int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label,
+ const char *op, u32 request, struct socket *sock)
{
AA_BUG(!label);
AA_BUG(!sock);
AA_BUG(!sock->sk);
- return aa_label_sk_perm(label, op, request, sock->sk);
+ return aa_label_sk_perm(subj_cred, label, op, request, sock->sk);
}
#ifdef CONFIG_NETWORK_SECMARK
@@ -214,7 +219,7 @@ static int apparmor_secmark_init(struct aa_secmark *secmark)
}
static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
- struct common_audit_data *sa)
+ struct apparmor_audit_data *ad)
{
int i, ret;
struct aa_perms perms = { };
@@ -245,17 +250,17 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
aa_apply_modes_to_perms(profile, &perms);
- return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
+ return aa_check_perms(profile, &perms, request, ad, audit_net_cb);
}
int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
u32 secid, const struct sock *sk)
{
struct aa_profile *profile;
- DEFINE_AUDIT_SK(sa, op, sk);
+ DEFINE_AUDIT_SK(ad, op, sk);
return fn_for_each_confined(label, profile,
aa_secmark_perm(profile, request, secid,
- &sa));
+ &ad));
}
#endif
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index b38f7b2a5e1d5..ed4c9803c8fad 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -88,6 +88,7 @@
#include "include/resource.h"
int unprivileged_userns_apparmor_policy = 1;
+int aa_unprivileged_unconfined_restricted;
const char *const aa_profile_mode_names[] = {
"enforce",
@@ -98,6 +99,41 @@ const char *const aa_profile_mode_names[] = {
};
+static void aa_free_pdb(struct aa_policydb *policy)
+{
+ if (policy) {
+ aa_put_dfa(policy->dfa);
+ if (policy->perms)
+ kvfree(policy->perms);
+ aa_free_str_table(&policy->trans);
+ }
+}
+
+/**
+ * aa_pdb_free_kref - free aa_policydb by kref (called by aa_put_pdb)
+ * @kref: kref callback for freeing of a dfa (NOT NULL)
+ */
+void aa_pdb_free_kref(struct kref *kref)
+{
+ struct aa_policydb *pdb = container_of(kref, struct aa_policydb, count);
+
+ aa_free_pdb(pdb);
+}
+
+
+struct aa_policydb *aa_alloc_pdb(gfp_t gfp)
+{
+ struct aa_policydb *pdb = kzalloc(sizeof(struct aa_policydb), gfp);
+
+ if (!pdb)
+ return NULL;
+
+ kref_init(&pdb->count);
+
+ return pdb;
+}
+
+
/**
* __add_profile - add a profiles to list and label tree
* @list: list to add it to (NOT NULL)
@@ -200,15 +236,15 @@ static void free_attachment(struct aa_attachment *attach)
for (i = 0; i < attach->xattr_count; i++)
kfree_sensitive(attach->xattrs[i]);
kfree_sensitive(attach->xattrs);
- aa_destroy_policydb(&attach->xmatch);
+ aa_put_pdb(attach->xmatch);
}
static void free_ruleset(struct aa_ruleset *rules)
{
int i;
- aa_destroy_policydb(&rules->file);
- aa_destroy_policydb(&rules->policy);
+ aa_put_pdb(rules->file);
+ aa_put_pdb(rules->policy);
aa_free_cap_rules(&rules->caps);
aa_free_rlimit_rules(&rules->rlimits);
@@ -255,6 +291,7 @@ void aa_free_profile(struct aa_profile *profile)
aa_put_ns(profile->ns);
kfree_sensitive(profile->rename);
+ kfree_sensitive(profile->disconnected);
free_attachment(&profile->attach);
@@ -285,6 +322,7 @@ void aa_free_profile(struct aa_profile *profile)
/**
* aa_alloc_profile - allocate, initialize and return a new profile
* @hname: name of the profile (NOT NULL)
+ * @proxy: proxy to use OR null if to allocate a new one
* @gfp: allocation type
*
* Returns: refcount profile or NULL on failure
@@ -588,16 +626,8 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
/* TODO: ideally we should inherit abi from parent */
profile->label.flags |= FLAG_NULL;
rules = list_first_entry(&profile->rules, typeof(*rules), list);
- rules->file.dfa = aa_get_dfa(nulldfa);
- rules->file.perms = kcalloc(2, sizeof(struct aa_perms), GFP_KERNEL);
- if (!rules->file.perms)
- goto fail;
- rules->file.size = 2;
- rules->policy.dfa = aa_get_dfa(nulldfa);
- rules->policy.perms = kcalloc(2, sizeof(struct aa_perms), GFP_KERNEL);
- if (!rules->policy.perms)
- goto fail;
- rules->policy.size = 2;
+ rules->file = aa_get_pdb(nullpdb);
+ rules->policy = aa_get_pdb(nullpdb);
if (parent) {
profile->path_flags = parent->path_flags;
@@ -608,11 +638,6 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
}
return profile;
-
-fail:
- aa_free_profile(profile);
-
- return NULL;
}
/**
@@ -721,16 +746,17 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace,
static void audit_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
+ struct apparmor_audit_data *ad = aad(sa);
- if (aad(sa)->iface.ns) {
+ if (ad->iface.ns) {
audit_log_format(ab, " ns=");
- audit_log_untrustedstring(ab, aad(sa)->iface.ns);
+ audit_log_untrustedstring(ab, ad->iface.ns);
}
}
/**
* audit_policy - Do auditing of policy changes
- * @label: label to check if it can manage policy
+ * @subj_label: label to check if it can manage policy
* @op: policy operation being performed
* @ns_name: name of namespace being manipulated
* @name: name of profile being manipulated (NOT NULL)
@@ -739,19 +765,19 @@ static void audit_cb(struct audit_buffer *ab, void *va)
*
* Returns: the error to be returned after audit is done
*/
-static int audit_policy(struct aa_label *label, const char *op,
+static int audit_policy(struct aa_label *subj_label, const char *op,
const char *ns_name, const char *name,
const char *info, int error)
{
- DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, op);
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, op);
- aad(&sa)->iface.ns = ns_name;
- aad(&sa)->name = name;
- aad(&sa)->info = info;
- aad(&sa)->error = error;
- aad(&sa)->label = label;
+ ad.iface.ns = ns_name;
+ ad.name = name;
+ ad.info = info;
+ ad.error = error;
+ ad.subj_label = subj_label;
- aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, audit_cb);
+ aa_audit_msg(AUDIT_APPARMOR_STATUS, &ad, audit_cb);
return error;
}
@@ -759,31 +785,35 @@ static int audit_policy(struct aa_label *label, const char *op,
/* don't call out to other LSMs in the stack for apparmor policy admin
* permissions
*/
-static int policy_ns_capable(struct aa_label *label,
+static int policy_ns_capable(const struct cred *subj_cred,
+ struct aa_label *label,
struct user_namespace *userns, int cap)
{
int err;
/* check for MAC_ADMIN cap in cred */
- err = cap_capable(current_cred(), userns, cap, CAP_OPT_NONE);
+ err = cap_capable(subj_cred, userns, cap, CAP_OPT_NONE);
if (!err)
- err = aa_capable(label, cap, CAP_OPT_NONE);
+ err = aa_capable(subj_cred, label, cap, CAP_OPT_NONE);
return err;
}
/**
* aa_policy_view_capable - check if viewing policy in at @ns is allowed
- * label: label that is trying to view policy in ns
- * ns: namespace being viewed by @label (may be NULL if @label's ns)
+ * @subj_cred: cred of subject
+ * @label: label that is trying to view policy in ns
+ * @ns: namespace being viewed by @label (may be NULL if @label's ns)
+ *
* Returns: true if viewing policy is allowed
*
* If @ns is NULL then the namespace being viewed is assumed to be the
* tasks current namespace.
*/
-bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns)
+bool aa_policy_view_capable(const struct cred *subj_cred,
+ struct aa_label *label, struct aa_ns *ns)
{
- struct user_namespace *user_ns = current_user_ns();
+ struct user_namespace *user_ns = subj_cred->user_ns;
struct aa_ns *view_ns = labels_view(label);
bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) ||
in_egroup_p(make_kgid(user_ns, 0));
@@ -800,15 +830,17 @@ bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns)
return response;
}
-bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns)
+bool aa_policy_admin_capable(const struct cred *subj_cred,
+ struct aa_label *label, struct aa_ns *ns)
{
- struct user_namespace *user_ns = current_user_ns();
- bool capable = policy_ns_capable(label, user_ns, CAP_MAC_ADMIN) == 0;
+ struct user_namespace *user_ns = subj_cred->user_ns;
+ bool capable = policy_ns_capable(subj_cred, label, user_ns,
+ CAP_MAC_ADMIN) == 0;
AA_DEBUG("cap_mac_admin? %d\n", capable);
AA_DEBUG("policy locked? %d\n", aa_g_lock_policy);
- return aa_policy_view_capable(label, ns) && capable &&
+ return aa_policy_view_capable(subj_cred, label, ns) && capable &&
!aa_g_lock_policy;
}
@@ -818,7 +850,7 @@ bool aa_current_policy_view_capable(struct aa_ns *ns)
bool res;
label = __begin_current_label_crit_section();
- res = aa_policy_view_capable(label, ns);
+ res = aa_policy_view_capable(current_cred(), label, ns);
__end_current_label_crit_section(label);
return res;
@@ -830,7 +862,7 @@ bool aa_current_policy_admin_capable(struct aa_ns *ns)
bool res;
label = __begin_current_label_crit_section();
- res = aa_policy_admin_capable(label, ns);
+ res = aa_policy_admin_capable(current_cred(), label, ns);
__end_current_label_crit_section(label);
return res;
@@ -838,12 +870,15 @@ bool aa_current_policy_admin_capable(struct aa_ns *ns)
/**
* aa_may_manage_policy - can the current task manage policy
+ * @subj_cred: subjects cred
* @label: label to check if it can manage policy
+ * @ns: namespace being managed by @label (may be NULL if @label's ns)
* @mask: contains the policy manipulation operation being done
*
* Returns: 0 if the task is allowed to manipulate policy else error
*/
-int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask)
+int aa_may_manage_policy(const struct cred *subj_cred, struct aa_label *label,
+ struct aa_ns *ns, u32 mask)
{
const char *op;
@@ -859,7 +894,7 @@ int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask)
return audit_policy(label, op, NULL, NULL, "policy_locked",
-EACCES);
- if (!aa_policy_admin_capable(label, ns))
+ if (!aa_policy_admin_capable(subj_cred, label, ns))
return audit_policy(label, op, NULL, NULL, "not policy admin",
-EACCES);
@@ -950,11 +985,11 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
/**
* __lookup_replace - lookup replacement information for a profile
- * @ns - namespace the lookup occurs in
- * @hname - name of profile to lookup
- * @noreplace - true if not replacing an existing profile
- * @p - Returns: profile to be replaced
- * @info - Returns: info string on why lookup failed
+ * @ns: namespace the lookup occurs in
+ * @hname: name of profile to lookup
+ * @noreplace: true if not replacing an existing profile
+ * @p: Returns - profile to be replaced
+ * @info: Returns - info string on why lookup failed
*
* Returns: profile to replace (no ref) on success else ptr error
*/
diff --git a/security/apparmor/policy_compat.c b/security/apparmor/policy_compat.c
index 0cb02da8a3193..423227670e685 100644
--- a/security/apparmor/policy_compat.c
+++ b/security/apparmor/policy_compat.c
@@ -143,6 +143,7 @@ static struct aa_perms compute_fperms_other(struct aa_dfa *dfa,
* compute_fperms - convert dfa compressed perms to internal perms and store
* them so they can be retrieved later.
* @dfa: a dfa using fperms to remap to internal permissions
+ * @size: Returns the permission table size
*
* Returns: remapped perm table
*/
diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c
index fd5b7afbcb487..1f02cfe1d974d 100644
--- a/security/apparmor/policy_ns.c
+++ b/security/apparmor/policy_ns.c
@@ -160,43 +160,6 @@ void aa_free_ns(struct aa_ns *ns)
}
/**
- * aa_findn_ns - look up a profile namespace on the namespace list
- * @root: namespace to search in (NOT NULL)
- * @name: name of namespace to find (NOT NULL)
- * @n: length of @name
- *
- * Returns: a refcounted namespace on the list, or NULL if no namespace
- * called @name exists.
- *
- * refcount released by caller
- */
-struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n)
-{
- struct aa_ns *ns = NULL;
-
- rcu_read_lock();
- ns = aa_get_ns(__aa_findn_ns(&root->sub_ns, name, n));
- rcu_read_unlock();
-
- return ns;
-}
-
-/**
- * aa_find_ns - look up a profile namespace on the namespace list
- * @root: namespace to search in (NOT NULL)
- * @name: name of namespace to find (NOT NULL)
- *
- * Returns: a refcounted namespace on the list, or NULL if no namespace
- * called @name exists.
- *
- * refcount released by caller
- */
-struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name)
-{
- return aa_findn_ns(root, name, strlen(name));
-}
-
-/**
* __aa_lookupn_ns - lookup the namespace matching @hname
* @view: namespace to search in (NOT NULL)
* @hname: hierarchical ns name (NOT NULL)
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 913ec8d0eb639..47ec097d6741f 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -34,17 +34,18 @@
static void audit_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
+ struct apparmor_audit_data *ad = aad(sa);
- if (aad(sa)->iface.ns) {
+ if (ad->iface.ns) {
audit_log_format(ab, " ns=");
- audit_log_untrustedstring(ab, aad(sa)->iface.ns);
+ audit_log_untrustedstring(ab, ad->iface.ns);
}
- if (aad(sa)->name) {
+ if (ad->name) {
audit_log_format(ab, " name=");
- audit_log_untrustedstring(ab, aad(sa)->name);
+ audit_log_untrustedstring(ab, ad->name);
}
- if (aad(sa)->iface.pos)
- audit_log_format(ab, " offset=%ld", aad(sa)->iface.pos);
+ if (ad->iface.pos)
+ audit_log_format(ab, " offset=%ld", ad->iface.pos);
}
/**
@@ -63,18 +64,18 @@ static int audit_iface(struct aa_profile *new, const char *ns_name,
int error)
{
struct aa_profile *profile = labels_profile(aa_current_raw_label());
- DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
if (e)
- aad(&sa)->iface.pos = e->pos - e->start;
- aad(&sa)->iface.ns = ns_name;
+ ad.iface.pos = e->pos - e->start;
+ ad.iface.ns = ns_name;
if (new)
- aad(&sa)->name = new->base.hname;
+ ad.name = new->base.hname;
else
- aad(&sa)->name = name;
- aad(&sa)->info = info;
- aad(&sa)->error = error;
+ ad.name = name;
+ ad.info = info;
+ ad.error = error;
- return aa_audit(AUDIT_APPARMOR_STATUS, profile, &sa, audit_cb);
+ return aa_audit(AUDIT_APPARMOR_STATUS, profile, &ad, audit_cb);
}
void __aa_loaddata_update(struct aa_loaddata *data, long revision)
@@ -705,24 +706,29 @@ fail_reset:
return -EPROTO;
}
-static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
+static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
bool required_dfa, bool required_trans,
const char **info)
{
+ struct aa_policydb *pdb;
void *pos = e->pos;
int i, flags, error = -EPROTO;
ssize_t size;
- size = unpack_perms_table(e, &policy->perms);
+ pdb = aa_alloc_pdb(GFP_KERNEL);
+ if (!pdb)
+ return -ENOMEM;
+
+ size = unpack_perms_table(e, &pdb->perms);
if (size < 0) {
error = size;
- policy->perms = NULL;
+ pdb->perms = NULL;
*info = "failed to unpack - perms";
goto fail;
}
- policy->size = size;
+ pdb->size = size;
- if (policy->perms) {
+ if (pdb->perms) {
/* perms table present accept is index */
flags = TO_ACCEPT1_FLAG(YYTD_DATA32);
} else {
@@ -731,13 +737,13 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
TO_ACCEPT2_FLAG(YYTD_DATA32);
}
- policy->dfa = unpack_dfa(e, flags);
- if (IS_ERR(policy->dfa)) {
- error = PTR_ERR(policy->dfa);
- policy->dfa = NULL;
+ pdb->dfa = unpack_dfa(e, flags);
+ if (IS_ERR(pdb->dfa)) {
+ error = PTR_ERR(pdb->dfa);
+ pdb->dfa = NULL;
*info = "failed to unpack - dfa";
goto fail;
- } else if (!policy->dfa) {
+ } else if (!pdb->dfa) {
if (required_dfa) {
*info = "missing required dfa";
goto fail;
@@ -751,18 +757,18 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
* sadly start was given different names for file and policydb
* but since it is optional we can try both
*/
- if (!aa_unpack_u32(e, &policy->start[0], "start"))
+ if (!aa_unpack_u32(e, &pdb->start[0], "start"))
/* default start state */
- policy->start[0] = DFA_START;
- if (!aa_unpack_u32(e, &policy->start[AA_CLASS_FILE], "dfa_start")) {
+ pdb->start[0] = DFA_START;
+ if (!aa_unpack_u32(e, &pdb->start[AA_CLASS_FILE], "dfa_start")) {
/* default start state for xmatch and file dfa */
- policy->start[AA_CLASS_FILE] = DFA_START;
+ pdb->start[AA_CLASS_FILE] = DFA_START;
} /* setup class index */
for (i = AA_CLASS_FILE + 1; i <= AA_CLASS_LAST; i++) {
- policy->start[i] = aa_dfa_next(policy->dfa, policy->start[0],
+ pdb->start[i] = aa_dfa_next(pdb->dfa, pdb->start[0],
i);
}
- if (!unpack_trans_table(e, &policy->trans) && required_trans) {
+ if (!unpack_trans_table(e, &pdb->trans) && required_trans) {
*info = "failed to unpack profile transition table";
goto fail;
}
@@ -770,9 +776,11 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
/* TODO: move compat mapping here, requires dfa merging first */
/* TODO: move verify here, it has to be done after compat mappings */
out:
+ *policy = pdb;
return 0;
fail:
+ aa_put_pdb(pdb);
e->pos = pos;
return error;
}
@@ -807,7 +815,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
const char *info = "failed to unpack profile";
size_t ns_len;
struct rhashtable_params params = { 0 };
- char *key = NULL;
+ char *key = NULL, *disconnected = NULL;
struct aa_data *data;
int error = -EPROTO;
kernel_cap_t tmpcap;
@@ -856,15 +864,15 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
}
/* neither xmatch_len not xmatch_perms are optional if xmatch is set */
- if (profile->attach.xmatch.dfa) {
+ if (profile->attach.xmatch->dfa) {
if (!aa_unpack_u32(e, &tmp, NULL)) {
info = "missing xmatch len";
goto fail;
}
profile->attach.xmatch_len = tmp;
- profile->attach.xmatch.start[AA_CLASS_XMATCH] = DFA_START;
- if (!profile->attach.xmatch.perms) {
- error = aa_compat_map_xmatch(&profile->attach.xmatch);
+ profile->attach.xmatch->start[AA_CLASS_XMATCH] = DFA_START;
+ if (!profile->attach.xmatch->perms) {
+ error = aa_compat_map_xmatch(profile->attach.xmatch);
if (error) {
info = "failed to convert xmatch permission table";
goto fail;
@@ -873,7 +881,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
}
/* disconnected attachment string is optional */
- (void) aa_unpack_str(e, &profile->disconnected, "disconnected");
+ (void) aa_unpack_strdup(e, &disconnected, "disconnected");
+ profile->disconnected = disconnected;
/* per profile debug flags (complain, audit) */
if (!aa_unpack_nameX(e, AA_STRUCT, "flags")) {
@@ -980,16 +989,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
if (error)
goto fail;
/* Fixup: drop when we get rid of start array */
- if (aa_dfa_next(rules->policy.dfa, rules->policy.start[0],
+ if (aa_dfa_next(rules->policy->dfa, rules->policy->start[0],
AA_CLASS_FILE))
- rules->policy.start[AA_CLASS_FILE] =
- aa_dfa_next(rules->policy.dfa,
- rules->policy.start[0],
+ rules->policy->start[AA_CLASS_FILE] =
+ aa_dfa_next(rules->policy->dfa,
+ rules->policy->start[0],
AA_CLASS_FILE);
if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
- if (!rules->policy.perms) {
- error = aa_compat_map_policy(&rules->policy,
+ if (!rules->policy->perms) {
+ error = aa_compat_map_policy(rules->policy,
e->version);
if (error) {
info = "failed to remap policydb permission table";
@@ -997,44 +1006,25 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
}
}
} else {
- rules->policy.dfa = aa_get_dfa(nulldfa);
- rules->policy.perms = kcalloc(2, sizeof(struct aa_perms),
- GFP_KERNEL);
- if (!rules->policy.perms)
- goto fail;
- rules->policy.size = 2;
+ rules->policy = aa_get_pdb(nullpdb);
}
/* get file rules */
error = unpack_pdb(e, &rules->file, false, true, &info);
if (error) {
goto fail;
- } else if (rules->file.dfa) {
- if (!rules->file.perms) {
- error = aa_compat_map_file(&rules->file);
+ } else if (rules->file->dfa) {
+ if (!rules->file->perms) {
+ error = aa_compat_map_file(rules->file);
if (error) {
info = "failed to remap file permission table";
goto fail;
}
}
- } else if (rules->policy.dfa &&
- rules->policy.start[AA_CLASS_FILE]) {
- rules->file.dfa = aa_get_dfa(rules->policy.dfa);
- rules->file.start[AA_CLASS_FILE] = rules->policy.start[AA_CLASS_FILE];
- rules->file.perms = kcalloc(rules->policy.size,
- sizeof(struct aa_perms),
- GFP_KERNEL);
- if (!rules->file.perms)
- goto fail;
- memcpy(rules->file.perms, rules->policy.perms,
- rules->policy.size * sizeof(struct aa_perms));
- rules->file.size = rules->policy.size;
+ } else if (rules->policy->dfa &&
+ rules->policy->start[AA_CLASS_FILE]) {
+ rules->file = aa_get_pdb(rules->policy);
} else {
- rules->file.dfa = aa_get_dfa(nulldfa);
- rules->file.perms = kcalloc(2, sizeof(struct aa_perms),
- GFP_KERNEL);
- if (!rules->file.perms)
- goto fail;
- rules->file.size = 2;
+ rules->file = aa_get_pdb(nullpdb);
}
error = -EPROTO;
if (aa_unpack_nameX(e, AA_STRUCT, "data")) {
@@ -1170,7 +1160,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
/**
* verify_dfa_accept_index - verify accept indexes are in range of perms table
* @dfa: the dfa to check accept indexes are in range
- * table_size: the permission table size the indexes should be within
+ * @table_size: the permission table size the indexes should be within
*/
static bool verify_dfa_accept_index(struct aa_dfa *dfa, int table_size)
{
@@ -1241,26 +1231,32 @@ static int verify_profile(struct aa_profile *profile)
if (!rules)
return 0;
- if ((rules->file.dfa && !verify_dfa_accept_index(rules->file.dfa,
- rules->file.size)) ||
- (rules->policy.dfa &&
- !verify_dfa_accept_index(rules->policy.dfa, rules->policy.size))) {
+ if (rules->file->dfa && !verify_dfa_accept_index(rules->file->dfa,
+ rules->file->size)) {
+ audit_iface(profile, NULL, NULL,
+ "Unpack: file Invalid named transition", NULL,
+ -EPROTO);
+ return -EPROTO;
+ }
+ if (rules->policy->dfa &&
+ !verify_dfa_accept_index(rules->policy->dfa, rules->policy->size)) {
audit_iface(profile, NULL, NULL,
- "Unpack: Invalid named transition", NULL, -EPROTO);
+ "Unpack: policy Invalid named transition", NULL,
+ -EPROTO);
return -EPROTO;
}
- if (!verify_perms(&rules->file)) {
+ if (!verify_perms(rules->file)) {
audit_iface(profile, NULL, NULL,
"Unpack: Invalid perm index", NULL, -EPROTO);
return -EPROTO;
}
- if (!verify_perms(&rules->policy)) {
+ if (!verify_perms(rules->policy)) {
audit_iface(profile, NULL, NULL,
"Unpack: Invalid perm index", NULL, -EPROTO);
return -EPROTO;
}
- if (!verify_perms(&profile->attach.xmatch)) {
+ if (!verify_perms(profile->attach.xmatch)) {
audit_iface(profile, NULL, NULL,
"Unpack: Invalid perm index", NULL, -EPROTO);
return -EPROTO;
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
index e859481648962..dcc94c3153d51 100644
--- a/security/apparmor/resource.c
+++ b/security/apparmor/resource.c
@@ -30,18 +30,20 @@ struct aa_sfs_entry aa_sfs_entry_rlimit[] = {
static void audit_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
+ struct apparmor_audit_data *ad = aad(sa);
audit_log_format(ab, " rlimit=%s value=%lu",
- rlim_names[aad(sa)->rlim.rlim], aad(sa)->rlim.max);
- if (aad(sa)->peer) {
+ rlim_names[ad->rlim.rlim], ad->rlim.max);
+ if (ad->peer) {
audit_log_format(ab, " peer=");
- aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+ aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
FLAGS_NONE, GFP_ATOMIC);
}
}
/**
* audit_resource - audit setting resource limit
+ * @subj_cred: cred setting the resource
* @profile: profile being enforced (NOT NULL)
* @resource: rlimit being auditing
* @value: value being set
@@ -49,22 +51,24 @@ static void audit_cb(struct audit_buffer *ab, void *va)
* @info: info being auditing
* @error: error value
*
- * Returns: 0 or sa->error else other error code on failure
+ * Returns: 0 or ad->error else other error code on failure
*/
-static int audit_resource(struct aa_profile *profile, unsigned int resource,
+static int audit_resource(const struct cred *subj_cred,
+ struct aa_profile *profile, unsigned int resource,
unsigned long value, struct aa_label *peer,
const char *info, int error)
{
- DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_RLIMITS,
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_RLIMITS,
OP_SETRLIMIT);
- aad(&sa)->rlim.rlim = resource;
- aad(&sa)->rlim.max = value;
- aad(&sa)->peer = peer;
- aad(&sa)->info = info;
- aad(&sa)->error = error;
+ ad.subj_cred = subj_cred;
+ ad.rlim.rlim = resource;
+ ad.rlim.max = value;
+ ad.peer = peer;
+ ad.info = info;
+ ad.error = error;
- return aa_audit(AUDIT_APPARMOR_AUTO, profile, &sa, audit_cb);
+ return aa_audit(AUDIT_APPARMOR_AUTO, profile, &ad, audit_cb);
}
/**
@@ -81,7 +85,8 @@ int aa_map_resource(int resource)
return rlim_map[resource];
}
-static int profile_setrlimit(struct aa_profile *profile, unsigned int resource,
+static int profile_setrlimit(const struct cred *subj_cred,
+ struct aa_profile *profile, unsigned int resource,
struct rlimit *new_rlim)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
@@ -91,22 +96,24 @@ static int profile_setrlimit(struct aa_profile *profile, unsigned int resource,
if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max >
rules->rlimits.limits[resource].rlim_max)
e = -EACCES;
- return audit_resource(profile, resource, new_rlim->rlim_max, NULL, NULL,
- e);
+ return audit_resource(subj_cred, profile, resource, new_rlim->rlim_max,
+ NULL, NULL, e);
}
/**
* aa_task_setrlimit - test permission to set an rlimit
- * @label - label confining the task (NOT NULL)
- * @task - task the resource is being set on
- * @resource - the resource being set
- * @new_rlim - the new resource limit (NOT NULL)
+ * @subj_cred: cred setting the limit
+ * @label: label confining the task (NOT NULL)
+ * @task: task the resource is being set on
+ * @resource: the resource being set
+ * @new_rlim: the new resource limit (NOT NULL)
*
* Control raising the processes hard limit.
*
* Returns: 0 or error code if setting resource failed
*/
-int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
+int aa_task_setrlimit(const struct cred *subj_cred, struct aa_label *label,
+ struct task_struct *task,
unsigned int resource, struct rlimit *new_rlim)
{
struct aa_profile *profile;
@@ -125,14 +132,15 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
*/
if (label != peer &&
- aa_capable(label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0)
+ aa_capable(subj_cred, label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0)
error = fn_for_each(label, profile,
- audit_resource(profile, resource,
+ audit_resource(subj_cred, profile, resource,
new_rlim->rlim_max, peer,
"cap_sys_resource", -EACCES));
else
error = fn_for_each_confined(label, profile,
- profile_setrlimit(profile, resource, new_rlim));
+ profile_setrlimit(subj_cred, profile, resource,
+ new_rlim));
aa_put_label(peer);
return error;
diff --git a/security/apparmor/task.c b/security/apparmor/task.c
index 84d16a29bfcbc..f29a2e80e6bf6 100644
--- a/security/apparmor/task.c
+++ b/security/apparmor/task.c
@@ -93,9 +93,8 @@ int aa_replace_current_label(struct aa_label *label)
* aa_set_current_onexec - set the tasks change_profile to happen onexec
* @label: system label to set at exec (MAYBE NULL to clear value)
* @stack: whether stacking should be done
- * Returns: 0 or error on failure
*/
-int aa_set_current_onexec(struct aa_label *label, bool stack)
+void aa_set_current_onexec(struct aa_label *label, bool stack)
{
struct aa_task_ctx *ctx = task_ctx(current);
@@ -103,8 +102,6 @@ int aa_set_current_onexec(struct aa_label *label, bool stack)
aa_put_label(ctx->onexec);
ctx->onexec = label;
ctx->token = stack;
-
- return 0;
}
/**
@@ -208,70 +205,75 @@ static const char *audit_ptrace_mask(u32 mask)
static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
+ struct apparmor_audit_data *ad = aad(sa);
- if (aad(sa)->request & AA_PTRACE_PERM_MASK) {
+ if (ad->request & AA_PTRACE_PERM_MASK) {
audit_log_format(ab, " requested_mask=\"%s\"",
- audit_ptrace_mask(aad(sa)->request));
+ audit_ptrace_mask(ad->request));
- if (aad(sa)->denied & AA_PTRACE_PERM_MASK) {
+ if (ad->denied & AA_PTRACE_PERM_MASK) {
audit_log_format(ab, " denied_mask=\"%s\"",
- audit_ptrace_mask(aad(sa)->denied));
+ audit_ptrace_mask(ad->denied));
}
}
audit_log_format(ab, " peer=");
- aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+ aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
FLAGS_NONE, GFP_ATOMIC);
}
/* assumes check for RULE_MEDIATES is already done */
/* TODO: conditionals */
-static int profile_ptrace_perm(struct aa_profile *profile,
- struct aa_label *peer, u32 request,
- struct common_audit_data *sa)
+static int profile_ptrace_perm(const struct cred *cred,
+ struct aa_profile *profile,
+ struct aa_label *peer, u32 request,
+ struct apparmor_audit_data *ad)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_perms perms = { };
- aad(sa)->peer = peer;
+ ad->subj_cred = cred;
+ ad->peer = peer;
aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request,
&perms);
aa_apply_modes_to_perms(profile, &perms);
- return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb);
+ return aa_check_perms(profile, &perms, request, ad, audit_ptrace_cb);
}
-static int profile_tracee_perm(struct aa_profile *tracee,
+static int profile_tracee_perm(const struct cred *cred,
+ struct aa_profile *tracee,
struct aa_label *tracer, u32 request,
- struct common_audit_data *sa)
+ struct apparmor_audit_data *ad)
{
if (profile_unconfined(tracee) || unconfined(tracer) ||
!ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE))
return 0;
- return profile_ptrace_perm(tracee, tracer, request, sa);
+ return profile_ptrace_perm(cred, tracee, tracer, request, ad);
}
-static int profile_tracer_perm(struct aa_profile *tracer,
+static int profile_tracer_perm(const struct cred *cred,
+ struct aa_profile *tracer,
struct aa_label *tracee, u32 request,
- struct common_audit_data *sa)
+ struct apparmor_audit_data *ad)
{
if (profile_unconfined(tracer))
return 0;
if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE))
- return profile_ptrace_perm(tracer, tracee, request, sa);
+ return profile_ptrace_perm(cred, tracer, tracee, request, ad);
/* profile uses the old style capability check for ptrace */
if (&tracer->label == tracee)
return 0;
- aad(sa)->label = &tracer->label;
- aad(sa)->peer = tracee;
- aad(sa)->request = 0;
- aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
- CAP_OPT_NONE);
+ ad->subj_label = &tracer->label;
+ ad->peer = tracee;
+ ad->request = 0;
+ ad->error = aa_capable(cred, &tracer->label, CAP_SYS_PTRACE,
+ CAP_OPT_NONE);
- return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
+ return aa_audit(AUDIT_APPARMOR_AUTO, tracer, ad, audit_ptrace_cb);
}
/**
@@ -282,7 +284,8 @@ static int profile_tracer_perm(struct aa_profile *tracer,
*
* Returns: %0 else error code if permission denied or error
*/
-int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
+int aa_may_ptrace(const struct cred *tracer_cred, struct aa_label *tracer,
+ const struct cred *tracee_cred, struct aa_label *tracee,
u32 request)
{
struct aa_profile *profile;
@@ -290,6 +293,49 @@ int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_PTRACE, OP_PTRACE);
return xcheck_labels(tracer, tracee, profile,
- profile_tracer_perm(profile, tracee, request, &sa),
- profile_tracee_perm(profile, tracer, xrequest, &sa));
+ profile_tracer_perm(tracer_cred, profile, tracee,
+ request, &sa),
+ profile_tracee_perm(tracee_cred, profile, tracer,
+ xrequest, &sa));
+}
+
+/* call back to audit ptrace fields */
+static void audit_ns_cb(struct audit_buffer *ab, void *va)
+{
+ struct apparmor_audit_data *ad = aad_of_va(va);
+
+ if (ad->request & AA_USERNS_CREATE)
+ audit_log_format(ab, " requested=\"userns_create\"");
+
+ if (ad->denied & AA_USERNS_CREATE)
+ audit_log_format(ab, " denied=\"userns_create\"");
+}
+
+int aa_profile_ns_perm(struct aa_profile *profile,
+ struct apparmor_audit_data *ad,
+ u32 request)
+{
+ struct aa_perms perms = { };
+ int error = 0;
+
+ ad->subj_label = &profile->label;
+ ad->request = request;
+
+ if (!profile_unconfined(profile)) {
+ struct aa_ruleset *rules = list_first_entry(&profile->rules,
+ typeof(*rules),
+ list);
+ aa_state_t state;
+
+ state = RULE_MEDIATES(rules, ad->class);
+ if (!state)
+ /* TODO: add flag to complain about unmediated */
+ return 0;
+ perms = *aa_lookup_perms(rules->policy, state);
+ aa_apply_modes_to_perms(profile, &perms);
+ error = aa_check_perms(profile, &perms, request, ad,
+ audit_ns_cb);
+ }
+
+ return error;
}