diff options
author | John Johansen <john.johansen@canonical.com> | 2022-09-19 20:48:48 -0700 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2023-10-18 15:30:38 -0700 |
commit | 90c436a64a6e20482a9a613c47eb4af2e8a5328e (patch) | |
tree | b5df0d74b93bb320f34f5b4a109f46a9128ea0b7 | |
parent | d20f5a1a6e792d22199c9989ec7ab9e95c48d60c (diff) | |
download | linux-90c436a64a6e20482a9a613c47eb4af2e8a5328e.tar.gz linux-90c436a64a6e20482a9a613c47eb4af2e8a5328e.tar.bz2 linux-90c436a64a6e20482a9a613c47eb4af2e8a5328e.zip |
apparmor: pass cred through to audit info.
The cred is needed to properly audit some messages, and will be needed
in the future for uid conditional mediation. So pass it through to
where the apparmor_audit_data struct gets defined.
Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
-rw-r--r-- | security/apparmor/apparmorfs.c | 11 | ||||
-rw-r--r-- | security/apparmor/capability.c | 5 | ||||
-rw-r--r-- | security/apparmor/domain.c | 97 | ||||
-rw-r--r-- | security/apparmor/file.c | 131 | ||||
-rw-r--r-- | security/apparmor/include/audit.h | 1 | ||||
-rw-r--r-- | security/apparmor/include/capability.h | 3 | ||||
-rw-r--r-- | security/apparmor/include/file.h | 17 | ||||
-rw-r--r-- | security/apparmor/include/ipc.h | 4 | ||||
-rw-r--r-- | security/apparmor/include/mount.h | 21 | ||||
-rw-r--r-- | security/apparmor/include/net.h | 6 | ||||
-rw-r--r-- | security/apparmor/include/policy.h | 9 | ||||
-rw-r--r-- | security/apparmor/include/resource.h | 3 | ||||
-rw-r--r-- | security/apparmor/include/task.h | 3 | ||||
-rw-r--r-- | security/apparmor/ipc.c | 14 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 85 | ||||
-rw-r--r-- | security/apparmor/mount.c | 85 | ||||
-rw-r--r-- | security/apparmor/net.c | 17 | ||||
-rw-r--r-- | security/apparmor/policy.c | 33 | ||||
-rw-r--r-- | security/apparmor/resource.c | 23 | ||||
-rw-r--r-- | security/apparmor/task.c | 31 |
20 files changed, 388 insertions, 211 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 37234e385fd1..f20d923944e4 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -423,7 +423,7 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size, /* high level check about policy management - fine grained in * below after unpack */ - error = aa_may_manage_policy(label, ns, mask); + error = aa_may_manage_policy(current_cred(), label, ns, mask); if (error) goto end_section; @@ -486,7 +486,8 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, /* high level check about policy management - fine grained in * below after unpack */ - error = aa_may_manage_policy(label, ns, AA_MAY_REMOVE_POLICY); + error = aa_may_manage_policy(current_cred(), label, ns, + AA_MAY_REMOVE_POLICY); if (error) goto out; @@ -1800,7 +1801,8 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, int error; label = begin_current_label_crit_section(); - error = aa_may_manage_policy(label, NULL, AA_MAY_LOAD_POLICY); + error = aa_may_manage_policy(current_cred(), label, NULL, + AA_MAY_LOAD_POLICY); end_current_label_crit_section(label); if (error) return error; @@ -1849,7 +1851,8 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) int error; label = begin_current_label_crit_section(); - error = aa_may_manage_policy(label, NULL, AA_MAY_LOAD_POLICY); + error = aa_may_manage_policy(current_cred(), label, NULL, + AA_MAY_LOAD_POLICY); end_current_label_crit_section(label); if (error) return error; diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 35979a832994..0b7d2b1086c9 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c @@ -140,6 +140,7 @@ static int profile_capable(struct aa_profile *profile, int cap, /** * aa_capable - test permission to use capability + * @subj_cread: cred we are testing capability against * @label: label being tested for capability (NOT NULL) * @cap: capability to be tested * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated @@ -148,12 +149,14 @@ static int profile_capable(struct aa_profile *profile, int cap, * * Returns: 0 on success, or else an error code. */ -int aa_capable(struct aa_label *label, int cap, unsigned int opts) +int aa_capable(const struct cred *subj_cred, struct aa_label *label, + int cap, unsigned int opts) { struct aa_profile *profile; int error = 0; DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_CAP, AA_CLASS_CAP, OP_CAPABLE); + ad.subj_cred = subj_cred; ad.common.u.cap = cap; error = fn_for_each_confined(label, profile, profile_capable(profile, cap, opts, &ad)); diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 7f81502019da..d95292a23bcf 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -31,6 +31,7 @@ /** * may_change_ptraced_domain - check if can change profile on ptraced task + * @cred: cred of task changing domain * @to_label: profile to change to (NOT NULL) * @info: message if there is an error * @@ -39,28 +40,34 @@ * * Returns: %0 or error if change not allowed */ -static int may_change_ptraced_domain(struct aa_label *to_label, +static int may_change_ptraced_domain(const struct cred *to_cred, + struct aa_label *to_label, const char **info) { struct task_struct *tracer; struct aa_label *tracerl = NULL; + const struct cred *tracer_cred = NULL; + int error = 0; rcu_read_lock(); tracer = ptrace_parent(current); - if (tracer) + if (tracer) { /* released below */ tracerl = aa_get_task_label(tracer); - + tracer_cred = get_task_cred(tracer); + } /* not ptraced */ if (!tracer || unconfined(tracerl)) goto out; - error = aa_may_ptrace(tracerl, to_label, PTRACE_MODE_ATTACH); + error = aa_may_ptrace(tracer_cred, tracerl, to_cred, to_label, + PTRACE_MODE_ATTACH); out: rcu_read_unlock(); aa_put_label(tracerl); + put_cred(tracer_cred); if (error) *info = "ptrace prevents transition"; @@ -621,7 +628,8 @@ static struct aa_label *x_to_label(struct aa_profile *profile, return new; } -static struct aa_label *profile_transition(struct aa_profile *profile, +static struct aa_label *profile_transition(const struct cred *subj_cred, + struct aa_profile *profile, const struct linux_binprm *bprm, char *buffer, struct path_cond *cond, bool *secure_exec) @@ -711,7 +719,8 @@ static struct aa_label *profile_transition(struct aa_profile *profile, } audit: - aa_audit_file(profile, &perms, OP_EXEC, MAY_EXEC, name, target, new, + aa_audit_file(subj_cred, profile, &perms, OP_EXEC, MAY_EXEC, name, + target, new, cond->uid, info, error); if (!new || nonewprivs) { aa_put_label(new); @@ -721,7 +730,8 @@ audit: return new; } -static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec, +static int profile_onexec(const struct cred *subj_cred, + struct aa_profile *profile, struct aa_label *onexec, bool stack, const struct linux_binprm *bprm, char *buffer, struct path_cond *cond, bool *secure_exec) @@ -789,13 +799,15 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec, } audit: - return aa_audit_file(profile, &perms, OP_EXEC, AA_MAY_ONEXEC, xname, + return aa_audit_file(subj_cred, profile, &perms, OP_EXEC, + AA_MAY_ONEXEC, xname, NULL, onexec, cond->uid, info, error); } /* ensure none ns domain transitions are correctly applied with onexec */ -static struct aa_label *handle_onexec(struct aa_label *label, +static struct aa_label *handle_onexec(const struct cred *subj_cred, + struct aa_label *label, struct aa_label *onexec, bool stack, const struct linux_binprm *bprm, char *buffer, struct path_cond *cond, @@ -812,26 +824,28 @@ static struct aa_label *handle_onexec(struct aa_label *label, if (!stack) { error = fn_for_each_in_ns(label, profile, - profile_onexec(profile, onexec, stack, + profile_onexec(subj_cred, profile, onexec, stack, bprm, buffer, cond, unsafe)); if (error) return ERR_PTR(error); new = fn_label_build_in_ns(label, profile, GFP_KERNEL, aa_get_newest_label(onexec), - profile_transition(profile, bprm, buffer, + profile_transition(subj_cred, profile, bprm, + buffer, cond, unsafe)); } else { /* TODO: determine how much we want to loosen this */ error = fn_for_each_in_ns(label, profile, - profile_onexec(profile, onexec, stack, bprm, + profile_onexec(subj_cred, profile, onexec, stack, bprm, buffer, cond, unsafe)); if (error) return ERR_PTR(error); new = fn_label_build_in_ns(label, profile, GFP_KERNEL, aa_label_merge(&profile->label, onexec, GFP_KERNEL), - profile_transition(profile, bprm, buffer, + profile_transition(subj_cred, profile, bprm, + buffer, cond, unsafe)); } @@ -840,7 +854,8 @@ static struct aa_label *handle_onexec(struct aa_label *label, /* TODO: get rid of GLOBAL_ROOT_UID */ error = fn_for_each_in_ns(label, profile, - aa_audit_file(profile, &nullperms, OP_CHANGE_ONEXEC, + aa_audit_file(subj_cred, profile, &nullperms, + OP_CHANGE_ONEXEC, AA_MAY_ONEXEC, bprm->filename, NULL, onexec, GLOBAL_ROOT_UID, "failed to build target label", -ENOMEM)); @@ -859,6 +874,7 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm) { struct aa_task_ctx *ctx; struct aa_label *label, *new = NULL; + const struct cred *subj_cred; struct aa_profile *profile; char *buffer = NULL; const char *info = NULL; @@ -871,6 +887,7 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm) file_inode(bprm->file)->i_mode }; + subj_cred = current_cred(); ctx = task_ctx(current); AA_BUG(!cred_label(bprm->cred)); AA_BUG(!ctx); @@ -897,11 +914,12 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm) /* Test for onexec first as onexec override other x transitions. */ if (ctx->onexec) - new = handle_onexec(label, ctx->onexec, ctx->token, + new = handle_onexec(subj_cred, label, ctx->onexec, ctx->token, bprm, buffer, &cond, &unsafe); else new = fn_label_build(label, profile, GFP_KERNEL, - profile_transition(profile, bprm, buffer, + profile_transition(subj_cred, profile, bprm, + buffer, &cond, &unsafe)); AA_BUG(!new); @@ -936,7 +954,7 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm) if (bprm->unsafe & (LSM_UNSAFE_PTRACE)) { /* TODO: test needs to be profile of label to new */ - error = may_change_ptraced_domain(new, &info); + error = may_change_ptraced_domain(bprm->cred, new, &info); if (error) goto audit; } @@ -973,7 +991,8 @@ done: audit: error = fn_for_each(label, profile, - aa_audit_file(profile, &nullperms, OP_EXEC, MAY_EXEC, + aa_audit_file(current_cred(), profile, &nullperms, + OP_EXEC, MAY_EXEC, bprm->filename, NULL, new, vfsuid_into_kuid(vfsuid), info, error)); aa_put_label(new); @@ -989,7 +1008,8 @@ audit: * * Returns: label for hat transition OR ERR_PTR. Does NOT return NULL */ -static struct aa_label *build_change_hat(struct aa_profile *profile, +static struct aa_label *build_change_hat(const struct cred *subj_cred, + struct aa_profile *profile, const char *name, bool sibling) { struct aa_profile *root, *hat = NULL; @@ -1021,7 +1041,8 @@ static struct aa_label *build_change_hat(struct aa_profile *profile, aa_put_profile(root); audit: - aa_audit_file(profile, &nullperms, OP_CHANGE_HAT, AA_MAY_CHANGEHAT, + aa_audit_file(subj_cred, profile, &nullperms, OP_CHANGE_HAT, + AA_MAY_CHANGEHAT, name, hat ? hat->base.hname : NULL, hat ? &hat->label : NULL, GLOBAL_ROOT_UID, info, error); @@ -1037,7 +1058,8 @@ audit: * * Returns: label for hat transition or ERR_PTR. Does not return NULL */ -static struct aa_label *change_hat(struct aa_label *label, const char *hats[], +static struct aa_label *change_hat(const struct cred *subj_cred, + struct aa_label *label, const char *hats[], int count, int flags) { struct aa_profile *profile, *root, *hat = NULL; @@ -1113,7 +1135,8 @@ fail: */ /* TODO: get rid of GLOBAL_ROOT_UID */ if (count > 1 || COMPLAIN_MODE(profile)) { - aa_audit_file(profile, &nullperms, OP_CHANGE_HAT, + aa_audit_file(subj_cred, profile, &nullperms, + OP_CHANGE_HAT, AA_MAY_CHANGEHAT, name, NULL, NULL, GLOBAL_ROOT_UID, info, error); } @@ -1122,7 +1145,8 @@ fail: build: new = fn_label_build_in_ns(label, profile, GFP_KERNEL, - build_change_hat(profile, name, sibling), + build_change_hat(subj_cred, profile, name, + sibling), aa_get_label(&profile->label)); if (!new) { info = "label build failed"; @@ -1152,7 +1176,7 @@ build: */ int aa_change_hat(const char *hats[], int count, u64 token, int flags) { - const struct cred *cred; + const struct cred *subj_cred; struct aa_task_ctx *ctx = task_ctx(current); struct aa_label *label, *previous, *new = NULL, *target = NULL; struct aa_profile *profile; @@ -1161,8 +1185,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) int error = 0; /* released below */ - cred = get_current_cred(); - label = aa_get_newest_cred_label(cred); + subj_cred = get_current_cred(); + label = aa_get_newest_cred_label(subj_cred); previous = aa_get_newest_label(ctx->previous); /* @@ -1182,7 +1206,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) } if (count) { - new = change_hat(label, hats, count, flags); + new = change_hat(subj_cred, label, hats, count, flags); AA_BUG(!new); if (IS_ERR(new)) { error = PTR_ERR(new); @@ -1191,7 +1215,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) goto out; } - error = may_change_ptraced_domain(new, &info); + /* target cred is the same as current except new label */ + error = may_change_ptraced_domain(subj_cred, new, &info); if (error) goto fail; @@ -1244,7 +1269,7 @@ out: aa_put_label(new); aa_put_label(previous); aa_put_label(label); - put_cred(cred); + put_cred(subj_cred); return error; @@ -1254,7 +1279,7 @@ kill: fail: fn_for_each_in_ns(label, profile, - aa_audit_file(profile, &perms, OP_CHANGE_HAT, + aa_audit_file(subj_cred, profile, &perms, OP_CHANGE_HAT, AA_MAY_CHANGEHAT, NULL, NULL, target, GLOBAL_ROOT_UID, info, error)); @@ -1263,6 +1288,7 @@ fail: static int change_profile_perms_wrapper(const char *op, const char *name, + const struct cred *subj_cred, struct aa_profile *profile, struct aa_label *target, bool stack, u32 request, struct aa_perms *perms) @@ -1277,7 +1303,8 @@ static int change_profile_perms_wrapper(const char *op, const char *name, rules->file.start[AA_CLASS_FILE], perms); if (error) - error = aa_audit_file(profile, perms, op, request, name, + error = aa_audit_file(subj_cred, profile, perms, op, request, + name, NULL, target, GLOBAL_ROOT_UID, info, error); @@ -1306,6 +1333,7 @@ int aa_change_profile(const char *fqname, int flags) const char *auditname = fqname; /* retain leading & if stack */ bool stack = flags & AA_CHANGE_STACK; struct aa_task_ctx *ctx = task_ctx(current); + const struct cred *subj_cred = get_current_cred(); int error = 0; char *op; u32 request; @@ -1383,6 +1411,7 @@ int aa_change_profile(const char *fqname, int flags) */ error = fn_for_each_in_ns(label, profile, change_profile_perms_wrapper(op, auditname, + subj_cred, profile, target, stack, request, &perms)); if (error) @@ -1393,7 +1422,7 @@ int aa_change_profile(const char *fqname, int flags) check: /* check if tracing task is allowed to trace target domain */ - error = may_change_ptraced_domain(target, &info); + error = may_change_ptraced_domain(subj_cred, target, &info); if (error && !fn_for_each_in_ns(label, profile, COMPLAIN_MODE(profile))) goto audit; @@ -1453,7 +1482,8 @@ check: audit: error = fn_for_each_in_ns(label, profile, - aa_audit_file(profile, &perms, op, request, auditname, + aa_audit_file(subj_cred, + profile, &perms, op, request, auditname, NULL, new ? new : target, GLOBAL_ROOT_UID, info, error)); @@ -1461,6 +1491,7 @@ out: aa_put_label(new); aa_put_label(target); aa_put_label(label); + put_cred(subj_cred); return error; } diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 26d45effdbc7..48afcef45694 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -45,7 +45,7 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; struct apparmor_audit_data *ad = aad(sa); - kuid_t fsuid = current_fsuid(); + kuid_t fsuid = ad->subj_cred ? ad->subj_cred->fsuid : current_fsuid(); char str[10]; if (ad->request & AA_AUDIT_FILE_MASK) { @@ -77,6 +77,7 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) /** * aa_audit_file - handle the auditing of file operations + * @subj_cred: cred of the subject * @profile: the profile being enforced (NOT NULL) * @perms: the permissions computed for the request (NOT NULL) * @op: operation being mediated @@ -90,7 +91,8 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) * * Returns: %0 or error on failure */ -int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms, +int aa_audit_file(const struct cred *subj_cred, + struct aa_profile *profile, struct aa_perms *perms, const char *op, u32 request, const char *name, const char *target, struct aa_label *tlabel, kuid_t ouid, const char *info, int error) @@ -98,6 +100,7 @@ int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms, int type = AUDIT_APPARMOR_AUTO; DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_TASK, AA_CLASS_FILE, op); + ad.subj_cred = subj_cred; ad.request = request; ad.name = name; ad.fs.target = target; @@ -141,7 +144,21 @@ int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms, return aa_audit(type, profile, &ad, file_audit_cb); } -static int path_name(const char *op, struct aa_label *label, +/** + * is_deleted - test if a file has been completely unlinked + * @dentry: dentry of file to test for deletion (NOT NULL) + * + * Returns: true if deleted else false + */ +static inline bool is_deleted(struct dentry *dentry) +{ + if (d_unlinked(dentry) && d_backing_inode(dentry)->i_nlink == 0) + return true; + return false; +} + +static int path_name(const char *op, const struct cred *subj_cred, + struct aa_label *label, const struct path *path, int flags, char *buffer, const char **name, struct path_cond *cond, u32 request) { @@ -153,7 +170,8 @@ static int path_name(const char *op, struct aa_label *label, labels_profile(label)->disconnected); if (error) { fn_for_each_confined(label, profile, - aa_audit_file(profile, &nullperms, op, request, *name, + aa_audit_file(subj_cred, + profile, &nullperms, op, request, *name, NULL, NULL, cond->uid, info, error)); return error; } @@ -207,9 +225,9 @@ aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start, return state; } -static int __aa_path_perm(const char *op, struct aa_profile *profile, - const char *name, u32 request, - struct path_cond *cond, int flags, +static int __aa_path_perm(const char *op, const struct cred *subj_cred, + struct aa_profile *profile, const char *name, + u32 request, struct path_cond *cond, int flags, struct aa_perms *perms) { struct aa_ruleset *rules = list_first_entry(&profile->rules, @@ -222,12 +240,14 @@ static int __aa_path_perm(const char *op, struct aa_profile *profile, name, cond, perms); if (request & ~perms->allow) e = -EACCES; - return aa_audit_file(profile, perms, op, request, name, NULL, NULL, + return aa_audit_file(subj_cred, + profile, perms, op, request, name, NULL, NULL, cond->uid, NULL, e); } -static int profile_path_perm(const char *op, struct aa_profile *profile, +static int profile_path_perm(const char *op, const struct cred *subj_cred, + struct aa_profile *profile, const struct path *path, char *buffer, u32 request, struct path_cond *cond, int flags, struct aa_perms *perms) @@ -238,18 +258,19 @@ static int profile_path_perm(const char *op, struct aa_profile *profile, if (profile_unconfined(profile)) return 0; - error = path_name(op, &profile->label, path, + error = path_name(op, subj_cred, &profile->label, path, flags | profile->path_flags, buffer, &name, cond, request); if (error) return error; - return __aa_path_perm(op, profile, name, request, cond, flags, - perms); + return __aa_path_perm(op, subj_cred, profile, name, request, cond, + flags, perms); } /** * aa_path_perm - do permissions check & audit for @path * @op: operation being checked + * @subj_cred: subject cred * @label: profile being enforced (NOT NULL) * @path: path to check permissions of (NOT NULL) * @flags: any additional path flags beyond what the profile specifies @@ -258,7 +279,8 @@ static int profile_path_perm(const char *op, struct aa_profile *profile, * * Returns: %0 else error if access denied or other error */ -int aa_path_perm(const char *op, struct aa_label *label, +int aa_path_perm(const char *op, const struct cred *subj_cred, + struct aa_label *label, const struct path *path, int flags, u32 request, struct path_cond *cond) { @@ -273,8 +295,8 @@ int aa_path_perm(const char *op, struct aa_label *label, if (!buffer) return -ENOMEM; error = fn_for_each_confined(label, profile, - profile_path_perm(op, profile, path, buffer, request, - cond, flags, &perms)); + profile_path_perm(op, subj_cred, profile, path, buffer, + request, cond, flags, &perms)); aa_put_buffer(buffer); @@ -301,7 +323,8 @@ static inline bool xindex_is_subset(u32 link, u32 target) return true; } -static int profile_path_link(struct aa_profile *profile, +static int profile_path_link(const struct cred *subj_cred, + struct aa_profile *profile, const struct path *link, char *buffer, const struct path *target, char *buffer2, struct path_cond *cond) @@ -315,13 +338,15 @@ static int profile_path_link(struct aa_profile *profile, aa_state_t state; int error; - error = path_name(OP_LINK, &profile->label, link, profile->path_flags, + error = path_name(OP_LINK, subj_cred, &profile->label, link, + profile->path_flags, buffer, &lname, cond, AA_MAY_LINK); if (error) goto audit; /* buffer2 freed below, tname is pointer in buffer2 */ - error = path_name(OP_LINK, &profile->label, target, profile->path_flags, + error = path_name(OP_LINK, subj_cred, &profile->label, target, + profile->path_flags, buffer2, &tname, cond, AA_MAY_LINK); if (error) goto audit; @@ -381,12 +406,14 @@ done_tests: error = 0; audit: - return aa_audit_file(profile, &lperms, OP_LINK, request, lname, tname, + return aa_audit_file(subj_cred, + profile, &lperms, OP_LINK, request, lname, tname, NULL, cond->uid, info, error); } /** * aa_path_link - Handle hard link permission check + * @subj_cred: subject cred * @label: the label being enforced (NOT NULL) * @old_dentry: the target dentry (NOT NULL) * @new_dir: directory the new link will be created in (NOT NULL) @@ -403,7 +430,8 @@ audit: * * Returns: %0 if allowed else error */ -int aa_path_link(struct aa_label *label, struct dentry *old_dentry, +int aa_path_link(const struct cred *subj_cred, + struct aa_label *label, struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry) { struct path link = { .mnt = new_dir->mnt, .dentry = new_dentry }; @@ -424,8 +452,8 @@ int aa_path_link(struct aa_label *label, struct dentry *old_dentry, goto out; error = fn_for_each_confined(label, profile, - profile_path_link(profile, &link, buffer, &target, - buffer2, &cond)); + profile_path_link(subj_cred, profile, &link, buffer, + &target, buffer2, &cond)); out: aa_put_buffer(buffer); aa_put_buffer(buffer2); @@ -453,7 +481,8 @@ static void update_file_ctx(struct aa_file_ctx *fctx, struct aa_label *label, spin_unlock(&fctx->lock); } -static int __file_path_perm(const char *op, struct aa_label *label, +static int __file_path_perm(const char *op, const struct cred *subj_cred, + struct aa_label *label, struct aa_label *flabel, struct file *file, u32 request, u32 denied, bool in_atomic) { @@ -480,7 +509,8 @@ static int __file_path_perm(const char *op, struct aa_label *label, /* check every profile in task label not in current cache */ error = fn_for_each_not_in_set(flabel, label, profile, - profile_path_perm(op, profile, &file->f_path, buffer, + profile_path_perm(op, subj_cred, profile, + &file->f_path, buffer, request, &cond, flags, &perms)); if (denied && !error) { /* @@ -493,12 +523,14 @@ static int __file_path_perm(const char *op, struct aa_label *label, */ if (label == flabel) error = fn_for_each(label, profile, - profile_path_perm(op, profile, &file->f_path, + profile_path_perm(op, subj_cred, + profile, &file->f_path, buffer, request, &cond, flags, &perms)); else error = fn_for_each_not_in_set(label, flabel, profile, - profile_path_perm(op, profile, &file->f_path, + profile_path_perm(op, subj_cred, + profile, &file->f_path, buffer, request, &cond, flags, &perms)); } @@ -510,7 +542,8 @@ static int __file_path_perm(const char *op, struct aa_label *label, return error; } -static int __file_sock_perm(const char *op, struct aa_label *label, +static int __file_sock_perm(const char *op, const struct cred *subj_cred, + struct aa_label *label, struct aa_label *flabel, struct file *file, u32 request, u32 denied) { @@ -524,11 +557,12 @@ static int __file_sock_perm(const char *op, struct aa_label *label, return 0; /* TODO: improve to skip profiles cached in flabel */ - error = aa_sock_file_perm(label, op, request, sock); + error = aa_sock_file_perm(subj_cred, label, op, request, sock); if (denied) { /* TODO: improve to skip profiles checked above */ /* check every profile in file label to is cached */ - last_error(error, aa_sock_file_perm(flabel, op, request, sock)); + last_error(error, aa_sock_file_perm(subj_cred, flabel, op, + request, sock)); } if (!error) update_file_ctx(file_ctx(file), label, request); @@ -539,6 +573,7 @@ static int __file_sock_perm(const char *op, struct aa_label *label, /** * aa_file_perm - do permission revalidation check & audit for @file * @op: operation being checked + * @subj_cred: subject cred * @label: label being enforced (NOT NULL) * @file: file to revalidate access permissions on (NOT NULL) * @request: requested permissions @@ -546,7 +581,8 @@ static int __file_sock_perm(const char *op, struct aa_label *label, * * Returns: %0 if access allowed else error */ -int aa_file_perm(const char *op, struct aa_label *label, struct file *file, +int aa_file_perm(const char *op, const struct cred *subj_cred, + struct aa_label *label, struct file *file, u32 request, bool in_atomic) { struct aa_file_ctx *fctx; @@ -582,19 +618,19 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file, /* TODO: label cross check */ if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry)) - error = __file_path_perm(op, label, flabel, file, request, - denied, in_atomic); + error = __file_path_perm(op, subj_cred, label, flabel, file, + request, denied, in_atomic); else if (S_ISSOCK(file_inode(file)->i_mode)) - error = __file_sock_perm(op, label, flabel, file, request, - denied); + error = __file_sock_perm(op, subj_cred, label, flabel, file, + request, denied); aa_put_label(flabel); done: return error; } -static void revalidate_tty(struct aa_label *label) +static void revalidate_tty(const struct cred *subj_cred, struct aa_label *label) { struct tty_struct *tty; int drop_tty = 0; @@ -612,8 +648,8 @@ static void revalidate_tty(struct aa_label *label) struct tty_file_private, list); file = file_priv->file; - if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE, - IN_ATOMIC)) + if (aa_file_perm(OP_INHERIT, subj_cred, label, file, + MAY_READ | MAY_WRITE, IN_ATOMIC)) drop_tty = 1; } spin_unlock(&tty->files_lock); @@ -623,12 +659,17 @@ static void revalidate_tty(struct aa_label *label) no_tty(); } +struct cred_label { + const struct cred *cred; + struct aa_label *label; +}; + static int match_file(const void *p, struct file *file, unsigned int fd) { - struct aa_label *label = (struct aa_label *)p; + struct cred_label *cl = (struct cred_label *)p; - if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file), - IN_ATOMIC)) + if (aa_file_perm(OP_INHERIT, cl->cred, cl->label, file, + aa_map_file_to_perms(file), IN_ATOMIC)) return fd + 1; return 0; } @@ -638,13 +679,17 @@ static int match_file(const void *p, struct file *file, unsigned int fd) void aa_inherit_files(const struct cred *cred, struct files_struct *files) { struct aa_label *label = aa_get_newest_cred_label(cred); + struct cred_label cl = { + .cred = cred, + .label = label, + }; struct file *devnull = NULL; unsigned int n; - revalidate_tty(label); + revalidate_tty(cred, label); /* Revalidate access to inherited open files. */ - n = iterate_fd(files, 0, match_file, label); + n = iterate_fd(files, 0, match_file, &cl); if (!n) /* none found? */ goto out; @@ -654,7 +699,7 @@ void aa_inherit_files(const struct cred *cred, struct files_struct *files) /* replace all the matching ones with this */ do { replace_fd(n - 1, devnull, 0); - } while ((n = iterate_fd(files, n, match_file, label)) != 0); + } while ((n = iterate_fd(files, n, match_file, &cl)) != 0); if (devnull) fput(devnull); out: diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 096f0a04af87..42d701fec5a6 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -109,6 +109,7 @@ struct apparmor_audit_data { int type; u16 class; const char *op; + const struct cred *subj_cred; struct aa_label *subj_label; const char *name; const char *info; diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h index d420e2d10b31..d6dcc604ec0c 100644 --- a/security/apparmor/include/capability.h +++ b/security/apparmor/include/capability.h @@ -36,7 +36,8 @@ struct aa_caps { extern struct aa_sfs_entry aa_sfs_entry_caps[]; -int aa_capable(struct aa_label *label, int cap, unsigned int opts); +int aa_capable(const struct cred *subj_cred, struct aa_label *label, + int cap, unsigned int opts); static inline void aa_free_cap_rules(struct aa_caps *caps) { diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 23cb6f9dbe6e..6e8f2aa66cd6 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -71,7 +71,8 @@ struct path_cond { #define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill) -int aa_audit_fi |