Commit 6bdfe2d8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'apparmor-pr-2023-11-03' of...

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
  ...
parents 136cc1e1 6cede101
...@@ -423,7 +423,7 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size, ...@@ -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 /* high level check about policy management - fine grained in
* below after unpack * below after unpack
*/ */
error = aa_may_manage_policy(label, ns, mask); error = aa_may_manage_policy(current_cred(), label, ns, mask);
if (error) if (error)
goto end_section; goto end_section;
...@@ -486,7 +486,8 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, ...@@ -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 /* high level check about policy management - fine grained in
* below after unpack * 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) if (error)
goto out; goto out;
...@@ -618,23 +619,23 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms, ...@@ -618,23 +619,23 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,
if (profile_unconfined(profile)) if (profile_unconfined(profile))
return; return;
if (rules->file.dfa && *match_str == AA_CLASS_FILE) { if (rules->file->dfa && *match_str == AA_CLASS_FILE) {
state = aa_dfa_match_len(rules->file.dfa, state = aa_dfa_match_len(rules->file->dfa,
rules->file.start[AA_CLASS_FILE], rules->file->start[AA_CLASS_FILE],
match_str + 1, match_len - 1); match_str + 1, match_len - 1);
if (state) { if (state) {
struct path_cond cond = { }; 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)) if (!RULE_MEDIATES(rules, *match_str))
return; /* no change to current perms */ return; /* no change to current perms */
state = aa_dfa_match_len(rules->policy.dfa, state = aa_dfa_match_len(rules->policy->dfa,
rules->policy.start[0], rules->policy->start[0],
match_str, match_len); match_str, match_len);
if (state) if (state)
tmp = *aa_lookup_perms(&rules->policy, state); tmp = *aa_lookup_perms(rules->policy, state);
} }
aa_apply_modes_to_perms(profile, &tmp); aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum_raw(perms, &tmp); aa_perms_accum_raw(perms, &tmp);
...@@ -1095,7 +1096,7 @@ static int seq_profile_attach_show(struct seq_file *seq, void *v) ...@@ -1095,7 +1096,7 @@ static int seq_profile_attach_show(struct seq_file *seq, void *v)
struct aa_profile *profile = labels_profile(label); struct aa_profile *profile = labels_profile(label);
if (profile->attach.xmatch_str) if (profile->attach.xmatch_str)
seq_printf(seq, "%s\n", 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"); seq_puts(seq, "<unknown>\n");
else else
seq_printf(seq, "%s\n", profile->base.name); seq_printf(seq, "%s\n", profile->base.name);
...@@ -1314,7 +1315,6 @@ SEQ_RAWDATA_FOPS(compressed_size); ...@@ -1314,7 +1315,6 @@ SEQ_RAWDATA_FOPS(compressed_size);
static int decompress_zstd(char *src, size_t slen, char *dst, size_t dlen) static int decompress_zstd(char *src, size_t slen, char *dst, size_t dlen)
{ {
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
if (slen < dlen) { if (slen < dlen) {
const size_t wksp_len = zstd_dctx_workspace_bound(); const size_t wksp_len = zstd_dctx_workspace_bound();
zstd_dctx *ctx; zstd_dctx *ctx;
...@@ -1341,7 +1341,6 @@ static int decompress_zstd(char *src, size_t slen, char *dst, size_t dlen) ...@@ -1341,7 +1341,6 @@ static int decompress_zstd(char *src, size_t slen, char *dst, size_t dlen)
kvfree(wksp); kvfree(wksp);
return ret; return ret;
} }
#endif
if (dlen < slen) if (dlen < slen)
return -EINVAL; return -EINVAL;
...@@ -1806,7 +1805,8 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, ...@@ -1806,7 +1805,8 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir,
int error; int error;
label = begin_current_label_crit_section(); 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); end_current_label_crit_section(label);
if (error) if (error)
return error; return error;
...@@ -1855,7 +1855,8 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) ...@@ -1855,7 +1855,8 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry)
int error; int error;
label = begin_current_label_crit_section(); 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); end_current_label_crit_section(label);
if (error) if (error)
return error; return error;
...@@ -2339,10 +2340,16 @@ static struct aa_sfs_entry aa_sfs_entry_domain[] = { ...@@ -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("post_nnp_subset", 1),
AA_SFS_FILE_BOOLEAN("computed_longest_left", 1), AA_SFS_FILE_BOOLEAN("computed_longest_left", 1),
AA_SFS_DIR("attach_conditions", aa_sfs_entry_attach), AA_SFS_DIR("attach_conditions", aa_sfs_entry_attach),
AA_SFS_FILE_BOOLEAN("disconnected.path", 1),
AA_SFS_FILE_STRING("version", "1.2"), 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[] = { static struct aa_sfs_entry aa_sfs_entry_versions[] = {
AA_SFS_FILE_BOOLEAN("v5", 1), AA_SFS_FILE_BOOLEAN("v5", 1),
AA_SFS_FILE_BOOLEAN("v6", 1), AA_SFS_FILE_BOOLEAN("v6", 1),
...@@ -2352,11 +2359,15 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = { ...@@ -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[] = { static struct aa_sfs_entry aa_sfs_entry_policy[] = {
AA_SFS_DIR("versions", aa_sfs_entry_versions), AA_SFS_DIR("versions", aa_sfs_entry_versions),
AA_SFS_FILE_BOOLEAN("set_load", 1), AA_SFS_FILE_BOOLEAN("set_load", 1),
/* number of out of band transitions supported */ /* number of out of band transitions supported */
AA_SFS_FILE_U64("outofband", MAX_OOB_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[] = { ...@@ -2368,6 +2379,7 @@ static struct aa_sfs_entry aa_sfs_entry_mount[] = {
static struct aa_sfs_entry aa_sfs_entry_ns[] = { static struct aa_sfs_entry aa_sfs_entry_ns[] = {
AA_SFS_FILE_BOOLEAN("profile", 1), AA_SFS_FILE_BOOLEAN("profile", 1),
AA_SFS_FILE_BOOLEAN("pivot_root", 0), 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[] = { ...@@ -2382,6 +2394,12 @@ static struct aa_sfs_entry aa_sfs_entry_query[] = {
AA_SFS_DIR("label", aa_sfs_entry_query_label), 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[] = { static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("policy", aa_sfs_entry_policy), AA_SFS_DIR("policy", aa_sfs_entry_policy),
AA_SFS_DIR("domain", aa_sfs_entry_domain), AA_SFS_DIR("domain", aa_sfs_entry_domain),
...@@ -2395,6 +2413,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = { ...@@ -2395,6 +2413,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace), AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace),
AA_SFS_DIR("signal", aa_sfs_entry_signal), AA_SFS_DIR("signal", aa_sfs_entry_signal),
AA_SFS_DIR("query", aa_sfs_entry_query), AA_SFS_DIR("query", aa_sfs_entry_query),
AA_SFS_DIR("io_uring", aa_sfs_entry_io_uring),
{ } { }
}; };
......
...@@ -58,8 +58,8 @@ static const char *const aa_class_names[] = { ...@@ -58,8 +58,8 @@ static const char *const aa_class_names[] = {
"io_uring", "io_uring",
"module", "module",
"lsm", "lsm",
"unknown", "namespace",
"unknown", "io_uring",
"unknown", "unknown",
"unknown", "unknown",
"unknown", "unknown",
...@@ -85,37 +85,36 @@ static const char *const aa_class_names[] = { ...@@ -85,37 +85,36 @@ static const char *const aa_class_names[] = {
/** /**
* audit_pre() - core AppArmor function. * audit_pre() - core AppArmor function.
* @ab: audit buffer to fill (NOT NULL) * @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) { if (aa_g_audit_header) {
audit_log_format(ab, "apparmor=\"%s\"", audit_log_format(ab, "apparmor=\"%s\"",
aa_audit_type[aad(sa)->type]); aa_audit_type[ad->type]);
} }
if (aad(sa)->op) { if (ad->op)
audit_log_format(ab, " operation=\"%s\"", aad(sa)->op); audit_log_format(ab, " operation=\"%s\"", ad->op);
}
if (aad(sa)->class) if (ad->class)
audit_log_format(ab, " class=\"%s\"", audit_log_format(ab, " class=\"%s\"",
aad(sa)->class <= AA_CLASS_LAST ? ad->class <= AA_CLASS_LAST ?
aa_class_names[aad(sa)->class] : aa_class_names[ad->class] :
"unknown"); "unknown");
if (aad(sa)->info) { if (ad->info) {
audit_log_format(ab, " info=\"%s\"", aad(sa)->info); audit_log_format(ab, " info=\"%s\"", ad->info);
if (aad(sa)->error) if (ad->error)
audit_log_format(ab, " error=%d", aad(sa)->error); audit_log_format(ab, " error=%d", ad->error);
} }
if (aad(sa)->label) { if (ad->subj_label) {
struct aa_label *label = aad(sa)->label; struct aa_label *label = ad->subj_label;
if (label_isprofile(label)) { if (label_isprofile(label)) {
struct aa_profile *profile = labels_profile(label); struct aa_profile *profile = labels_profile(label);
...@@ -134,42 +133,44 @@ static void audit_pre(struct audit_buffer *ab, void *ca) ...@@ -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_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 * 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) * @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 *)) void (*cb) (struct audit_buffer *, void *))
{ {
aad(sa)->type = type; ad->type = type;
common_lsm_audit(sa, audit_pre, cb); common_lsm_audit(&ad->common, audit_pre, cb);
} }
/** /**
* aa_audit - Log a profile based audit event to the audit subsystem * aa_audit - Log a profile based audit event to the audit subsystem
* @type: audit type for the message * @type: audit type for the message
* @profile: profile to check against (NOT NULL) * @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) * @cb: optional callback fn for type specific fields (MAYBE NULL)
* *
* Handle default message switching based off of audit mode flags * Handle default message switching based off of audit mode flags
* *
* Returns: error on failure * 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 *)) void (*cb) (struct audit_buffer *, void *))
{ {
AA_BUG(!profile); AA_BUG(!profile);
if (type == AUDIT_APPARMOR_AUTO) { if (type == AUDIT_APPARMOR_AUTO) {
if (likely(!aad(sa)->error)) { if (likely(!ad->error)) {
if (AUDIT_MODE(profile) != AUDIT_ALL) if (AUDIT_MODE(profile) != AUDIT_ALL)
return 0; return 0;
type = AUDIT_APPARMOR_AUDIT; type = AUDIT_APPARMOR_AUDIT;
...@@ -181,24 +182,24 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, ...@@ -181,24 +182,24 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
if (AUDIT_MODE(profile) == AUDIT_QUIET || if (AUDIT_MODE(profile) == AUDIT_QUIET ||
(type == AUDIT_APPARMOR_DENIED && (type == AUDIT_APPARMOR_DENIED &&
AUDIT_MODE(profile) == AUDIT_QUIET_DENIED)) AUDIT_MODE(profile) == AUDIT_QUIET_DENIED))
return aad(sa)->error; return ad->error;
if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
type = AUDIT_APPARMOR_KILL; 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, (void)send_sig_info(SIGKILL, NULL,
sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ? ad->common.type == LSM_AUDIT_DATA_TASK &&
sa->u.tsk : current); ad->common.u.tsk ? ad->common.u.tsk : current);
if (aad(sa)->type == AUDIT_APPARMOR_ALLOWED) if (ad->type == AUDIT_APPARMOR_ALLOWED)
return complain_error(aad(sa)->error); return complain_error(ad->error);
return aad(sa)->error; return ad->error;
} }
struct aa_audit_rule { struct aa_audit_rule {
......
...@@ -38,8 +38,8 @@ static DEFINE_PER_CPU(struct audit_cache, audit_cache); ...@@ -38,8 +38,8 @@ static DEFINE_PER_CPU(struct audit_cache, audit_cache);
/** /**
* audit_cb - call back for capability components of audit struct * audit_cb - call back for capability components of audit struct
* @ab - audit buffer (NOT NULL) * @ab: audit buffer (NOT NULL)
* @va - audit struct to audit data from (NOT NULL) * @va: audit struct to audit data from (NOT NULL)
*/ */
static void audit_cb(struct audit_buffer *ab, void *va) static void audit_cb(struct audit_buffer *ab, void *va)
{ {
...@@ -51,7 +51,7 @@ 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 * audit_caps - audit a capability
* @sa: audit data * @ad: audit data
* @profile: profile being tested for confinement (NOT NULL) * @profile: profile being tested for confinement (NOT NULL)
* @cap: capability tested * @cap: capability tested
* @error: error code returned by test * @error: error code returned by test
...@@ -59,9 +59,9 @@ static void audit_cb(struct audit_buffer *ab, void *va) ...@@ -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 * Do auditing of capability and handle, audit/complain/kill modes switching
* and duplicate message elimination. * 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) int cap, int error)
{ {
struct aa_ruleset *rules = list_first_entry(&profile->rules, 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, ...@@ -69,7 +69,7 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
struct audit_cache *ent; struct audit_cache *ent;
int type = AUDIT_APPARMOR_AUTO; int type = AUDIT_APPARMOR_AUTO;
aad(sa)->error = error; ad->error = error;
if (likely(!error)) { if (likely(!error)) {
/* test if auditing is being forced */ /* test if auditing is being forced */
...@@ -101,7 +101,7 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, ...@@ -101,7 +101,7 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
} }
put_cpu_var(audit_cache); 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, ...@@ -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) * @profile: profile being enforced (NOT NULL, NOT unconfined)
* @cap: capability to test if allowed * @cap: capability to test if allowed
* @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated * @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 * Returns: 0 if allowed else -EPERM
*/ */
static int profile_capable(struct aa_profile *profile, int cap, 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, struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list); typeof(*rules), list);
...@@ -132,14 +132,15 @@ static int profile_capable(struct aa_profile *profile, int cap, ...@@ -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 /* audit the cap request in complain mode but note that it
* should be optional. * 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 * aa_capable - test permission to use capability
* @subj_cred: cred we are testing capability against
* @label: label being tested for capability (NOT NULL) * @label: label being tested for capability (NOT NULL)
* @cap: capability to be tested * @cap: capability to be tested
* @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated * @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, ...@@ -148,15 +149,17 @@ static int profile_capable(struct aa_profile *profile, int cap,
* *
* Returns: 0 on success, or else an error code. * 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; struct aa_profile *profile;
int error = 0; 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, error = fn_for_each_confined(label, profile,
profile_capable(profile, cap, opts, &sa)); profile_capable(profile, cap, opts, &ad));
return error; return error;
} }
This diff is collapsed.
This diff is collapsed.
...@@ -30,9 +30,10 @@ ...@@ -30,9 +30,10 @@
#define AA_CLASS_NET 14 #define AA_CLASS_NET 14
#define AA_CLASS_LABEL 16 #define AA_CLASS_LABEL 16
#define AA_CLASS_POSIX_MQUEUE 17 #define AA_CLASS_POSIX_MQUEUE 17
#define AA_CLASS_IO_URING 18
#define AA_CLASS_MODULE 19 #define AA_CLASS_MODULE 19
#define AA_CLASS_DISPLAY_LSM 20 #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_X 31
#define AA_CLASS_DBUS 32 #define AA_CLASS_DBUS 32
......
...@@ -103,13 +103,18 @@ enum audit_type { ...@@ -103,13 +103,18 @@ enum audit_type {
#define OP_PROF_LOAD "profile_load" #define OP_PROF_LOAD "profile_load"
#define OP_PROF_RM "profile_remove" #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 { struct apparmor_audit_data {
int error; int error;
int type; int type;
u16 class; u16 class;
const char *op; const char *op;
struct aa_label *label; const struct cred *subj_cred;
struct aa_label *subj_label;
const char *name; const char *name;
const char *info; const char *info;
u32 request; u32 request;
...@@ -151,34 +156,39 @@ struct apparmor_audit_data { ...@@ -151,34 +156,39 @@ struct apparmor_audit_data {
const char *data; const char *data;
unsigned long flags; unsigned long flags;
} mnt; } mnt;
struct {
struct aa_label *target;
} uring;
}; };
struct common_audit_data common;
}; };
/* macros for dealing with apparmor_audit_data structure */ /* 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) \ #define DEFINE_AUDIT_DATA(NAME, T, C, X) \
/* TODO: cleanup audit init so we don't need _aad = {0,} */ \ /* TODO: cleanup audit init so we don't need _aad = {0,} */ \
struct apparmor_audit_data NAME ## _aad = { \ struct apparmor_audit_data NAME = { \
.class = (C), \ .class = (C), \
.op = (X), \ .op = (X), \
}; \ .common.type = (T), \
struct common_audit_data NAME = \ .common.u.tsk = NULL, \
{ \ .common.apparmor_audit_data = &NAME, \
.type = (T), \ };
.u.tsk = NULL, \
}; \ void aa_audit_msg(int type, struct apparmor_audit_data *ad,
NAME.apparmor_audit_data = &(NAME ## _aad)
void aa_audit_msg(int type, struct common_audit_data *sa,
void (*cb) (struct audit_buffer *, void *)); 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 *)); void (*cb) (struct audit_buffer *, void *));
#define aa_audit_error(ERROR, SA, CB) \ #define aa_audit_error(ERROR, AD, CB) \
({ \ ({ \
aad((SA))->error = (ERROR); \ (AD)->error = (ERROR); \
aa_audit_msg(AUDIT_APPARMOR_ERROR, (SA), (CB)); \ aa_audit_msg(AUDIT_APPARMOR_ERROR, (AD), (CB)); \
aad((SA))->error; \ (AD)->error; \
}) })
......
...@@ -36,7 +36,8 @@ struct aa_caps { ...@@ -36,7 +36,8 @@ struct aa_caps {
extern struct aa_sfs_entry aa_sfs_entry_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) static inline void aa_free_cap_rules(struct aa_caps *caps)
{ {
......
...@@ -45,43 +45,6 @@ struct aa_file_ctx { ...@@ -45,43 +45,6 @@ struct aa_file_ctx {
u32 allow; 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 * The xindex is broken into 3 parts
* - index - an index into either the exec name table or the variable table * - index - an index into either the exec name table or the variable table
...@@ -108,7 +71,8 @@ struct path_cond { ...@@ -108,7 +71,8 @@ struct path_cond {
#define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill) #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 *op, u32 request, const char *name,
const char *target, struct aa_label *tlabel, kuid_t ouid, const char *target, struct aa_label *tlabel, kuid_t ouid,
const char *info, int error); const char *info, int error);
...@@ -119,14 +83,16 @@ aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start, ...@@ -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, const char *name, struct path_cond *cond,
struct aa_perms *perms); struct aa_perms *perms);
int aa_path_perm(const char *op, struct aa_label *label, int aa_path_perm(const char *op, const struct cred *subj_cred,
const struct path *path, int flags, u32 request, struct aa_label *label, const struct path *path,
struct path_cond *cond); int flags, u32 request, struct path_cond *cond);
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,
const struct path *new_dir, struct dentry *new_dentry); 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); u32 request, bool in_atomic);
void aa_inherit_files(const struct cred *cred, struct files_struct *files); void aa_inherit_files(const struct cred *cred, struct files_struct *files);
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <linux/sched.h> #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 */ #endif /* __AA_IPC_H */
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include "match.h" #include "match.h"
extern struct aa_dfa *stacksplitdfa;
/* /*
* DEBUG remains global (no per profile flag) since it is mostly used in sysctl * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
* which is not related to profile accesses. * which is not related to profile accesses.
......
...@@ -102,9 +102,6 @@ struct aa_dfa { ...@@ -102,9 +102,6 @@ struct aa_dfa {
struct table_header *tables[YYTD_ID_TSIZE]; struct table_header *tables[YYTD_ID_TSIZE];
}; };
extern struct aa_dfa *nulldfa;
extern struct aa_dfa *stacksplitdfa;
#define byte_to_byte(X) (X) #define byte_to_byte(X) (X)
#define UNPACK_ARRAY(TABLE, BLOB, LEN, TTYPE, BTYPE, NTOHX) \ #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) ...@@ -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); 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 #define aa_state_t unsigned int
struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags); struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
......
...@@ -25,26 +25,36 @@ ...@@ -25,26 +25,36 @@
#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN) #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); 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); 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); unsigned long flags);
int aa_move_mount(struct aa_label *label, const struct path *path, int aa_move_mount_old(const struct cred *subj_cred,
const char *old_name); 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, const struct path *path, const char *type, unsigned long flags,
void *data); 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); const struct path *new_path);
#endif /* __AA_MOUNT_H */ #endif /* __AA_MOUNT_H */
...@@ -52,7 +52,11 @@ struct aa_sk_ctx { ...@@ -52,7 +52,11 @@ struct aa_sk_ctx {
}; };
#define SK_CTX(X) ((X)->sk_security) #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) \ #define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \
struct lsm_network_audit NAME ## _net = { .sk = (SK), \ struct lsm_network_audit NAME ## _net = { .sk = (SK), \
.family = (F)}; \ .family = (F)}; \
...@@ -61,9 +65,9 @@ struct aa_sk_ctx { ...@@ -61,9 +65,9 @@ struct aa_sk_ctx {
LSM_AUDIT_DATA_NONE, \ LSM_AUDIT_DATA_NONE, \
AA_CLASS_NET, \ AA_CLASS_NET, \
OP); \ OP); \
NAME.u.net = &(NAME ## _net); \ NAME.common.u.net = &(NAME ## _net); \
aad(&NAME)->net.type = (T); \ NAME.net.type = (T); \
aad(&NAME)->net.protocol = (P) NAME.net.protocol = (P)
#define DEFINE_AUDIT_SK(NAME, OP, SK) \ #define DEFINE_AUDIT_SK(NAME, OP, SK) \
DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \ DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \
...@@ -90,21 +94,24 @@ struct aa_secmark { ...@@ -90,21 +94,24 @@ struct aa_secmark {
extern struct aa_sfs_entry aa_sfs_entry_network[]; extern struct aa_sfs_entry aa_sfs_entry_network[];
void audit_net_cb(struct audit_buffer *ab, void *va); 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); 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); int type, int protocol);
static inline int aa_profile_af_sk_perm(struct aa_profile *profile, static inline int aa_profile_af_sk_perm(struct aa_profile *profile,
struct common_audit_data *sa, struct apparmor_audit_data *ad,
u32 request, u32 request,
struct sock *sk) 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); sk->sk_type);
} }
int aa_sk_perm(const char *op, u32 request, struct sock *sk); 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); struct socket *sock);
int apparmor_secmark_check(struct aa_label *label, char *op, u32 request, int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
......
...@@ -48,6 +48,9 @@ ...@@ -48,6 +48,9 @@
#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */ #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 | \ #define PERMS_CHRS_MASK (MAY_READ | MAY_WRITE | AA_MAY_CREATE | \
AA_MAY_DELETE | AA_MAY_LINK | AA_MAY_LOCK | \ AA_MAY_DELETE | AA_MAY_LINK | AA_MAY_LOCK | \
...@@ -212,8 +215,8 @@ void aa_profile_match_label(struct aa_profile *profile, ...@@ -212,8 +215,8 @@ void aa_profile_match_label(struct aa_profile *profile,
int type, u32 request, struct aa_perms *perms); int type, u32 request, struct aa_perms *perms);
int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
u32 request, int type, u32 *deny, 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, 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 *)); void (*cb)(struct audit_buffer *, void *));
#endif /* __AA_PERM_H */ #endif /* __AA_PERM_H */
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
struct aa_ns; struct aa_ns;
extern int unprivileged_userns_apparmor_policy; extern int unprivileged_userns_apparmor_policy;
extern int aa_unprivileged_unconfined_restricted;
extern const char *const aa_profile_mode_names[]; extern const char *const aa_profile_mode_names[];
#define APPARMOR_MODE_NAMES_MAX_INDEX 4 #define APPARMOR_MODE_NAMES_MAX_INDEX 4
...@@ -74,12 +75,14 @@ enum profile_mode { ...@@ -74,12 +75,14 @@ enum profile_mode {
/* struct aa_policydb - match engine for a policy /* struct aa_policydb - match engine for a policy
* count: refcount for the pdb
* dfa: dfa pattern match * dfa: dfa pattern match
* perms: table of permissions * perms: table of permissions
* strs: table of strings, index by x * strs: table of strings, index by x
* start: set of start states for the different classes of data * start: set of start states for the different classes of data
*/ */
struct aa_policydb { struct aa_policydb {
struct kref count;
struct aa_dfa *dfa; struct aa_dfa *dfa;
struct { struct {
struct aa_perms *perms; struct aa_perms *perms;
...@@ -89,13 +92,36 @@ struct aa_policydb { ...@@ -89,13 +92,36 @@ struct aa_policydb {
aa_state_t start[AA_CLASS_LAST + 1]; 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 (pdb)
if (policy->perms) kref_get(&(pdb->count));
kvfree(policy->perms);
aa_free_str_table(&policy->trans); 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, static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy,
...@@ -139,8 +165,8 @@ struct aa_ruleset { ...@@ -139,8 +165,8 @@ struct aa_ruleset {
int size; int size;
/* TODO: merge policy and file */ /* TODO: merge policy and file */
struct aa_policydb policy; struct aa_policydb *policy;
struct aa_policydb file; struct aa_policydb *file;
struct aa_caps caps; struct aa_caps caps;
struct aa_rlimit rlimits; struct aa_rlimit rlimits;
...@@ -159,7 +185,7 @@ struct aa_ruleset { ...@@ -159,7 +185,7 @@ struct aa_ruleset {
*/ */
struct aa_attachment { struct aa_attachment {
const char *xmatch_str; const char *xmatch_str;
struct aa_policydb xmatch; struct aa_policydb *xmatch;
unsigned int xmatch_len; unsigned int xmatch_len;
int xattr_count; int xattr_count;
char **xattrs; char **xattrs;
...@@ -227,10 +253,6 @@ extern enum profile_mode aa_g_profile_mode; ...@@ -227,10 +253,6 @@ extern enum profile_mode aa_g_profile_mode;
#define profiles_ns(P) ((P)->ns) #define profiles_ns(P) ((P)->ns)
#define name_is_shared(A, B) ((A)->hname && (A)->hname == (B)->hname) #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_ruleset *aa_alloc_ruleset(gfp_t gfp);
struct aa_profile *aa_alloc_profile(const char *name, struct aa_proxy *proxy, struct aa_profile *aa_alloc_profile(const char *name, struct aa_proxy *proxy,
gfp_t gfp); gfp_t gfp);
...@@ -239,14 +261,12 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name, ...@@ -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, struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
const char *base, gfp_t gfp); const char *base, gfp_t gfp);
void aa_free_profile(struct aa_profile *profile); 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_find_child(struct aa_profile *parent, const char *name);
struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname,
size_t n); size_t n);
struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name); struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name);
struct aa_profile *aa_fqlookupn_profile(struct aa_label *base, struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
const char *fqname, size_t n); 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, ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_label *label,
u32 mask, struct aa_loaddata *udata); u32 mask, struct aa_loaddata *udata);
...@@ -254,9 +274,6 @@ ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_label *label, ...@@ -254,9 +274,6 @@ ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_label *label,
char *name, size_t size); char *name, size_t size);
void __aa_profile_list_release(struct list_head *head); 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) #define profile_unconfined(X) ((X)->mode == APPARMOR_UNCONFINED)
/** /**
...@@ -276,10 +293,10 @@ static inline aa_state_t RULE_MEDIATES(struct aa_ruleset *rules, ...@@ -276,10 +293,10 @@ static inline aa_state_t RULE_MEDIATES(struct aa_ruleset *rules,
unsigned char class) unsigned char class)
{ {
if (class <= AA_CLASS_LAST) if (class <= AA_CLASS_LAST)
return rules->policy.start[class]; return rules->policy->start[class];
else else
return aa_dfa_match_len(rules->policy.dfa, return aa_dfa_match_len(rules->policy->dfa,
rules->policy.start[0], &class, 1); rules->policy->start[0], &class, 1);
} }
static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF) 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) ...@@ -289,7 +306,7 @@ static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF)
if (!state) if (!state)
return DFA_NOMATCH; 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, 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) ...@@ -370,9 +387,12 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
return profile->audit; return profile->audit;
} }
bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns); bool aa_policy_view_capable(const struct cred *subj_cred,
bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns); struct aa_label *label, struct aa_ns *ns);
int aa_may_manage_policy(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); u32 mask);
bool aa_current_policy_view_capable(struct aa_ns *ns); bool aa_current_policy_view_capable(struct aa_ns *ns);
bool aa_current_policy_admin_capable(struct aa_ns *ns); bool aa_current_policy_admin_capable(struct aa_ns *ns);
......
...@@ -86,10 +86,7 @@ const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child, bool subns); ...@@ -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); void aa_free_ns(struct aa_ns *ns);
int aa_alloc_root_ns(void); int aa_alloc_root_ns(void);
void aa_free_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 *hname, size_t n);
struct aa_ns *aa_lookupn_ns(struct aa_ns *view, const char *name, 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, 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, ...@@ -151,15 +148,4 @@ static inline struct aa_ns *__aa_find_ns(struct list_head *head,
return __aa_findn_ns(head, name, strlen(name)); 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 */ #endif /* AA_NAMESPACE_H */
...@@ -33,7 +33,8 @@ struct aa_rlimit { ...@@ -33,7 +33,8 @@ struct aa_rlimit {
extern struct aa_sfs_entry aa_sfs_entry_rlimit[]; extern struct aa_sfs_entry aa_sfs_entry_rlimit[];
int aa_map_resource(int resource); 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); unsigned int resource, struct rlimit *new_rlim);
void __aa_transition_rlimits(struct aa_label *old, struct aa_label *new); void __aa_transition_rlimits(struct aa_label *old, struct aa_label *new);
......
...@@ -30,7 +30,7 @@ struct aa_task_ctx { ...@@ -30,7 +30,7 @@ struct aa_task_ctx {
}; };
int aa_replace_current_label(struct aa_label *label); 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_set_current_hat(struct aa_label *label, u64 token);
int aa_restore_previous_label(u64 cookie); int aa_restore_previous_label(u64 cookie);
struct aa_label *aa_get_task_label(struct task_struct *task); 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) ...@@ -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 " \ "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
"xcpu xfsz vtalrm prof winch io pwr sys emt lost" "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); 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 */ #endif /* __AA_TASK_H */
...@@ -52,31 +52,33 @@ static const char *audit_signal_mask(u32 mask) ...@@ -52,31 +52,33 @@ static const char *audit_signal_mask(u32 mask)
static void audit_signal_cb(struct audit_buffer *ab, void *va) static void audit_signal_cb(struct audit_buffer *ab, void *va)
{ {
struct common_audit_data *sa = 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_log_format(ab, " requested_mask=\"%s\"",
audit_signal_mask(aad(sa)->request)); audit_signal_mask(ad->request));
if (aad(sa)->denied & AA_SIGNAL_PERM_MASK) { if (ad->denied & AA_SIGNAL_PERM_MASK) {
audit_log_format(ab, " denied_mask=\"%s\"", 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)", audit_log_format(ab, "signal=unknown(%d)",
aad(sa)->unmappedsig); ad->unmappedsig);
else if (aad(sa)->signal < MAXMAPPED_SIGNAME) else if (ad->signal < MAXMAPPED_SIGNAME)
audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]); audit_log_format(ab, " signal=%s", sig_names[ad->signal]);
else else
audit_log_format(ab, " signal=rtmin+%d", audit_log_format(ab, " signal=rtmin+%d",
aad(sa)->signal - SIGRT_BASE); ad->signal - SIGRT_BASE);
audit_log_format(ab, " 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); 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 aa_label *peer, u32 request,
struct common_audit_data *sa) struct apparmor_audit_data *ad)
{ {
struct aa_ruleset *rules = list_first_entry(&profile->rules, struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list); typeof(*rules), list);
...@@ -87,24 +89,29 @@ static int profile_signal_perm(struct aa_profile *profile, ...@@ -87,24 +89,29 @@ static int profile_signal_perm(struct aa_profile *profile,
!ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_SIGNAL)) !ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_SIGNAL))
return 0; return 0;
aad(sa)->peer = peer; ad->subj_cred = cred;
ad->peer = peer;
/* TODO: secondary cache check <profile, profile, perm> */ /* TODO: secondary cache check <profile, profile, perm> */
state = aa_dfa_next(rules->policy.dfa, state = aa_dfa_next(rules->policy->dfa,
rules->policy.start[AA_CLASS_SIGNAL], rules->policy->start[AA_CLASS_SIGNAL],
aad(sa)->signal); ad->signal);
aa_label_match(profile, rules, peer, state, false, request, &perms); aa_label_match(profile, rules, peer, state, false, request, &perms);
aa_apply_modes_to_perms(profile, &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; 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); ad.signal = map_signal_num(sig);
aad(&sa)->unmappedsig = sig; ad.unmappedsig = sig;
return xcheck_labels(sender, target, profile, return xcheck_labels(sender, target, profile,
profile_signal_perm(profile, target, MAY_WRITE, &sa), profile_signal_perm(subj_cred, profile, target,
profile_signal_perm(profile, sender, MAY_READ, &sa)); MAY_WRITE, &ad),
profile_signal_perm(target_cred, profile, sender,
MAY_READ, &ad));
} }
...@@ -154,13 +154,14 @@ static int profile_cmp(struct aa_profile *a, struct aa_profile *b) ...@@ -154,13 +154,14 @@ static int profile_cmp(struct aa_profile *a, struct aa_profile *b)
/** /**
* vec_cmp - label comparison for set ordering * vec_cmp - label comparison for set ordering
* @a: label to compare (NOT NULL) * @a: aa_profile to compare (NOT NULL)
* @vec: vector of profiles to compare (NOT NULL) * @an: length of @a
* @n: length of @vec * @b: aa_profile to compare (NOT NULL)
* * @bn: length of @b
* Returns: <0 if a < vec *
* ==0 if a == vec * Returns: <0 if @a < @b
* >0 if a > vec * ==0 if @a == @b
* >0 if @a > @b
*/ */
static int vec_cmp(struct aa_profile **a, int an, struct aa_profile **b, int bn) 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) ...@@ -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 * aa_vec_unique - canonical sort and unique a list of profiles
* @n: number of refcounted profiles in the list (@n > 0) * @n: number of refcounted profiles in the list (@n > 0)
* @vec: list of profiles to sort and merge * @vec: list of profiles to sort and merge
* @flags: null terminator flags of @vec
* *
* Returns: the number of duplicates eliminated == references put * 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) ...@@ -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 * __label_remove - remove @label from the label set
* @l: label to remove * @label: label to remove
* @new: label to redirect to * @new: label to redirect to
* *
* Requires: labels_set(@label)->lock write_lock * Requires: labels_set(@label)->lock write_lock
...@@ -917,8 +919,8 @@ struct aa_label *aa_label_find(struct aa_label *label) ...@@ -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 * aa_label_insert - insert label @label into @ls or return existing label
* @ls - labelset to insert @label into * @ls: labelset to insert @label into
* @label - label to insert * @label: label to insert
* *
* Requires: caller to hold a valid ref on @label * 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) ...@@ -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 * 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) * @a: label to merge with @b (NOT NULL)
* @b: label to merge with @a (NOT NULL) * @b: label to merge with @a (NOT NULL)
* @gfp: memory allocation type * @gfp: memory allocation type
...@@ -1269,21 +1270,22 @@ static inline aa_state_t match_component(struct aa_profile *profile, ...@@ -1269,21 +1270,22 @@ static inline aa_state_t match_component(struct aa_profile *profile,
const char *ns_name; const char *ns_name;
if (profile->ns == tp->ns) 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 */ /* try matching with namespace name and then profile */
ns_name = aa_ns_name(profile->ns, tp->ns, true); ns_name = aa_ns_name(profile->ns, tp->ns, true);
state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1); state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1);
state = aa_dfa_match(rules->policy.dfa, state, ns_name); state = aa_dfa_match(rules->policy->dfa, state, ns_name);
state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1); state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1);
return aa_dfa_match(rules->policy.dfa, state, tp->base.hname); return aa_dfa_match(rules->policy->dfa, state, tp->base.hname);
} }
/** /**
* label_compound_match - find perms for full compound label * label_compound_match - find perms for full compound label
* @profile: profile to find perms for * @profile: profile to find perms for
* @rules: ruleset to search
* @label: label to check access permissions for * @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 * @subns: whether to do permission checks on components in a subns
* @request: permissions to request * @request: permissions to request
* @perms: perms struct to set * @perms: perms struct to set
...@@ -1321,12 +1323,12 @@ static int label_compound_match(struct aa_profile *profile, ...@@ -1321,12 +1323,12 @@ static int label_compound_match(struct aa_profile *profile,
label_for_each_cont(i, label, tp) { label_for_each_cont(i, label, tp) {
if (!aa_ns_visible(profile->ns, tp->ns, subns)) if (!aa_ns_visible(profile->ns, tp->ns, subns))
continue; continue;
state = aa_dfa_match(rules->policy.dfa, state, "//&"); state = aa_dfa_match(rules->policy->dfa, state, "//&");
state = match_component(profile, rules, tp, state); state = match_component(profile, rules, tp, state);
if (!state) if (!state)
goto fail; goto fail;
} }
*perms = *aa_lookup_perms(&rules->policy, state); *perms = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, perms); aa_apply_modes_to_perms(profile, perms);
if ((perms->allow & request) != request) if ((perms->allow & request) != request)
return -EACCES; return -EACCES;
...@@ -1379,7 +1381,7 @@ static int label_components_match(struct aa_profile *profile, ...@@ -1379,7 +1381,7 @@ static int label_components_match(struct aa_profile *profile,
return 0; return 0;
next: next:
tmp = *aa_lookup_perms(&rules->policy, state); tmp = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, &tmp); aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp); aa_perms_accum(perms, &tmp);
label_for_each_cont(i, label, tp) { label_for_each_cont(i, label, tp) {
...@@ -1388,7 +1390,7 @@ static int label_components_match(struct aa_profile *profile, ...@@ -1388,7 +1390,7 @@ static int label_components_match(struct aa_profile *profile,
state = match_component(profile, rules, tp, start); state = match_component(profile, rules, tp, start);
if (!state) if (!state)
goto fail; goto fail;
tmp = *aa_lookup_perms(&rules->policy, state); tmp = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, &tmp); aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp); aa_perms_accum(perms, &tmp);
} }
...@@ -2037,7 +2039,7 @@ static struct aa_label *labelset_next_stale(struct aa_labelset *ls) ...@@ -2037,7 +2039,7 @@ static struct aa_label *labelset_next_stale(struct aa_labelset *ls)
/** /**
* __label_update - insert updated version of @label into labelset * __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 * Returns: new label that is up to date
* else NULL on failure * else NULL on failure
......
...@@ -27,7 +27,7 @@ struct aa_perms allperms = { .allow = ALL_PERMS_MASK, ...@@ -27,7 +27,7 @@ struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
/** /**
* aa_free_str_table - free entries str table * 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) void aa_free_str_table(struct aa_str_table *t)
{ {
...@@ -85,6 +85,7 @@ char *aa_split_fqname(char *fqname, char **ns_name) ...@@ -85,6 +85,7 @@ char *aa_split_fqname(char *fqname, char **ns_name)
/** /**
* skipn_spaces - Removes leading whitespace from @str. * skipn_spaces - Removes leading whitespace from @str.
* @str: The string to be stripped. * @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. * Returns a pointer to the first non-whitespace character in @str.
* if all whitespace will return NULL * 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, ...@@ -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) void aa_info_message(const char *str)
{ {
if (audit_enabled) { 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; ad.info = str;
aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); aa_audit_msg(AUDIT_APPARMOR_STATUS, &ad, NULL);
} }
printk(KERN_INFO "AppArmor: %s\n", str); 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, ...@@ -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) static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
{ {
struct common_audit_data *sa = 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="); 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_CHRS_MASK, aa_file_perm_names,
PERMS_NAMES_MASK); PERMS_NAMES_MASK);
} }
if (aad(sa)->denied) { if (ad->denied) {
audit_log_format(ab, "denied_mask="); 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_CHRS_MASK, aa_file_perm_names,
PERMS_NAMES_MASK); PERMS_NAMES_MASK);
} }
audit_log_format(ab, " 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); FLAGS_NONE, GFP_ATOMIC);
} }
...@@ -339,8 +341,8 @@ void aa_profile_match_label(struct aa_profile *profile, ...@@ -339,8 +341,8 @@ void aa_profile_match_label(struct aa_profile *profile,
/* TODO: doesn't yet handle extended types */ /* TODO: doesn't yet handle extended types */
aa_state_t state; aa_state_t state;
state = aa_dfa_next(rules->policy.dfa, state = aa_dfa_next(rules->policy->dfa,
rules->policy.start[AA_CLASS_LABEL], rules->policy->start[AA_CLASS_LABEL],
type); type);
aa_label_match(profile, rules, label, state, false, request, perms); aa_label_match(profile, rules, label, state, false, request, perms);
} }
...@@ -349,21 +351,20 @@ void aa_profile_match_label(struct aa_profile *profile, ...@@ -349,21 +351,20 @@ void aa_profile_match_label(struct aa_profile *profile,
/* currently unused */ /* currently unused */
int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
u32 request, int type, u32 *deny, 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, struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list); typeof(*rules), list);
struct aa_perms perms; struct aa_perms perms;
aad(sa)->label = &profile->label; ad->peer = &target->label;
aad(sa)->peer = &target->label; ad->request = request;
aad(sa)->request = request;
aa_profile_match_label(profile, rules, &target->label, type, request, aa_profile_match_label(profile, rules, &target->label, type, request,
&perms); &perms);
aa_apply_modes_to_perms(profile, &perms); aa_apply_modes_to_perms(profile, &perms);
*deny |= request & perms.deny; *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, ...@@ -371,8 +372,7 @@ int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
* @profile: profile being checked * @profile: profile being checked
* @perms: perms computed for the request * @perms: perms computed for the request
* @request: requested perms * @request: requested perms
* @deny: Returns: explicit deny set * @ad: initialized audit structure (MAY BE NULL if not auditing)
* @sa: initialized audit structure (MAY BE NULL if not auditing)
* @cb: callback fn for type specific fields (MAY BE NULL) * @cb: callback fn for type specific fields (MAY BE NULL)
* *
* Returns: 0 if permission else error code * Returns: 0 if permission else error code
...@@ -385,7 +385,7 @@ int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, ...@@ -385,7 +385,7 @@ int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
* with a positive value. * with a positive value.
*/ */
int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, 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 *)) void (*cb)(struct audit_buffer *, void *))
{ {
int type, error; int type, error;
...@@ -394,7 +394,7 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, ...@@ -394,7 +394,7 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
if (likely(!denied)) { if (likely(!denied)) {
/* mask off perms that are not being force audited */ /* mask off perms that are not being force audited */
request &= perms->audit; request &= perms->audit;
if (!request || !sa) if (!request || !ad)
return 0; return 0;
type = AUDIT_APPARMOR_AUDIT; type = AUDIT_APPARMOR_AUDIT;
...@@ -413,16 +413,16 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, ...@@ -413,16 +413,16 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
error = -ENOENT; error = -ENOENT;
denied &= ~perms->quiet; denied &= ~perms->quiet;
if (!sa || !denied) if (!ad || !denied)
return error; return error;
} }
if (sa) { if (ad) {
aad(sa)->label = &profile->label; ad->subj_label = &profile->label;
aad(sa)->request = request; ad->request = request;
aad(sa)->denied = denied; ad->denied = denied;
aad(sa)->error = error; ad->error = error;
aa_audit_msg(type, sa, cb); aa_audit_msg(type, ad, cb);
} }
if (type == AUDIT_APPARMOR_ALLOWED) if (type == AUDIT_APPARMOR_ALLOWED)
......
This diff is collapsed.
...@@ -21,50 +21,6 @@ ...@@ -21,50 +21,6 @@
#define base_idx(X) ((X) & 0xffffff) #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) * unpack_table - unpack a dfa table (one of accept, default, base, next check)
* @blob: data to unpack (NOT NULL) * @blob: data to unpack (NOT NULL)
...@@ -136,7 +92,7 @@ static struct table_header *unpack_table(char *blob, size_t bsize) ...@@ -136,7 +92,7 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
/** /**
* verify_table_headers - verify that the tables headers are as expected * 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 * @flags: flags controlling what type of accept table are acceptable
* *
* Assumes dfa has gone through the first pass verification done by unpacking * Assumes dfa has gone through the first pass verification done by unpacking
...@@ -283,7 +239,7 @@ static void dfa_free(struct aa_dfa *dfa) ...@@ -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) * 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) void aa_dfa_free_kref(struct kref *kref)
{ {
......
This diff is collapsed.
...@@ -71,6 +71,7 @@ static const char * const net_mask_names[] = { ...@@ -71,6 +71,7 @@ static const char * const net_mask_names[] = {
void audit_net_cb(struct audit_buffer *ab, void *va) void audit_net_cb(struct audit_buffer *ab, void *va)
{ {
struct common_audit_data *sa = va; struct common_audit_data *sa = va;
struct apparmor_audit_data *ad = aad(sa);
if (address_family_names[sa->u.net->family]) if (address_family_names[sa->u.net->family])
audit_log_format(ab, " family=\"%s\"", audit_log_format(ab, " family=\"%s\"",
...@@ -78,35 +79,36 @@ void audit_net_cb(struct audit_buffer *ab, void *va) ...@@ -78,35 +79,36 @@ void audit_net_cb(struct audit_buffer *ab, void *va)
else else
audit_log_format(ab, " family=\"unknown(%d)\"", audit_log_format(ab, " family=\"unknown(%d)\"",
sa->u.net->family); 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\"", audit_log_format(ab, " sock_type=\"%s\"",
sock_type_names[aad(sa)->net.type]); sock_type_names[ad->net.type]);
else else
audit_log_format(ab, " sock_type=\"unknown(%d)\"", audit_log_format(ab, " sock_type=\"unknown(%d)\"",
aad(sa)->net.type); ad->net.type);
audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol); 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="); 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); 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="); 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); net_mask_names, NET_PERMS_MASK);
} }
} }
if (aad(sa)->peer) { if (ad->peer) {
audit_log_format(ab, " 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); FLAGS_NONE, GFP_ATOMIC);
} }
} }
/* Generic af perm */ /* Generic af perm */
int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, int aa_profile_af_perm(struct aa_profile *profile,
u32 request, u16 family, int type) struct apparmor_audit_data *ad, u32 request, u16 family,
int type)
{ {
struct aa_ruleset *rules = list_first_entry(&profile->rules, struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list); typeof(*rules), list);
...@@ -125,26 +127,28 @@ int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, ...@@ -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[0] = cpu_to_be16(family);
buffer[1] = cpu_to_be16((u16) type); 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); 4);
perms = *aa_lookup_perms(&rules->policy, state); perms = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, &perms); 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 aa_af_perm(const struct cred *subj_cred, struct aa_label *label,
int type, int protocol) const char *op, u32 request, u16 family, int type, int protocol)
{ {
struct aa_profile *profile; 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, return fn_for_each_confined(label, profile,
aa_profile_af_perm(profile, &sa, request, family, aa_profile_af_perm(profile, &ad, request, family,
type)); 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 sock *sk)
{ {
struct aa_sk_ctx *ctx = SK_CTX(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, ...@@ -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)) { if (ctx->label != kernel_t && !unconfined(label)) {
struct aa_profile *profile; 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, 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; return error;
...@@ -174,21 +179,21 @@ int aa_sk_perm(const char *op, u32 request, struct sock *sk) ...@@ -174,21 +179,21 @@ int aa_sk_perm(const char *op, u32 request, struct sock *sk)
/* TODO: switch to begin_current_label ???? */ /* TODO: switch to begin_current_label ???? */
label = begin_current_label_crit_section(); 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); end_current_label_crit_section(label);
return error; return error;
} }
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,
struct socket *sock) const char *op, u32 request, struct socket *sock)
{ {
AA_BUG(!label); AA_BUG(!label);
AA_BUG(!sock); AA_BUG(!sock);
AA_BUG(!sock->sk); 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 #ifdef CONFIG_NETWORK_SECMARK
...@@ -214,7 +219,7 @@ static int apparmor_secmark_init(struct aa_secmark *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, 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; int i, ret;
struct aa_perms perms = { }; struct aa_perms perms = { };
...@@ -245,17 +250,17 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid, ...@@ -245,17 +250,17 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
aa_apply_modes_to_perms(profile, &perms); 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, int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
u32 secid, const struct sock *sk) u32 secid, const struct sock *sk)
{ {
struct aa_profile *profile; struct aa_profile *profile;
DEFINE_AUDIT_SK(sa, op, sk); DEFINE_AUDIT_SK(ad, op, sk);
return fn_for_each_confined(label, profile, return fn_for_each_confined(label, profile,
aa_secmark_perm(profile, request, secid, aa_secmark_perm(profile, request, secid,
&sa)); &ad));
} }
#endif #endif
...@@ -88,6 +88,7 @@ ...@@ -88,6 +88,7 @@
#include "include/resource.h" #include "include/resource.h"
int unprivileged_userns_apparmor_policy = 1; int unprivileged_userns_apparmor_policy = 1;
int aa_unprivileged_unconfined_restricted;
const char *const aa_profile_mode_names[] = { const char *const aa_profile_mode_names[] = {
"enforce", "enforce",
...@@ -98,6 +99,41 @@ const char *const aa_profile_mode_names[] = { ...@@ -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 * __add_profile - add a profiles to list and label tree
* @list: list to add it to (NOT NULL) * @list: list to add it to (NOT NULL)
...@@ -200,15 +236,15 @@ static void free_attachment(struct aa_attachment *attach) ...@@ -200,15 +236,15 @@ static void free_attachment(struct aa_attachment *attach)
for (i = 0; i < attach->xattr_count; i++) for (i = 0; i < attach->xattr_count; i++)
kfree_sensitive(attach->xattrs[i]); kfree_sensitive(attach->xattrs[i]);
kfree_sensitive(attach->xattrs); kfree_sensitive(attach->xattrs);
aa_destroy_policydb(&attach->xmatch); aa_put_pdb(attach->xmatch);
} }
static void free_ruleset(struct aa_ruleset *rules) static void free_ruleset(struct aa_ruleset *rules)
{ {
int i; int i;
aa_destroy_policydb(&rules->file); aa_put_pdb(rules->file);
aa_destroy_policydb(&rules->policy); aa_put_pdb(rules->policy);
aa_free_cap_rules(&rules->caps); aa_free_cap_rules(&rules->caps);
aa_free_rlimit_rules(&rules->rlimits); aa_free_rlimit_rules(&rules->rlimits);
...@@ -255,6 +291,7 @@ void aa_free_profile(struct aa_profile *profile) ...@@ -255,6 +291,7 @@ void aa_free_profile(struct aa_profile *profile)
aa_put_ns(profile->ns); aa_put_ns(profile->ns);
kfree_sensitive(profile->rename); kfree_sensitive(profile->rename);
kfree_sensitive(profile->disconnected);
free_attachment(&profile->attach); free_attachment(&profile->attach);
...@@ -285,6 +322,7 @@ void aa_free_profile(struct aa_profile *profile) ...@@ -285,6 +322,7 @@ void aa_free_profile(struct aa_profile *profile)
/** /**
* aa_alloc_profile - allocate, initialize and return a new profile * aa_alloc_profile - allocate, initialize and return a new profile
* @hname: name of the profile (NOT NULL) * @hname: name of the profile (NOT NULL)
* @proxy: proxy to use OR null if to allocate a new one
* @gfp: allocation type * @gfp: allocation type
* *
* Returns: refcount profile or NULL on failure * Returns: refcount profile or NULL on failure
...@@ -588,16 +626,8 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name, ...@@ -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 */ /* TODO: ideally we should inherit abi from parent */
profile->label.flags |= FLAG_NULL; profile->label.flags |= FLAG_NULL;
rules = list_first_entry(&profile->rules, typeof(*rules), list); rules = list_first_entry(&profile->rules, typeof(*rules), list);
rules->file.dfa = aa_get_dfa(nulldfa); rules->file = aa_get_pdb(nullpdb);
rules->file.perms = kcalloc(2, sizeof(struct aa_perms), GFP_KERNEL); rules->policy = aa_get_pdb(nullpdb);
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;
if (parent) { if (parent) {
profile->path_flags = parent->path_flags; profile->path_flags = parent->path_flags;
...@@ -608,11 +638,6 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name, ...@@ -608,11 +638,6 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
} }
return profile; return profile;
fail:
aa_free_profile(profile);
return NULL;
} }
/** /**
...@@ -721,16 +746,17 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace, ...@@ -721,16 +746,17 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace,
static void audit_cb(struct audit_buffer *ab, void *va) static void audit_cb(struct audit_buffer *ab, void *va)
{ {
struct common_audit_data *sa = 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_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 * 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 * @op: policy operation being performed
* @ns_name: name of namespace being manipulated * @ns_name: name of namespace being manipulated
* @name: name of profile being manipulated (NOT NULL) * @name: name of profile being manipulated (NOT NULL)
...@@ -739,19 +765,19 @@ static void audit_cb(struct audit_buffer *ab, void *va) ...@@ -739,19 +765,19 @@ static void audit_cb(struct audit_buffer *ab, void *va)
* *
* Returns: the error to be returned after audit is done * 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 *ns_name, const char *name,
const char *info, int error) 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; ad.iface.ns = ns_name;
aad(&sa)->name = name; ad.name = name;
aad(&sa)->info = info; ad.info = info;
aad(&sa)->error = error; ad.error = error;
aad(&sa)->label = label; 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; return error;
} }
...@@ -759,31 +785,35 @@ static int audit_policy(struct aa_label *label, const char *op, ...@@ -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 /* don't call out to other LSMs in the stack for apparmor policy admin
* permissions * 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) struct user_namespace *userns, int cap)
{ {
int err; int err;
/* check for MAC_ADMIN cap in cred */ /* 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) if (!err)
err = aa_capable(label, cap, CAP_OPT_NONE); err = aa_capable(subj_cred, label, cap, CAP_OPT_NONE);
return err; return err;
} }
/** /**
* aa_policy_view_capable - check if viewing policy in at @ns is allowed * aa_policy_view_capable - check if viewing policy in at @ns is allowed
* label: label that is trying to view policy in ns * @subj_cred: cred of subject
* ns: namespace being viewed by @label (may be NULL if @label's ns) * @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 * Returns: true if viewing policy is allowed
* *
* If @ns is NULL then the namespace being viewed is assumed to be the * If @ns is NULL then the namespace being viewed is assumed to be the
* tasks current namespace. * 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); struct aa_ns *view_ns = labels_view(label);
bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) || bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) ||
in_egroup_p(make_kgid(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) ...@@ -800,15 +830,17 @@ bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns)
return response; 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(); struct user_namespace *user_ns = subj_cred->user_ns;
bool capable = policy_ns_capable(label, user_ns, CAP_MAC_ADMIN) == 0; bool capable = policy_ns_capable(subj_cred, label, user_ns,
CAP_MAC_ADMIN) == 0;
AA_DEBUG("cap_mac_admin? %d\n", capable); AA_DEBUG("cap_mac_admin? %d\n", capable);
AA_DEBUG("policy locked? %d\n", aa_g_lock_policy); 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; !aa_g_lock_policy;
} }
...@@ -818,7 +850,7 @@ bool aa_current_policy_view_capable(struct aa_ns *ns) ...@@ -818,7 +850,7 @@ bool aa_current_policy_view_capable(struct aa_ns *ns)
bool res; bool res;
label = __begin_current_label_crit_section(); 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); __end_current_label_crit_section(label);
return res; return res;
...@@ -830,7 +862,7 @@ bool aa_current_policy_admin_capable(struct aa_ns *ns) ...@@ -830,7 +862,7 @@ bool aa_current_policy_admin_capable(struct aa_ns *ns)
bool res; bool res;
label = __begin_current_label_crit_section(); 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); __end_current_label_crit_section(label);
return res; return res;
...@@ -838,12 +870,15 @@ bool aa_current_policy_admin_capable(struct aa_ns *ns) ...@@ -838,12 +870,15 @@ bool aa_current_policy_admin_capable(struct aa_ns *ns)
/** /**
* aa_may_manage_policy - can the current task manage policy * aa_may_manage_policy - can the current task manage policy
* @subj_cred: subjects cred
* @label: label to check if it can manage policy * @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 * @mask: contains the policy manipulation operation being done
* *
* Returns: 0 if the task is allowed to manipulate policy else error * 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; const char *op;
...@@ -859,7 +894,7 @@ int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask) ...@@ -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", return audit_policy(label, op, NULL, NULL, "policy_locked",
-EACCES); -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", return audit_policy(label, op, NULL, NULL, "not policy admin",
-EACCES); -EACCES);
...@@ -950,11 +985,11 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new) ...@@ -950,11 +985,11 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
/** /**
* __lookup_replace - lookup replacement information for a profile * __lookup_replace - lookup replacement information for a profile
* @ns - namespace the lookup occurs in * @ns: namespace the lookup occurs in
* @hname - name of profile to lookup * @hname: name of profile to lookup
* @noreplace - true if not replacing an existing profile * @noreplace: true if not replacing an existing profile
* @p - Returns: profile to be replaced * @p: Returns - profile to be replaced
* @info - Returns: info string on why lookup failed * @info: Returns - info string on why lookup failed
* *
* Returns: profile to replace (no ref) on success else ptr error * Returns: profile to replace (no ref) on success else ptr error
*/ */
......
...@@ -143,6 +143,7 @@ static struct aa_perms compute_fperms_other(struct aa_dfa *dfa, ...@@ -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 * compute_fperms - convert dfa compressed perms to internal perms and store
* them so they can be retrieved later. * them so they can be retrieved later.
* @dfa: a dfa using fperms to remap to internal permissions * @dfa: a dfa using fperms to remap to internal permissions
* @size: Returns the permission table size
* *
* Returns: remapped perm table * Returns: remapped perm table
*/ */
......
...@@ -159,43 +159,6 @@ void aa_free_ns(struct aa_ns *ns) ...@@ -159,43 +159,6 @@ void aa_free_ns(struct aa_ns *ns)
kfree_sensitive(ns); kfree_sensitive(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 * __aa_lookupn_ns - lookup the namespace matching @hname
* @view: namespace to search in (NOT NULL) * @view: namespace to search in (NOT NULL)
......
This diff is collapsed.
...@@ -30,18 +30,20 @@ struct aa_sfs_entry aa_sfs_entry_rlimit[] = { ...@@ -30,18 +30,20 @@ struct aa_sfs_entry aa_sfs_entry_rlimit[] = {
static void audit_cb(struct audit_buffer *ab, void *va) static void audit_cb(struct audit_buffer *ab, void *va)
{ {
struct common_audit_data *sa = va; struct common_audit_data *sa = va;
struct apparmor_audit_data *ad = aad(sa);
audit_log_format(ab, " rlimit=%s value=%lu", audit_log_format(ab, " rlimit=%s value=%lu",
rlim_names[aad(sa)->rlim.rlim], aad(sa)->rlim.max); rlim_names[ad->rlim.rlim], ad->rlim.max);
if (aad(sa)->peer) { if (ad->peer) {
audit_log_format(ab, " 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); FLAGS_NONE, GFP_ATOMIC);
} }
} }
/** /**
* audit_resource - audit setting resource limit * audit_resource - audit setting resource limit
* @subj_cred: cred setting the resource
* @profile: profile being enforced (NOT NULL) * @profile: profile being enforced (NOT NULL)
* @resource: rlimit being auditing * @resource: rlimit being auditing
* @value: value being set * @value: value being set
...@@ -49,22 +51,24 @@ static void audit_cb(struct audit_buffer *ab, void *va) ...@@ -49,22 +51,24 @@ static void audit_cb(struct audit_buffer *ab, void *va)
* @info: info being auditing * @info: info being auditing
* @error: error value * @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, unsigned long value, struct aa_label *peer,
const char *info, int error) 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); OP_SETRLIMIT);
aad(&sa)->rlim.rlim = resource; ad.subj_cred = subj_cred;
aad(&sa)->rlim.max = value; ad.rlim.rlim = resource;
aad(&sa)->peer = peer; ad.rlim.max = value;
aad(&sa)->info = info; ad.peer = peer;
aad(&sa)->error = error; 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) ...@@ -81,7 +85,8 @@ int aa_map_resource(int resource)
return rlim_map[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 rlimit *new_rlim)
{ {
struct aa_ruleset *rules = list_first_entry(&profile->rules, struct aa_ruleset *rules = list_first_entry(&profile->rules,
...@@ -91,22 +96,24 @@ static int profile_setrlimit(struct aa_profile *profile, unsigned int resource, ...@@ -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 > if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max >
rules->rlimits.limits[resource].rlim_max) rules->rlimits.limits[resource].rlim_max)
e = -EACCES; e = -EACCES;
return audit_resource(profile, resource, new_rlim->rlim_max, NULL, NULL, return audit_resource(subj_cred, profile, resource, new_rlim->rlim_max,
e); NULL, NULL, e);
} }
/** /**
* aa_task_setrlimit - test permission to set an rlimit * aa_task_setrlimit - test permission to set an rlimit
* @label - label confining the task (NOT NULL) * @subj_cred: cred setting the limit
* @task - task the resource is being set on * @label: label confining the task (NOT NULL)
* @resource - the resource being set * @task: task the resource is being set on
* @new_rlim - the new resource limit (NOT NULL) * @resource: the resource being set
* @new_rlim: the new resource limit (NOT NULL)
* *
* Control raising the processes hard limit. * Control raising the processes hard limit.
* *
* Returns: 0 or error code if setting resource failed * 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) unsigned int resource, struct rlimit *new_rlim)
{ {
struct aa_profile *profile; struct aa_profile *profile;
...@@ -125,14 +132,15 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, ...@@ -125,14 +132,15 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
*/ */
if (label != peer && 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, error = fn_for_each(label, profile,
audit_resource(profile, resource, audit_resource(subj_cred, profile, resource,
new_rlim->rlim_max, peer, new_rlim->rlim_max, peer,
"cap_sys_resource", -EACCES)); "cap_sys_resource", -EACCES));
else else
error = fn_for_each_confined(label, profile, 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); aa_put_label(peer);
return error; return error;
......
...@@ -93,9 +93,8 @@ int aa_replace_current_label(struct aa_label *label) ...@@ -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 * aa_set_current_onexec - set the tasks change_profile to happen onexec
* @label: system label to set at exec (MAYBE NULL to clear value) * @label: system label to set at exec (MAYBE NULL to clear value)
* @stack: whether stacking should be done * @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); struct aa_task_ctx *ctx = task_ctx(current);
...@@ -103,8 +102,6 @@ int aa_set_current_onexec(struct aa_label *label, bool stack) ...@@ -103,8 +102,6 @@ int aa_set_current_onexec(struct aa_label *label, bool stack)
aa_put_label(ctx->onexec); aa_put_label(ctx->onexec);
ctx->onexec = label; ctx->onexec = label;
ctx->token = stack; ctx->token = stack;
return 0;
} }
/** /**
...@@ -208,70 +205,75 @@ static const char *audit_ptrace_mask(u32 mask) ...@@ -208,70 +205,75 @@ static const char *audit_ptrace_mask(u32 mask)
static void audit_ptrace_cb(struct audit_buffer *ab, void *va) static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
{ {
struct common_audit_data *sa = 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_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_log_format(ab, " denied_mask=\"%s\"",
audit_ptrace_mask(aad(sa)->denied)); audit_ptrace_mask(ad->denied));
} }
} }
audit_log_format(ab, " 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); FLAGS_NONE, GFP_ATOMIC);
} }
/* assumes check for RULE_MEDIATES is already done */ /* assumes check for RULE_MEDIATES is already done */
/* TODO: conditionals */ /* TODO: conditionals */
static int profile_ptrace_perm(struct aa_profile *profile, static int profile_ptrace_perm(const struct cred *cred,
struct aa_label *peer, u32 request, struct aa_profile *profile,
struct common_audit_data *sa) struct aa_label *peer, u32 request,
struct apparmor_audit_data *ad)
{ {
struct aa_ruleset *rules = list_first_entry(&profile->rules, struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list); typeof(*rules), list);
struct aa_perms perms = { }; 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, aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request,
&perms); &perms);
aa_apply_modes_to_perms(profile, &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 aa_label *tracer, u32 request,
struct common_audit_data *sa) struct apparmor_audit_data *ad)
{ {
if (profile_unconfined(tracee) || unconfined(tracer) || if (profile_unconfined(tracee) || unconfined(tracer) ||
!ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE)) !ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE))
return 0; 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 aa_label *tracee, u32 request,
struct common_audit_data *sa) struct apparmor_audit_data *ad)
{ {
if (profile_unconfined(tracer)) if (profile_unconfined(tracer))
return 0; return 0;
if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE)) 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 */ /* profile uses the old style capability check for ptrace */
if (&tracer->label == tracee) if (&tracer->label == tracee)
return 0; return 0;
aad(sa)->label = &tracer->label; ad->subj_label = &tracer->label;
aad(sa)->peer = tracee; ad->peer = tracee;
aad(sa)->request = 0; ad->request = 0;
aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, ad->error = aa_capable(cred, &tracer->label, CAP_SYS_PTRACE,
CAP_OPT_NONE); 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, ...@@ -282,7 +284,8 @@ static int profile_tracer_perm(struct aa_profile *tracer,
* *
* Returns: %0 else error code if permission denied or error * 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) u32 request)
{ {
struct aa_profile *profile; struct aa_profile *profile;
...@@ -290,6 +293,49 @@ int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, ...@@ -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); DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_PTRACE, OP_PTRACE);
return xcheck_labels(tracer, tracee, profile, return xcheck_labels(tracer, tracee, profile,
profile_tracer_perm(profile, tracee, request, &sa), profile_tracer_perm(tracer_cred, profile, tracee,
profile_tracee_perm(profile, tracer, xrequest, &sa)); 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;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment