summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-11-03 09:48:17 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2023-11-03 09:48:17 -1000
commit6bdfe2d88b9ff8b0cce32ce87cd47c0e9d665f48 (patch)
treea8a43da53fa84ce69adfb252ddbdaa38fc15e303
parent136cc1e1f5be75f57f1e0404b94ee1c8792cb07d (diff)
parent6cede10161be00d129a24e8b84c2674785a32cf8 (diff)
downloadlinux-6bdfe2d88b9ff8b0cce32ce87cd47c0e9d665f48.tar.gz
linux-6bdfe2d88b9ff8b0cce32ce87cd47c0e9d665f48.tar.bz2
linux-6bdfe2d88b9ff8b0cce32ce87cd47c0e9d665f48.zip
Merge tag 'apparmor-pr-2023-11-03' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
Pull apparmor updates from John Johansen: "This adds initial support for mediating io_uring and userns creation. Adds a new restriction that tightens the use of change_profile, and a couple of optimizations to reduce performance bottle necks that have been found when retrieving the current task's secid and allocating work buffers. The majority of the patch set continues cleaning up and simplifying the code (fixing comments, removing now dead functions, and macros etc). Finally there are 4 bug fixes, with the regression fix having had a couple months of testing. Features: - optimize retrieving current task secid - add base io_uring mediation - add base userns mediation - improve buffer allocation - allow restricting unprivilege change_profile Cleanups: - Fix kernel doc comments - remove unused declarations - remove unused functions - remove unneeded #ifdef - remove unused macros - mark fns static - cleanup fn with unused return values - cleanup audit data - pass cred through to audit data - refcount the pdb instead of using duplicates - make SK_CTX macro an inline fn - some comment cleanups Bug fixes: - fix regression in mount mediation - fix invalid refenece - use passed in gfp flags - advertise avaiability of extended perms and disconnected.path" * tag 'apparmor-pr-2023-11-03' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: (39 commits) apparmor: Fix some kernel-doc comments apparmor: Fix one kernel-doc comment apparmor: Fix some kernel-doc comments apparmor: mark new functions static apparmor: Fix regression in mount mediation apparmor: cache buffers on percpu list if there is lock contention apparmor: add io_uring mediation apparmor: add user namespace creation mediation apparmor: allow restricting unprivileged change_profile apparmor: advertise disconnected.path is available apparmor: refcount the pdb apparmor: provide separate audit messages for file and policy checks apparmor: pass cred through to audit info. apparmor: rename audit_data->label to audit_data->subj_label apparmor: combine common_audit_data and apparmor_audit_data apparmor: rename SK_CTX() to aa_sock and make it an inline fn apparmor: Optimize retrieving current task secid apparmor: remove unused functions in policy_ns.c/.h apparmor: remove unneeded #ifdef in decompress_zstd() apparmor: fix invalid reference on profile->disconnected ...
-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 53a0070ff5df..38650e52ef57 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 5a7978aa4b19..45beb1c5f747 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 326a51838ef2..9934df16c843 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 f3715cda59c5..89fbeab4b33b 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(&am