From bd7bd201ca46c211c3ab251ca9854787d1331a2f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 14 Sep 2022 00:20:12 -0700 Subject: apparmor: combine common_audit_data and apparmor_audit_data Everywhere where common_audit_data is used apparmor audit_data is also used. We can simplify the code and drop the use of the aad macro everywhere by combining the two structures. Reviewed-by: Georgia Garcia Signed-off-by: John Johansen --- security/apparmor/net.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'security/apparmor/net.c') diff --git a/security/apparmor/net.c b/security/apparmor/net.c index 788be1609a86..0c7304cd479c 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c @@ -71,6 +71,7 @@ static const char * const net_mask_names[] = { void audit_net_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; + struct apparmor_audit_data *ad = aad(sa); if (address_family_names[sa->u.net->family]) audit_log_format(ab, " family=\"%s\"", @@ -78,35 +79,36 @@ void audit_net_cb(struct audit_buffer *ab, void *va) else audit_log_format(ab, " family=\"unknown(%d)\"", sa->u.net->family); - if (sock_type_names[aad(sa)->net.type]) + if (sock_type_names[ad->net.type]) audit_log_format(ab, " sock_type=\"%s\"", - sock_type_names[aad(sa)->net.type]); + sock_type_names[ad->net.type]); else audit_log_format(ab, " sock_type=\"unknown(%d)\"", - aad(sa)->net.type); - audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol); + ad->net.type); + audit_log_format(ab, " protocol=%d", ad->net.protocol); - if (aad(sa)->request & NET_PERMS_MASK) { + if (ad->request & NET_PERMS_MASK) { audit_log_format(ab, " requested_mask="); - aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0, + aa_audit_perm_mask(ab, ad->request, NULL, 0, net_mask_names, NET_PERMS_MASK); - if (aad(sa)->denied & NET_PERMS_MASK) { + if (ad->denied & NET_PERMS_MASK) { audit_log_format(ab, " denied_mask="); - aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0, + aa_audit_perm_mask(ab, ad->denied, NULL, 0, net_mask_names, NET_PERMS_MASK); } } - if (aad(sa)->peer) { + if (ad->peer) { audit_log_format(ab, " peer="); - aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, + aa_label_xaudit(ab, labels_ns(ad->label), ad->peer, FLAGS_NONE, GFP_ATOMIC); } } /* Generic af perm */ -int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, - u32 request, u16 family, int type) +int aa_profile_af_perm(struct aa_profile *profile, + struct apparmor_audit_data *ad, u32 request, u16 family, + int type) { struct aa_ruleset *rules = list_first_entry(&profile->rules, typeof(*rules), list); @@ -130,17 +132,17 @@ int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, perms = *aa_lookup_perms(&rules->policy, state); aa_apply_modes_to_perms(profile, &perms); - return aa_check_perms(profile, &perms, request, sa, audit_net_cb); + return aa_check_perms(profile, &perms, request, ad, audit_net_cb); } int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, int type, int protocol) { struct aa_profile *profile; - DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol); + DEFINE_AUDIT_NET(ad, op, NULL, family, type, protocol); return fn_for_each_confined(label, profile, - aa_profile_af_perm(profile, &sa, request, family, + aa_profile_af_perm(profile, &ad, request, family, type)); } @@ -155,10 +157,10 @@ static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, if (ctx->label != kernel_t && !unconfined(label)) { struct aa_profile *profile; - DEFINE_AUDIT_SK(sa, op, sk); + DEFINE_AUDIT_SK(ad, op, sk); 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; @@ -214,7 +216,7 @@ static int apparmor_secmark_init(struct aa_secmark *secmark) } static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid, - struct common_audit_data *sa) + struct apparmor_audit_data *ad) { int i, ret; struct aa_perms perms = { }; @@ -245,17 +247,17 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid, aa_apply_modes_to_perms(profile, &perms); - return aa_check_perms(profile, &perms, request, sa, audit_net_cb); + return aa_check_perms(profile, &perms, request, ad, audit_net_cb); } int apparmor_secmark_check(struct aa_label *label, char *op, u32 request, u32 secid, const struct sock *sk) { struct aa_profile *profile; - DEFINE_AUDIT_SK(sa, op, sk); + DEFINE_AUDIT_SK(ad, op, sk); return fn_for_each_confined(label, profile, aa_secmark_perm(profile, request, secid, - &sa)); + &ad)); } #endif -- cgit From d20f5a1a6e792d22199c9989ec7ab9e95c48d60c Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 19 Sep 2022 00:46:09 -0700 Subject: apparmor: rename audit_data->label to audit_data->subj_label rename audit_data's label field to subj_label to better reflect its use. Also at the same time drop unneeded assignments to ->subj_label as the later call to aa_check_perms will do the assignment if needed. Reviewed-by: Georgia Garcia Signed-off-by: John Johansen --- security/apparmor/audit.c | 6 +++--- security/apparmor/file.c | 2 +- security/apparmor/include/audit.h | 2 +- security/apparmor/ipc.c | 2 +- security/apparmor/lib.c | 5 ++--- security/apparmor/lsm.c | 4 ++-- security/apparmor/net.c | 2 +- security/apparmor/policy.c | 6 +++--- security/apparmor/resource.c | 2 +- security/apparmor/task.c | 4 ++-- 10 files changed, 17 insertions(+), 18 deletions(-) (limited to 'security/apparmor/net.c') diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 06ad6a8fcce1..6933cb2f679b 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -113,8 +113,8 @@ static void audit_pre(struct audit_buffer *ab, void *va) audit_log_format(ab, " error=%d", ad->error); } - if (ad->label) { - struct aa_label *label = ad->label; + if (ad->subj_label) { + struct aa_label *label = ad->subj_label; if (label_isprofile(label)) { struct aa_profile *profile = labels_profile(label); @@ -187,7 +187,7 @@ int aa_audit(int type, struct aa_profile *profile, if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) type = AUDIT_APPARMOR_KILL; - ad->label = &profile->label; + ad->subj_label = &profile->label; aa_audit_msg(type, ad, cb); diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 01ff612c060e..26d45effdbc7 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -67,7 +67,7 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) if (ad->peer) { audit_log_format(ab, " target="); - aa_label_xaudit(ab, labels_ns(ad->label), ad->peer, + aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, FLAG_VIEW_SUBNS, GFP_KERNEL); } else if (ad->fs.target) { audit_log_format(ab, " target="); diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 85931ec94e91..096f0a04af87 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -109,7 +109,7 @@ struct apparmor_audit_data { int type; u16 class; const char *op; - struct aa_label *label; + struct aa_label *subj_label; const char *name; const char *info; u32 request; diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index f198b8d620a4..fd8306399b82 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -71,7 +71,7 @@ static void audit_signal_cb(struct audit_buffer *ab, void *va) audit_log_format(ab, " signal=rtmin+%d", ad->signal - SIGRT_BASE); audit_log_format(ab, " peer="); - aa_label_xaudit(ab, labels_ns(ad->label), ad->peer, + aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, FLAGS_NONE, GFP_ATOMIC); } diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index d6b2750fd72e..c87bccafff44 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -297,7 +297,7 @@ static void aa_audit_perms_cb(struct audit_buffer *ab, void *va) PERMS_NAMES_MASK); } audit_log_format(ab, " peer="); - aa_label_xaudit(ab, labels_ns(ad->label), ad->peer, + aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, FLAGS_NONE, GFP_ATOMIC); } @@ -357,7 +357,6 @@ int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, typeof(*rules), list); struct aa_perms perms; - ad->label = &profile->label; ad->peer = &target->label; ad->request = request; @@ -419,7 +418,7 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, } if (ad) { - ad->label = &profile->label; + ad->subj_label = &profile->label; ad->request = request; ad->denied = denied; ad->error = error; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index a8c8b179a16c..3a9a9902d117 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -722,11 +722,11 @@ out: return error; fail: - ad.label = begin_current_label_crit_section(); + ad.subj_label = begin_current_label_crit_section(); ad.info = name; ad.error = error = -EINVAL; aa_audit_msg(AUDIT_APPARMOR_DENIED, &ad, NULL); - end_current_label_crit_section(ad.label); + end_current_label_crit_section(ad.subj_label); goto out; } diff --git a/security/apparmor/net.c b/security/apparmor/net.c index 0c7304cd479c..5e50f80e35db 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c @@ -100,7 +100,7 @@ void audit_net_cb(struct audit_buffer *ab, void *va) } if (ad->peer) { audit_log_format(ab, " peer="); - aa_label_xaudit(ab, labels_ns(ad->label), ad->peer, + aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, FLAGS_NONE, GFP_ATOMIC); } } diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 4e26c97f1396..d78970d4a851 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -733,7 +733,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) /** * audit_policy - Do auditing of policy changes - * @label: label to check if it can manage policy + * @subj_label: label to check if it can manage policy * @op: policy operation being performed * @ns_name: name of namespace being manipulated * @name: name of profile being manipulated (NOT NULL) @@ -742,7 +742,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) * * Returns: the error to be returned after audit is done */ -static int audit_policy(struct aa_label *label, const char *op, +static int audit_policy(struct aa_label *subj_label, const char *op, const char *ns_name, const char *name, const char *info, int error) { @@ -752,7 +752,7 @@ static int audit_policy(struct aa_label *label, const char *op, ad.name = name; ad.info = info; ad.error = error; - ad.label = label; + ad.subj_label = subj_label; aa_audit_msg(AUDIT_APPARMOR_STATUS, &ad, audit_cb); diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index b6b5e1bfe9a2..73ba26c646a5 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -36,7 +36,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) rlim_names[ad->rlim.rlim], ad->rlim.max); if (ad->peer) { audit_log_format(ab, " peer="); - aa_label_xaudit(ab, labels_ns(ad->label), ad->peer, + aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, FLAGS_NONE, GFP_ATOMIC); } } diff --git a/security/apparmor/task.c b/security/apparmor/task.c index b2a777ed14d8..552442844ff8 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c @@ -217,7 +217,7 @@ static void audit_ptrace_cb(struct audit_buffer *ab, void *va) } } audit_log_format(ab, " peer="); - aa_label_xaudit(ab, labels_ns(ad->label), ad->peer, + aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, FLAGS_NONE, GFP_ATOMIC); } @@ -263,7 +263,7 @@ static int profile_tracer_perm(struct aa_profile *tracer, if (&tracer->label == tracee) return 0; - ad->label = &tracer->label; + ad->subj_label = &tracer->label; ad->peer = tracee; ad->request = 0; ad->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, -- cgit From 90c436a64a6e20482a9a613c47eb4af2e8a5328e Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 19 Sep 2022 20:48:48 -0700 Subject: 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 Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 11 ++- security/apparmor/capability.c | 5 +- security/apparmor/domain.c | 97 +++++++++++++++--------- security/apparmor/file.c | 131 ++++++++++++++++++++++----------- security/apparmor/include/audit.h | 1 + security/apparmor/include/capability.h | 3 +- security/apparmor/include/file.h | 17 +++-- security/apparmor/include/ipc.h | 4 +- security/apparmor/include/mount.h | 21 ++++-- security/apparmor/include/net.h | 6 +- security/apparmor/include/policy.h | 9 ++- security/apparmor/include/resource.h | 3 +- security/apparmor/include/task.h | 3 +- security/apparmor/ipc.c | 14 +++- security/apparmor/lsm.c | 85 ++++++++++++--------- security/apparmor/mount.c | 85 +++++++++++++-------- security/apparmor/net.c | 17 +++-- security/apparmor/policy.c | 33 +++++---- security/apparmor/resource.c | 23 ++++-- security/apparmor/task.c | 31 +++++--- 20 files changed, 388 insertions(+), 211 deletions(-) (limited to 'security/apparmor/net.c') 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_file(struct aa_profile *profile, struct aa_perms *perms, +int aa_audit_file(const struct cred *cred, + struct aa_profile *profile, struct aa_perms *perms, const char *op, u32 request, const char *name, const char *target, struct aa_label *tlabel, kuid_t ouid, const char *info, int error); @@ -82,14 +83,16 @@ aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start, const char *name, struct path_cond *cond, struct aa_perms *perms); -int aa_path_perm(const char *op, struct aa_label *label, - const struct path *path, int flags, u32 request, - struct path_cond *cond); +int aa_path_perm(const char *op, const struct cred *subj_cred, + struct aa_label *label, const struct path *path, + int flags, u32 request, struct path_cond *cond); -int aa_path_link(struct aa_label *label, struct dentry *old_dentry, - const struct path *new_dir, struct dentry *new_dentry); +int aa_path_link(const struct cred *subj_cred, struct aa_label *label, + struct dentry *old_dentry, const struct path *new_dir, + struct dentry *new_dentry); -int aa_file_perm(const char *op, struct aa_label *label, struct file *file, +int aa_file_perm(const char *op, const struct cred *subj_cred, + struct aa_label *label, struct file *file, u32 request, bool in_atomic); void aa_inherit_files(const struct cred *cred, struct files_struct *files); diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h index a1ac6ffb95e9..74d17052f76b 100644 --- a/security/apparmor/include/ipc.h +++ b/security/apparmor/include/ipc.h @@ -13,6 +13,8 @@ #include -int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig); +int aa_may_signal(const struct cred *subj_cred, struct aa_label *sender, + const struct cred *target_cred, struct aa_label *target, + int sig); #endif /* __AA_IPC_H */ diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h index a710683b2496..10c76f906a65 100644 --- a/security/apparmor/include/mount.h +++ b/security/apparmor/include/mount.h @@ -25,26 +25,33 @@ #define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN) -int aa_remount(struct aa_label *label, const struct path *path, +int aa_remount(const struct cred *subj_cred, + struct aa_label *label, const struct path *path, unsigned long flags, void *data); -int aa_bind_mount(struct aa_label *label, const struct path *path, +int aa_bind_mount(const struct cred *subj_cred, + struct aa_label *label, const struct path *path, const char *old_name, unsigned long flags); -int aa_mount_change_type(struct aa_label *label, const struct path *path, +int aa_mount_change_type(const struct cred *subj_cred, + struct aa_label *label, const struct path *path, unsigned long flags); -int aa_move_mount(struct aa_label *label, const struct path *path, +int aa_move_mount(const struct cred *subj_cred, + struct aa_label *label, const struct path *path, const char *old_name); -int aa_new_mount(struct aa_label *label, const char *dev_name, +int aa_new_mount(const struct cred *subj_cred, + struct aa_label *label, const char *dev_name, const struct path *path, const char *type, unsigned long flags, void *data); -int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags); +int aa_umount(const struct cred *subj_cred, + struct aa_label *label, struct vfsmount *mnt, int flags); -int aa_pivotroot(struct aa_label *label, const struct path *old_path, +int aa_pivotroot(const struct cred *subj_cred, + struct aa_label *label, const struct path *old_path, const struct path *new_path); #endif /* __AA_MOUNT_H */ diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h index e0068a3a4efd..67bf888c3bd6 100644 --- a/security/apparmor/include/net.h +++ b/security/apparmor/include/net.h @@ -97,7 +97,8 @@ void audit_net_cb(struct audit_buffer *ab, void *va); int aa_profile_af_perm(struct aa_profile *profile, struct apparmor_audit_data *ad, u32 request, u16 family, int type); -int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, +int aa_af_perm(const struct cred *subj_cred, struct aa_label *label, + const char *op, u32 request, u16 family, int type, int protocol); static inline int aa_profile_af_sk_perm(struct aa_profile *profile, struct apparmor_audit_data *ad, @@ -109,7 +110,8 @@ static inline int aa_profile_af_sk_perm(struct aa_profile *profile, } int aa_sk_perm(const char *op, u32 request, struct sock *sk); -int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, +int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label, + const char *op, u32 request, struct socket *sock); int apparmor_secmark_check(struct aa_label *label, char *op, u32 request, diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 062a4cd3c367..5572447d7c37 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -361,9 +361,12 @@ static inline int AUDIT_MODE(struct aa_profile *profile) return profile->audit; } -bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns); -bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns); -int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, +bool aa_policy_view_capable(const struct cred *subj_cred, + struct aa_label *label, struct aa_ns *ns); +bool aa_policy_admin_capable(const struct cred *subj_cred, + struct aa_label *label, struct aa_ns *ns); +int aa_may_manage_policy(const struct cred *subj_cred, + struct aa_label *label, struct aa_ns *ns, u32 mask); bool aa_current_policy_view_capable(struct aa_ns *ns); bool aa_current_policy_admin_capable(struct aa_ns *ns); diff --git a/security/apparmor/include/resource.h b/security/apparmor/include/resource.h index 961d85d328ea..ad2c0da8e64f 100644 --- a/security/apparmor/include/resource.h +++ b/security/apparmor/include/resource.h @@ -33,7 +33,8 @@ struct aa_rlimit { extern struct aa_sfs_entry aa_sfs_entry_rlimit[]; int aa_map_resource(int resource); -int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, +int aa_task_setrlimit(const struct cred *subj_cred, struct aa_label *label, + struct task_struct *task, unsigned int resource, struct rlimit *new_rlim); void __aa_transition_rlimits(struct aa_label *old, struct aa_label *new); diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h index 01717fe432c3..13945e2495f0 100644 --- a/security/apparmor/include/task.h +++ b/security/apparmor/include/task.h @@ -91,7 +91,8 @@ static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \ "xcpu xfsz vtalrm prof winch io pwr sys emt lost" -int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, +int aa_may_ptrace(const struct cred *tracer_cred, struct aa_label *tracer, + const struct cred *tracee_cred, struct aa_label *tracee, u32 request); diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index fd8306399b82..c0d0dbd7b4c4 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -75,7 +75,8 @@ static void audit_signal_cb(struct audit_buffer *ab, void *va) 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 apparmor_audit_data *ad) { @@ -88,6 +89,7 @@ static int profile_signal_perm(struct aa_profile *profile, !ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_SIGNAL)) return 0; + ad->subj_cred = cred; ad->peer = peer; /* TODO: secondary cache check */ state = aa_dfa_next(rules->policy.dfa, @@ -98,7 +100,9 @@ static int profile_signal_perm(struct aa_profile *profile, return aa_check_perms(profile, &perms, request, ad, audit_signal_cb); } -int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig) +int aa_may_signal(const struct cred *subj_cred, struct aa_label *sender, + const struct cred *target_cred, struct aa_label *target, + int sig) { struct aa_profile *profile; DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_SIGNAL, OP_SIGNAL); @@ -106,6 +110,8 @@ int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig) ad.signal = map_signal_num(sig); ad.unmappedsig = sig; return xcheck_labels(sender, target, profile, - profile_signal_perm(profile, target, MAY_WRITE, &ad), - profile_signal_perm(profile, sender, MAY_READ, &ad)); + profile_signal_perm(subj_cred, profile, target, + MAY_WRITE, &ad), + profile_signal_perm(target_cred, profile, sender, + MAY_READ, &ad)); } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 3a9a9902d117..9e31a932a644 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -116,15 +116,17 @@ static int apparmor_ptrace_access_check(struct task_struct *child, unsigned int mode) { struct aa_label *tracer, *tracee; + const struct cred *cred; int error; + cred = get_task_cred(child); + tracee = cred_label(cred); /* ref count on cred */ tracer = __begin_current_label_crit_section(); - tracee = aa_get_task_label(child); - error = aa_may_ptrace(tracer, tracee, + error = aa_may_ptrace(current_cred(), tracer, cred, tracee, (mode & PTRACE_MODE_READ) ? AA_PTRACE_READ : AA_PTRACE_TRACE); - aa_put_label(tracee); __end_current_label_crit_section(tracer); + put_cred(cred); return error; } @@ -132,12 +134,15 @@ static int apparmor_ptrace_access_check(struct task_struct *child, static int apparmor_ptrace_traceme(struct task_struct *parent) { struct aa_label *tracer, *tracee; + const struct cred *cred; int error; tracee = __begin_current_label_crit_section(); - tracer = aa_get_task_label(parent); - error = aa_may_ptrace(tracer, tracee, AA_PTRACE_TRACE); - aa_put_label(tracer); + cred = get_task_cred(parent); + tracer = cred_label(cred); /* ref count on cred */ + error = aa_may_ptrace(cred, tracer, current_cred(), tracee, + AA_PTRACE_TRACE); + put_cred(cred); __end_current_label_crit_section(tracee); return error; @@ -188,7 +193,7 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, label = aa_get_newest_cred_label(cred); if (!unconfined(label)) - error = aa_capable(label, cap, opts); + error = aa_capable(cred, label, cap, opts); aa_put_label(label); return error; @@ -211,7 +216,8 @@ static int common_perm(const char *op, const struct path *path, u32 mask, label = __begin_current_label_crit_section(); if (!unconfined(label)) - error = aa_path_perm(op, label, path, 0, mask, cond); + error = aa_path_perm(op, current_cred(), label, path, 0, mask, + cond); __end_current_label_crit_section(label); return error; @@ -357,7 +363,8 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_ label = begin_current_label_crit_section(); if (!unconfined(label)) - error = aa_path_link(label, old_dentry, new_dir, new_dentry); + error = aa_path_link(current_cred(), label, old_dentry, new_dir, + new_dentry); end_current_label_crit_section(label); return error; @@ -396,23 +403,27 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d vfsuid = i_uid_into_vfsuid(idmap, d_backing_inode(old_dentry)); cond_exchange.uid = vfsuid_into_kuid(vfsuid); - error = aa_path_perm(OP_RENAME_SRC, label, &new_path, 0, + error = aa_path_perm(OP_RENAME_SRC, current_cred(), + label, &new_path, 0, MAY_READ | AA_MAY_GETATTR | MAY_WRITE | AA_MAY_SETATTR | AA_MAY_DELETE, &cond_exchange); if (!error) - error = aa_path_perm(OP_RENAME_DEST, label, &old_path, + error = aa_path_perm(OP_RENAME_DEST, current_cred(), + label, &old_path, 0, MAY_WRITE | AA_MAY_SETATTR | AA_MAY_CREATE, &cond_exchange); } if (!error) - error = aa_path_perm(OP_RENAME_SRC, label, &old_path, 0, + error = aa_path_perm(OP_RENAME_SRC, current_cred(), + label, &old_path, 0, MAY_READ | AA_MAY_GETATTR | MAY_WRITE | AA_MAY_SETATTR | AA_MAY_DELETE, &cond); if (!error) - error = aa_path_perm(OP_RENAME_DEST, label, &new_path, + error = aa_path_perm(OP_RENAME_DEST, current_cred(), + label, &new_path, 0, MAY_WRITE | AA_MAY_SETATTR | AA_MAY_CREATE, &cond); @@ -467,7 +478,8 @@ static int apparmor_file_open(struct file *file) vfsuid = i_uid_into_vfsuid(idmap, inode); cond.uid = vfsuid_into_kuid(vfsuid); - error = aa_path_perm(OP_OPEN, label, &file->f_path, 0, + error = aa_path_perm(OP_OPEN, file->f_cred, + label, &file->f_path, 0, aa_map_file_to_perms(file), &cond); /* todo cache full allowed permissions set and state */ fctx->allow = aa_map_file_to_perms(file); @@ -507,7 +519,7 @@ static int common_file_perm(const char *op, struct file *file, u32 mask, return -EACCES; label = __begin_current_label_crit_section(); - error = aa_file_perm(op, label, file, mask, in_atomic); + error = aa_file_perm(op, current_cred(), label, file, mask, in_atomic); __end_current_label_crit_section(label); return error; @@ -585,17 +597,21 @@ static int apparmor_sb_mount(const char *dev_name, const struct path *path, label = __begin_current_label_crit_section(); if (!unconfined(label)) { if (flags & MS_REMOUNT) - error = aa_remount(label, path, flags, data); + error = aa_remount(current_cred(), label, path, flags, + data); else if (flags & MS_BIND) - error = aa_bind_mount(label, path, dev_name, flags); + error = aa_bind_mount(current_cred(), label, path, + dev_name, flags); else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) - error = aa_mount_change_type(label, path, flags); + error = aa_mount_change_type(current_cred(), label, + path, flags); else if (flags & MS_MOVE) - error = aa_move_mount(label, path, dev_name); + error = aa_move_mount(current_cred(), label, path, + dev_name); else - error = aa_new_mount(label, dev_name, path, type, - flags, data); + error = aa_new_mount(current_cred(), label, dev_name, + path, type, flags, data); } __end_current_label_crit_section(label); @@ -609,7 +625,7 @@ static int apparmor_sb_umount(struct vfsmount *mnt, int flags) label = __begin_current_label_crit_section(); if (!unconfined(label)) - error = aa_umount(label, mnt, flags); + error = aa_umount(current_cred(), label, mnt, flags); __end_current_label_crit_section(label); return error; @@ -623,7 +639,7 @@ static int apparmor_sb_pivotroot(const struct path *old_path, label = aa_get_current_label(); if (!unconfined(label)) - error = aa_pivotroot(label, old_path, new_path); + error = aa_pivotroot(current_cred(), label, old_path, new_path); aa_put_label(label); return error; @@ -785,7 +801,8 @@ static int apparmor_task_setrlimit(struct task_struct *task, int error = 0; if (!unconfined(label)) - error = aa_task_setrlimit(label, task, resource, new_rlim); + error = aa_task_setrlimit(current_cred(), label, task, + resource, new_rlim); __end_current_label_crit_section(label); return error; @@ -794,26 +811,27 @@ static int apparmor_task_setrlimit(struct task_struct *task, static int apparmor_task_kill(struct task_struct *target, struct kernel_siginfo *info, int sig, const struct cred *cred) { + const struct cred *tc; struct aa_label *cl, *tl; int error; + tc = get_task_cred(target); + tl = aa_get_newest_cred_label(tc); if (cred) { /* * Dealing with USB IO specific behavior */ cl = aa_get_newest_cred_label(cred); - tl = aa_get_task_label(target); - error = aa_may_signal(cl, tl, sig); + error = aa_may_signal(cred, cl, tc, tl, sig); aa_put_label(cl); - aa_put_label(tl); return error; + } else { + cl = __begin_current_label_crit_section(); + error = aa_may_signal(current_cred(), cl, tc, tl, sig); + __end_current_label_crit_section(cl); } - - cl = __begin_current_label_crit_section(); - tl = aa_get_task_label(target); - error = aa_may_signal(cl, tl, sig); aa_put_label(tl); - __end_current_label_crit_section(cl); + put_cred(tc); return error; } @@ -879,7 +897,8 @@ static int apparmor_socket_create(int family, int type, int protocol, int kern) if (!(kern || unconfined(label))) error = af_select(family, create_perm(label, family, type, protocol), - aa_af_perm(label, OP_CREATE, AA_MAY_CREATE, + aa_af_perm(current_cred(), label, + OP_CREATE, AA_MAY_CREATE, family, type, protocol)); end_current_label_crit_section(label); diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 3830bceff9c8..2bb77aacc49a 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -113,6 +113,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) /** * audit_mount - handle the auditing of mount operations + * @subj_cred: cred of the subject * @profile: the profile being enforced (NOT NULL) * @op: operation being mediated (NOT NULL) * @name: name of object being mediated (MAYBE NULL) @@ -128,7 +129,8 @@ static void audit_cb(struct audit_buffer *ab, void *va) * * Returns: %0 or error on failure */ -static int audit_mount(struct aa_profile *profile, const char *op, +static int audit_mount(const struct cred *subj_cred, + struct aa_profile *profile, const char *op, const char *name, const char *src_name, const char *type, const char *trans, unsigned long flags, const void *data, u32 request, @@ -166,6 +168,7 @@ static int audit_mount(struct aa_profile *profile, const char *op, return error; } + ad.subj_cred = subj_cred; ad.name = name; ad.mnt.src_name = src_name; ad.mnt.type = type; @@ -284,6 +287,7 @@ static int path_flags(struct aa_profile *profile, const struct path *path) /** * match_mnt_path_str - handle path matching for mount + * @subj_cred: cred of confined subject * @profile: the confining profile * @mntpath: for the mntpnt (NOT NULL) * @buffer: buffer to be used to lookup mntpath @@ -296,7 +300,8 @@ static int path_flags(struct aa_profile *profile, const struct path *path) * * Returns: 0 on success else error */ -static int match_mnt_path_str(struct aa_profile *profile, +static int match_mnt_path_str(const struct cred *subj_cred, + struct aa_profile *profile, const struct path *mntpath, char *buffer, const char *devname, const char *type, unsigned long flags, void *data, bool binary, @@ -337,12 +342,14 @@ static int match_mnt_path_str(struct aa_profile *profile, error = 0; audit: - return audit_mount(profile, OP_MOUNT, mntpnt, devname, type, NULL, + return audit_mount(subj_cred, profile, OP_MOUNT, mntpnt, devname, + type, NULL, flags, data, AA_MAY_MOUNT, &perms, info, error); } /** * match_mnt - handle path matching for mount + * @subj_cred: cred of the subject * @profile: the confining profile * @path: for the mntpnt (NOT NULL) * @buffer: buffer to be used to lookup mntpath @@ -355,7 +362,8 @@ audit: * * Returns: 0 on success else error */ -static int match_mnt(struct aa_profile *profile, const struct path *path, +static int match_mnt(const struct cred *subj_cred, + struct aa_profile *profile, const struct path *path, char *buffer, const struct path *devpath, char *devbuffer, const char *type, unsigned long flags, void *data, bool binary) @@ -379,11 +387,12 @@ static int match_mnt(struct aa_profile *profile, const struct path *path, devname = ERR_PTR(error); } - return match_mnt_path_str(profile, path, buffer, devname, type, flags, - data, binary, info); + return match_mnt_path_str(subj_cred, profile, path, buffer, devname, + type, flags, data, binary, info); } -int aa_remount(struct aa_label *label, const struct path *path, +int aa_remount(const struct cred *subj_cred, + struct aa_label *label, const struct path *path, unsigned long flags, void *data) { struct aa_profile *profile; @@ -400,14 +409,16 @@ int aa_remount(struct aa_label *label, const struct path *path, if (!buffer) return -ENOMEM; error = fn_for_each_confined(label, profile, - match_mnt(profile, path, buffer, NULL, NULL, NULL, + match_mnt(subj_cred, profile, path, buffer, NULL, + NULL, NULL, flags, data, binary)); aa_put_buffer(buffer); return error; } -int aa_bind_mount(struct aa_label *label, const struct path *path, +int aa_bind_mount(const struct cred *subj_cred, + struct aa_label *label, const struct path *path, const char *dev_name, unsigned long flags) { struct aa_profile *profile; @@ -434,8 +445,8 @@ int aa_bind_mount(struct aa_label *label, const struct path *path, goto out; error = fn_for_each_confined(label, profile, - match_mnt(profile, path, buffer, &old_path, old_buffer, - NULL, flags, NULL, false)); + match_mnt(subj_cred, profile, path, buffer, &old_path, + old_buffer, NULL, flags, NULL, false)); out: aa_put_buffer(buffer); aa_put_buffer(old_buffer); @@ -444,7 +455,8 @@ out: return error; } -int aa_mount_change_type(struct aa_label *label, const struct path *path, +int aa_mount_change_type(const struct cred *subj_cred, + struct aa_label *label, const struct path *path, unsigned long flags) { struct aa_profile *profile; @@ -462,14 +474,16 @@ int aa_mount_change_type(struct aa_label *label, const struct path *path, if (!buffer) return -ENOMEM; error = fn_for_each_confined(label, profile, - match_mnt(profile, path, buffer, NULL, NULL, NULL, + match_mnt(subj_cred, profile, path, buffer, NULL, + NULL, NULL, flags, NULL, false)); aa_put_buffer(buffer); return error; } -int aa_move_mount(struct aa_label *label, const struct path *path, +int aa_move_mount(const struct cred *subj_cred, + struct aa_label *label, const struct path *path, const char *orig_name) { struct aa_profile *profile; @@ -493,7 +507,8 @@ int aa_move_mount(struct aa_label *label, const struct path *path, if (!buffer || !old_buffer) goto out; error = fn_for_each_confined(label, profile, - match_mnt(profile, path, buffer, &old_path, old_buffer, + match_mnt(subj_cred, profile, path, buffer, &old_path, + old_buffer, NULL, MS_MOVE, NULL, false)); out: aa_put_buffer(buffer); @@ -503,9 +518,9 @@ out: return error; } -int aa_new_mount(struct aa_label *label, const char *dev_name, - const struct path *path, const char *type, unsigned long flags, - void *data) +int aa_new_mount(const struct cred *subj_cred, struct aa_label *label, + const char *dev_name, const struct path *path, + const char *type, unsigned long flags, void *data) { struct aa_profile *profile; char *buffer = NULL, *dev_buffer = NULL; @@ -550,12 +565,14 @@ int aa_new_mount(struct aa_label *label, const char *dev_name, goto out; } error = fn_for_each_confined(label, profile, - match_mnt(profile, path, buffer, dev_path, dev_buffer, + match_mnt(subj_cred, profile, path, buffer, + dev_path, dev_buffer, type, flags, data, binary)); } else { error = fn_for_each_confined(label, profile, - match_mnt_path_str(profile, path, buffer, dev_name, - type, flags, data, binary, NULL)); + match_mnt_path_str(subj_cred, profile, path, + buffer, dev_name, + type, flags, data, binary, NULL)); } out: @@ -567,7 +584,8 @@ out: return error; } -static int profile_umount(struct aa_profile *profile, const struct path *path, +static int profile_umount(const struct cred *subj_cred, + struct aa_profile *profile, const struct path *path, char *buffer) { struct aa_ruleset *rules = list_first_entry(&profile->rules, @@ -596,11 +614,13 @@ static int profile_umount(struct aa_profile *profile, const struct path *path, error = -EACCES; audit: - return audit_mount(profile, OP_UMOUNT, name, NULL, NULL, NULL, 0, NULL, + return audit_mount(subj_cred, profile, OP_UMOUNT, name, NULL, NULL, + NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error); } -int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags) +int aa_umount(const struct cred *subj_cred, struct aa_label *label, + struct vfsmount *mnt, int flags) { struct aa_profile *profile; char *buffer = NULL; @@ -615,7 +635,7 @@ int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags) return -ENOMEM; error = fn_for_each_confined(label, profile, - profile_umount(profile, &path, buffer)); + profile_umount(subj_cred, profile, &path, buffer)); aa_put_buffer(buffer); return error; @@ -625,7 +645,8 @@ int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags) * * Returns: label for transition or ERR_PTR. Does not return NULL */ -static struct aa_label *build_pivotroot(struct aa_profile *profile, +static struct aa_label *build_pivotroot(const struct cred *subj_cred, + struct aa_profile *profile, const struct path *new_path, char *new_buffer, const struct path *old_path, @@ -670,7 +691,8 @@ static struct aa_label *build_pivotroot(struct aa_profile *profile, error = 0; audit: - error = audit_mount(profile, OP_PIVOTROOT, new_name, old_name, + error = audit_mount(subj_cred, profile, OP_PIVOTROOT, new_name, + old_name, NULL, trans_name, 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error); if (error) @@ -679,7 +701,8 @@ audit: return aa_get_newest_label(&profile->label); } -int aa_pivotroot(struct aa_label *label, const struct path *old_path, +int aa_pivotroot(const struct cred *subj_cred, struct aa_label *label, + const struct path *old_path, const struct path *new_path) { struct aa_profile *profile; @@ -697,7 +720,8 @@ int aa_pivotroot(struct aa_label *label, const struct path *old_path, if (!old_buffer || !new_buffer) goto out; target = fn_label_build(label, profile, GFP_KERNEL, - build_pivotroot(profile, new_path, new_buffer, + build_pivotroot(subj_cred, profile, new_path, + new_buffer, old_path, old_buffer)); if (!target) { info = "label build failed"; @@ -723,7 +747,8 @@ out: fail: /* TODO: add back in auditing of new_name and old_name */ error = fn_for_each(label, profile, - audit_mount(profile, OP_PIVOTROOT, NULL /*new_name */, + audit_mount(subj_cred, profile, OP_PIVOTROOT, + NULL /*new_name */, NULL /* old_name */, NULL, NULL, 0, NULL, AA_MAY_PIVOTROOT, &nullperms, info, diff --git a/security/apparmor/net.c b/security/apparmor/net.c index 5e50f80e35db..704c171232ab 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c @@ -135,8 +135,8 @@ int aa_profile_af_perm(struct aa_profile *profile, return aa_check_perms(profile, &perms, request, ad, audit_net_cb); } -int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, - int type, int protocol) +int aa_af_perm(const struct cred *subj_cred, struct aa_label *label, + const char *op, u32 request, u16 family, int type, int protocol) { struct aa_profile *profile; DEFINE_AUDIT_NET(ad, op, NULL, family, type, protocol); @@ -146,7 +146,9 @@ int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, type)); } -static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, +static int aa_label_sk_perm(const struct cred *subj_cred, + struct aa_label *label, + const char *op, u32 request, struct sock *sk) { struct aa_sk_ctx *ctx = SK_CTX(sk); @@ -159,6 +161,7 @@ static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, struct aa_profile *profile; DEFINE_AUDIT_SK(ad, op, sk); + ad.subj_cred = subj_cred; error = fn_for_each_confined(label, profile, aa_profile_af_sk_perm(profile, &ad, request, sk)); } @@ -176,21 +179,21 @@ int aa_sk_perm(const char *op, u32 request, struct sock *sk) /* TODO: switch to begin_current_label ???? */ label = begin_current_label_crit_section(); - error = aa_label_sk_perm(label, op, request, sk); + error = aa_label_sk_perm(current_cred(), label, op, request, sk); end_current_label_crit_section(label); return error; } -int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, - struct socket *sock) +int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label, + const char *op, u32 request, struct socket *sock) { AA_BUG(!label); AA_BUG(!sock); AA_BUG(!sock->sk); - return aa_label_sk_perm(label, op, request, sock->sk); + return aa_label_sk_perm(subj_cred, label, op, request, sock->sk); } #ifdef CONFIG_NETWORK_SECMARK diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index d78970d4a851..6f80e1207d24 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -762,21 +762,23 @@ static int audit_policy(struct aa_label *subj_label, const char *op, /* don't call out to other LSMs in the stack for apparmor policy admin * permissions */ -static int policy_ns_capable(struct aa_label *label, +static int policy_ns_capable(const struct cred *subj_cred, + struct aa_label *label, struct user_namespace *userns, int cap) { int err; /* check for MAC_ADMIN cap in cred */ - err = cap_capable(current_cred(), userns, cap, CAP_OPT_NONE); + err = cap_capable(subj_cred, userns, cap, CAP_OPT_NONE); if (!err) - err = aa_capable(label, cap, CAP_OPT_NONE); + err = aa_capable(subj_cred, label, cap, CAP_OPT_NONE); return err; } /** * aa_policy_view_capable - check if viewing policy in at @ns is allowed + * @subj_cred: cred of subject * @label: label that is trying to view policy in ns * @ns: namespace being viewed by @label (may be NULL if @label's ns) * @@ -785,9 +787,10 @@ static int policy_ns_capable(struct aa_label *label, * If @ns is NULL then the namespace being viewed is assumed to be the * tasks current namespace. */ -bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns) +bool aa_policy_view_capable(const struct cred *subj_cred, + struct aa_label *label, struct aa_ns *ns) { - struct user_namespace *user_ns = current_user_ns(); + struct user_namespace *user_ns = subj_cred->user_ns; struct aa_ns *view_ns = labels_view(label); bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) || in_egroup_p(make_kgid(user_ns, 0)); @@ -804,15 +807,17 @@ bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns) return response; } -bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns) +bool aa_policy_admin_capable(const struct cred *subj_cred, + struct aa_label *label, struct aa_ns *ns) { - struct user_namespace *user_ns = current_user_ns(); - bool capable = policy_ns_capable(label, user_ns, CAP_MAC_ADMIN) == 0; + struct user_namespace *user_ns = subj_cred->user_ns; + bool capable = policy_ns_capable(subj_cred, label, user_ns, + CAP_MAC_ADMIN) == 0; AA_DEBUG("cap_mac_admin? %d\n", capable); AA_DEBUG("policy locked? %d\n", aa_g_lock_policy); - return aa_policy_view_capable(label, ns) && capable && + return aa_policy_view_capable(subj_cred, label, ns) && capable && !aa_g_lock_policy; } @@ -822,7 +827,7 @@ bool aa_current_policy_view_capable(struct aa_ns *ns) bool res; label = __begin_current_label_crit_section(); - res = aa_policy_view_capable(label, ns); + res = aa_policy_view_capable(current_cred(), label, ns); __end_current_label_crit_section(label); return res; @@ -834,7 +839,7 @@ bool aa_current_policy_admin_capable(struct aa_ns *ns) bool res; label = __begin_current_label_crit_section(); - res = aa_policy_admin_capable(label, ns); + res = aa_policy_admin_capable(current_cred(), label, ns); __end_current_label_crit_section(label); return res; @@ -842,13 +847,15 @@ bool aa_current_policy_admin_capable(struct aa_ns *ns) /** * aa_may_manage_policy - can the current task manage policy + * @subj_cred; subjects cred * @label: label to check if it can manage policy * @ns: namespace being managed by @label (may be NULL if @label's ns) * @mask: contains the policy manipulation operation being done * * Returns: 0 if the task is allowed to manipulate policy else error */ -int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask) +int aa_may_manage_policy(const struct cred *subj_cred, struct aa_label *label, + struct aa_ns *ns, u32 mask) { const char *op; @@ -864,7 +871,7 @@ int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask) return audit_policy(label, op, NULL, NULL, "policy_locked", -EACCES); - if (!aa_policy_admin_capable(label, ns)) + if (!aa_policy_admin_capable(subj_cred, label, ns)) return audit_policy(label, op, NULL, NULL, "not policy admin", -EACCES); diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index 73ba26c646a5..dcc94c3153d5 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -43,6 +43,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) /** * audit_resource - audit setting resource limit + * @subj_cred: cred setting the resource * @profile: profile being enforced (NOT NULL) * @resource: rlimit being auditing * @value: value being set @@ -52,13 +53,15 @@ static void audit_cb(struct audit_buffer *ab, void *va) * * Returns: 0 or ad->error else other error code on failure */ -static int audit_resource(struct aa_profile *profile, unsigned int resource, +static int audit_resource(const struct cred *subj_cred, + struct aa_profile *profile, unsigned int resource, unsigned long value, struct aa_label *peer, const char *info, int error) { DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_RLIMITS, OP_SETRLIMIT); + ad.subj_cred = subj_cred; ad.rlim.rlim = resource; ad.rlim.max = value; ad.peer = peer; @@ -82,7 +85,8 @@ int aa_map_resource(int resource) return rlim_map[resource]; } -static int profile_setrlimit(struct aa_profile *profile, unsigned int resource, +static int profile_setrlimit(const struct cred *subj_cred, + struct aa_profile *profile, unsigned int resource, struct rlimit *new_rlim) { struct aa_ruleset *rules = list_first_entry(&profile->rules, @@ -92,12 +96,13 @@ static int profile_setrlimit(struct aa_profile *profile, unsigned int resource, if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max > rules->rlimits.limits[resource].rlim_max) e = -EACCES; - return audit_resource(profile, resource, new_rlim->rlim_max, NULL, NULL, - e); + return audit_resource(subj_cred, profile, resource, new_rlim->rlim_max, + NULL, NULL, e); } /** * aa_task_setrlimit - test permission to set an rlimit + * @subj_cred: cred setting the limit * @label: label confining the task (NOT NULL) * @task: task the resource is being set on * @resource: the resource being set @@ -107,7 +112,8 @@ static int profile_setrlimit(struct aa_profile *profile, unsigned int resource, * * Returns: 0 or error code if setting resource failed */ -int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, +int aa_task_setrlimit(const struct cred *subj_cred, struct aa_label *label, + struct task_struct *task, unsigned int resource, struct rlimit *new_rlim) { struct aa_profile *profile; @@ -126,14 +132,15 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, */ if (label != peer && - aa_capable(label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0) + aa_capable(subj_cred, label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0) error = fn_for_each(label, profile, - audit_resource(profile, resource, + audit_resource(subj_cred, profile, resource, new_rlim->rlim_max, peer, "cap_sys_resource", -EACCES)); else error = fn_for_each_confined(label, profile, - profile_setrlimit(profile, resource, new_rlim)); + profile_setrlimit(subj_cred, profile, resource, + new_rlim)); aa_put_label(peer); return error; diff --git a/security/apparmor/task.c b/security/apparmor/task.c index 552442844ff8..1a7c9d02e31d 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c @@ -223,14 +223,16 @@ static void audit_ptrace_cb(struct audit_buffer *ab, void *va) /* assumes check for RULE_MEDIATES is already done */ /* TODO: conditionals */ -static int profile_ptrace_perm(struct aa_profile *profile, - struct aa_label *peer, u32 request, - struct apparmor_audit_data *ad) +static int profile_ptrace_perm(const struct cred *cred, + struct aa_profile *profile, + struct aa_label *peer, u32 request, + struct apparmor_audit_data *ad) { struct aa_ruleset *rules = list_first_entry(&profile->rules, typeof(*rules), list); struct aa_perms perms = { }; + ad->subj_cred = cred; ad->peer = peer; aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request, &perms); @@ -238,7 +240,8 @@ static int profile_ptrace_perm(struct aa_profile *profile, 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 apparmor_audit_data *ad) { @@ -246,10 +249,11 @@ static int profile_tracee_perm(struct aa_profile *tracee, !ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE)) return 0; - return profile_ptrace_perm(tracee, tracer, request, ad); + 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 apparmor_audit_data *ad) { @@ -257,7 +261,7 @@ static int profile_tracer_perm(struct aa_profile *tracer, return 0; if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE)) - return profile_ptrace_perm(tracer, tracee, request, ad); + return profile_ptrace_perm(cred, tracer, tracee, request, ad); /* profile uses the old style capability check for ptrace */ if (&tracer->label == tracee) @@ -266,8 +270,8 @@ static int profile_tracer_perm(struct aa_profile *tracer, ad->subj_label = &tracer->label; ad->peer = tracee; ad->request = 0; - ad->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, - CAP_OPT_NONE); + ad->error = aa_capable(cred, &tracer->label, CAP_SYS_PTRACE, + CAP_OPT_NONE); return aa_audit(AUDIT_APPARMOR_AUTO, tracer, ad, audit_ptrace_cb); } @@ -280,7 +284,8 @@ static int profile_tracer_perm(struct aa_profile *tracer, * * Returns: %0 else error code if permission denied or error */ -int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, +int aa_may_ptrace(const struct cred *tracer_cred, struct aa_label *tracer, + const struct cred *tracee_cred, struct aa_label *tracee, u32 request) { struct aa_profile *profile; @@ -288,6 +293,8 @@ int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_PTRACE, OP_PTRACE); return xcheck_labels(tracer, tracee, profile, - profile_tracer_perm(profile, tracee, request, &sa), - profile_tracee_perm(profile, tracer, xrequest, &sa)); + profile_tracer_perm(tracer_cred, profile, tracee, + request, &sa), + profile_tracee_perm(tracee_cred, profile, tracer, + xrequest, &sa)); } -- cgit From 98b824ff8984fd523fc264fbb13208098ab09da3 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 28 Apr 2023 05:32:52 -0700 Subject: apparmor: refcount the pdb With the move to permission tables the dfa is no longer a stand alone entity when used, needing a minimum of a permission table. However it still could be shared among different pdbs each using a different permission table. Instead of duping the permission table when sharing a pdb, add a refcount to the pdb so it can be easily shared. Reviewed-by: Georgia Garcia Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 18 +++---- security/apparmor/domain.c | 60 ++++++++++----------- security/apparmor/file.c | 12 ++--- security/apparmor/include/lib.h | 2 + security/apparmor/include/match.h | 6 --- security/apparmor/include/policy.h | 49 ++++++++++++----- security/apparmor/ipc.c | 4 +- security/apparmor/label.c | 18 +++---- security/apparmor/lib.c | 4 +- security/apparmor/lsm.c | 63 ++++++++++++++++++++++ security/apparmor/match.c | 44 --------------- security/apparmor/mount.c | 20 +++---- security/apparmor/net.c | 4 +- security/apparmor/policy.c | 58 +++++++++++++------- security/apparmor/policy_unpack.c | 108 +++++++++++++++++-------------------- 15 files changed, 260 insertions(+), 210 deletions(-) (limited to 'security/apparmor/net.c') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index f20d923944e4..0bba46ccdb71 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -619,23 +619,23 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms, if (profile_unconfined(profile)) return; - if (rules->file.dfa && *match_str == AA_CLASS_FILE) { - state = aa_dfa_match_len(rules->file.dfa, - rules->file.start[AA_CLASS_FILE], + if (rules->file->dfa && *match_str == AA_CLASS_FILE) { + state = aa_dfa_match_len(rules->file->dfa, + rules->file->start[AA_CLASS_FILE], match_str + 1, match_len - 1); if (state) { struct path_cond cond = { }; - tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); + tmp = *(aa_lookup_fperms(rules->file, state, &cond)); } - } else if (rules->policy.dfa) { + } else if (rules->policy->dfa) { if (!RULE_MEDIATES(rules, *match_str)) return; /* no change to current perms */ - state = aa_dfa_match_len(rules->policy.dfa, - rules->policy.start[0], + state = aa_dfa_match_len(rules->policy->dfa, + rules->policy->start[0], match_str, match_len); if (state) - tmp = *aa_lookup_perms(&rules->policy, state); + tmp = *aa_lookup_perms(rules->policy, state); } aa_apply_modes_to_perms(profile, &tmp); aa_perms_accum_raw(perms, &tmp); @@ -1096,7 +1096,7 @@ static int seq_profile_attach_show(struct seq_file *seq, void *v) struct aa_profile *profile = labels_profile(label); if (profile->attach.xmatch_str) seq_printf(seq, "%s\n", profile->attach.xmatch_str); - else if (profile->attach.xmatch.dfa) + else if (profile->attach.xmatch->dfa) seq_puts(seq, "\n"); else seq_printf(seq, "%s\n", profile->base.name); diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index d95292a23bcf..87dfa0e40398 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -77,7 +77,7 @@ out: /**** TODO: dedup to aa_label_match - needs perm and dfa, merging * specifically this is an exact copy of aa_label_match except * aa_compute_perms is replaced with aa_compute_fperms - * and policy.dfa with file.dfa + * and policy->dfa with file->dfa ****/ /* match a profile and its associated ns component if needed * Assumes visibility test has already been done. @@ -93,16 +93,16 @@ static inline aa_state_t match_component(struct aa_profile *profile, const char *ns_name; if (stack) - state = aa_dfa_match(rules->file.dfa, state, "&"); + state = aa_dfa_match(rules->file->dfa, state, "&"); if (profile->ns == tp->ns) - return aa_dfa_match(rules->file.dfa, state, tp->base.hname); + return aa_dfa_match(rules->file->dfa, state, tp->base.hname); /* try matching with namespace name and then profile */ ns_name = aa_ns_name(profile->ns, tp->ns, true); - state = aa_dfa_match_len(rules->file.dfa, state, ":", 1); - state = aa_dfa_match(rules->file.dfa, state, ns_name); - state = aa_dfa_match_len(rules->file.dfa, state, ":", 1); - return aa_dfa_match(rules->file.dfa, state, tp->base.hname); + state = aa_dfa_match_len(rules->file->dfa, state, ":", 1); + state = aa_dfa_match(rules->file->dfa, state, ns_name); + state = aa_dfa_match_len(rules->file->dfa, state, ":", 1); + return aa_dfa_match(rules->file->dfa, state, tp->base.hname); } /** @@ -150,12 +150,12 @@ next: label_for_each_cont(i, label, tp) { if (!aa_ns_visible(profile->ns, tp->ns, subns)) continue; - state = aa_dfa_match(rules->file.dfa, state, "//&"); + state = aa_dfa_match(rules->file->dfa, state, "//&"); state = match_component(profile, tp, false, state); if (!state) goto fail; } - *perms = *(aa_lookup_fperms(&(rules->file), state, &cond)); + *perms = *(aa_lookup_fperms(rules->file, state, &cond)); aa_apply_modes_to_perms(profile, perms); if ((perms->allow & request) != request) return -EACCES; @@ -210,7 +210,7 @@ static int label_components_match(struct aa_profile *profile, return 0; next: - tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); + tmp = *(aa_lookup_fperms(rules->file, state, &cond)); aa_apply_modes_to_perms(profile, &tmp); aa_perms_accum(perms, &tmp); label_for_each_cont(i, label, tp) { @@ -219,7 +219,7 @@ next: state = match_component(profile, tp, stack, start); if (!state) goto fail; - tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); + tmp = *(aa_lookup_fperms(rules->file, state, &cond)); aa_apply_modes_to_perms(profile, &tmp); aa_perms_accum(perms, &tmp); } @@ -317,7 +317,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm, might_sleep(); /* transition from exec match to xattr set */ - state = aa_dfa_outofband_transition(attach->xmatch.dfa, state); + state = aa_dfa_outofband_transition(attach->xmatch->dfa, state); d = bprm->file->f_path.dentry; for (i = 0; i < attach->xattr_count; i++) { @@ -331,20 +331,20 @@ static int aa_xattrs_match(const struct linux_binprm *bprm, * that not present xattr can be distinguished from a 0 * length value or rule that matches any value */ - state = aa_dfa_null_transition(attach->xmatch.dfa, + state = aa_dfa_null_transition(attach->xmatch->dfa, state); /* Check xattr value */ - state = aa_dfa_match_len(attach->xmatch.dfa, state, + state = aa_dfa_match_len(attach->xmatch->dfa, state, value, size); - index = ACCEPT_TABLE(attach->xmatch.dfa)[state]; - perm = attach->xmatch.perms[index].allow; + index = ACCEPT_TABLE(attach->xmatch->dfa)[state]; + perm = attach->xmatch->perms[index].allow; if (!(perm & MAY_EXEC)) { ret = -EINVAL; goto out; } } /* transition to next element */ - state = aa_dfa_outofband_transition(attach->xmatch.dfa, state); + state = aa_dfa_outofband_transition(attach->xmatch->dfa, state); if (size < 0) { /* * No xattr match, so verify if transition to @@ -413,16 +413,16 @@ restart: * as another profile, signal a conflict and refuse to * match. */ - if (attach->xmatch.dfa) { + if (attach->xmatch->dfa) { unsigned int count; aa_state_t state; u32 index, perm; - state = aa_dfa_leftmatch(attach->xmatch.dfa, - attach->xmatch.start[AA_CLASS_XMATCH], + state = aa_dfa_leftmatch(attach->xmatch->dfa, + attach->xmatch->start[AA_CLASS_XMATCH], name, &count); - index = ACCEPT_TABLE(attach->xmatch.dfa)[state]; - perm = attach->xmatch.perms[index].allow; + index = ACCEPT_TABLE(attach->xmatch->dfa)[state]; + perm = attach->xmatch->perms[index].allow; /* any accepting state means a valid match. */ if (perm & MAY_EXEC) { int ret = 0; @@ -525,7 +525,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex, /* TODO: move lookup parsing to unpack time so this is a straight * index into the resultant label */ - for (*name = rules->file.trans.table[index]; !label && *name; + for (*name = rules->file->trans.table[index]; !label && *name; *name = next_name(xtype, *name)) { if (xindex & AA_X_CHILD) { struct aa_profile *new_profile; @@ -579,7 +579,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile, break; case AA_X_TABLE: /* TODO: fix when perm mapping done at unload */ - stack = rules->file.trans.table[xindex & AA_X_INDEX_MASK]; + stack = rules->file->trans.table[xindex & AA_X_INDEX_MASK]; if (*stack != '&') { /* released by caller */ new = x_table_lookup(profile, xindex, lookupname); @@ -638,7 +638,7 @@ static struct aa_label *profile_transition(const struct cred *subj_cred, typeof(*rules), list); struct aa_label *new = NULL; const char *info = NULL, *name = NULL, *target = NULL; - aa_state_t state = rules->file.start[AA_CLASS_FILE]; + aa_state_t state = rules->file->start[AA_CLASS_FILE]; struct aa_perms perms = {}; bool nonewprivs = false; int error = 0; @@ -672,7 +672,7 @@ static struct aa_label *profile_transition(const struct cred *subj_cred, } /* find exec permissions for name */ - state = aa_str_perms(&(rules->file), state, name, cond, &perms); + state = aa_str_perms(rules->file, state, name, cond, &perms); if (perms.allow & MAY_EXEC) { /* exec permission determine how to transition */ new = x_to_label(profile, bprm, name, perms.xindex, &target, @@ -738,7 +738,7 @@ static int profile_onexec(const struct cred *subj_cred, { struct aa_ruleset *rules = list_first_entry(&profile->rules, typeof(*rules), list); - aa_state_t state = rules->file.start[AA_CLASS_FILE]; + aa_state_t state = rules->file->start[AA_CLASS_FILE]; struct aa_perms perms = {}; const char *xname = NULL, *info = "change_profile onexec"; int error = -EACCES; @@ -771,7 +771,7 @@ static int profile_onexec(const struct cred *subj_cred, } /* find exec permissions for name */ - state = aa_str_perms(&(rules->file), state, xname, cond, &perms); + state = aa_str_perms(rules->file, state, xname, cond, &perms); if (!(perms.allow & AA_MAY_ONEXEC)) { info = "no change_onexec valid for executable"; goto audit; @@ -780,7 +780,7 @@ static int profile_onexec(const struct cred *subj_cred, * onexec permission is linked to exec with a standard pairing * exec\0change_profile */ - state = aa_dfa_null_transition(rules->file.dfa, state); + state = aa_dfa_null_transition(rules->file->dfa, state); error = change_profile_perms(profile, onexec, stack, AA_MAY_ONEXEC, state, &perms); if (error) { @@ -1300,7 +1300,7 @@ static int change_profile_perms_wrapper(const char *op, const char *name, if (!error) error = change_profile_perms(profile, target, stack, request, - rules->file.start[AA_CLASS_FILE], + rules->file->start[AA_CLASS_FILE], perms); if (error) error = aa_audit_file(subj_cred, profile, perms, op, request, diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 48afcef45694..c03eb7c19f16 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -236,7 +236,7 @@ static int __aa_path_perm(const char *op, const struct cred *subj_cred, if (profile_unconfined(profile)) return 0; - aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE], + aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE], name, cond, perms); if (request & ~perms->allow) e = -EACCES; @@ -353,16 +353,16 @@ static int profile_path_link(const struct cred *subj_cred, error = -EACCES; /* aa_str_perms - handles the case of the dfa being NULL */ - state = aa_str_perms(&(rules->file), - rules->file.start[AA_CLASS_FILE], lname, + state = aa_str_perms(rules->file, + rules->file->start[AA_CLASS_FILE], lname, cond, &lperms); if (!(lperms.allow & AA_MAY_LINK)) goto audit; /* test to see if target can be paired with link */ - state = aa_dfa_null_transition(rules->file.dfa, state); - aa_str_perms(&(rules->file), state, tname, cond, &perms); + state = aa_dfa_null_transition(rules->file->dfa, state); + aa_str_perms(rules->file, state, tname, cond, &perms); /* force audit/quiet masks for link are stored in the second entry * in the link pair. @@ -384,7 +384,7 @@ static int profile_path_link(const struct cred *subj_cred, /* Do link perm subset test requiring allowed permission on link are * a subset of the allowed permissions on target. */ - aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE], + aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE], tname, cond, &perms); /* AA_MAY_LINK is not considered in the subset test */ diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 73c8a32c6861..d7a894b1031f 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -16,6 +16,8 @@ #include "match.h" +extern struct aa_dfa *stacksplitdfa; + /* * DEBUG remains global (no per profile flag) since it is mostly used in sysctl * which is not related to profile accesses. diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index 58fbf67139b9..4bb0405c9190 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -102,9 +102,6 @@ struct aa_dfa { struct table_header *tables[YYTD_ID_TSIZE]; }; -extern struct aa_dfa *nulldfa; -extern struct aa_dfa *stacksplitdfa; - #define byte_to_byte(X) (X) #define UNPACK_ARRAY(TABLE, BLOB, LEN, TTYPE, BTYPE, NTOHX) \ @@ -122,9 +119,6 @@ static inline size_t table_size(size_t len, size_t el_size) return ALIGN(sizeof(struct table_header) + len * el_size, 8); } -int aa_setup_dfa_engine(void); -void aa_teardown_dfa_engine(void); - #define aa_state_t unsigned int struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags); diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 5572447d7c37..e69c91619a7c 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -74,12 +74,14 @@ enum profile_mode { /* struct aa_policydb - match engine for a policy + * count: refcount for the pdb * dfa: dfa pattern match * perms: table of permissions * strs: table of strings, index by x * start: set of start states for the different classes of data */ struct aa_policydb { + struct kref count; struct aa_dfa *dfa; struct { struct aa_perms *perms; @@ -89,13 +91,36 @@ struct aa_policydb { aa_state_t start[AA_CLASS_LAST + 1]; }; -static inline void aa_destroy_policydb(struct aa_policydb *policy) +extern struct aa_policydb *nullpdb; + +struct aa_policydb *aa_alloc_pdb(gfp_t gfp); +void aa_pdb_free_kref(struct kref *kref); + +/** + * aa_get_pdb - increment refcount on @pdb + * @pdb: policydb (MAYBE NULL) + * + * Returns: pointer to @pdb if @pdb is NULL will return NULL + * Requires: @pdb must be held with valid refcount when called + */ +static inline struct aa_policydb *aa_get_pdb(struct aa_policydb *pdb) { - aa_put_dfa(policy->dfa); - if (policy->perms) - kvfree(policy->perms); - aa_free_str_table(&policy->trans); + if (pdb) + kref_get(&(pdb->count)); + return pdb; +} + +/** + * aa_put_pdb - put a pdb refcount + * @pdb: pdb to put refcount (MAYBE NULL) + * + * Requires: if @pdb != NULL that a valid refcount be held + */ +static inline void aa_put_pdb(struct aa_policydb *pdb) +{ + if (pdb) + kref_put(&pdb->count, aa_pdb_free_kref); } static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy, @@ -139,8 +164,8 @@ struct aa_ruleset { int size; /* TODO: merge policy and file */ - struct aa_policydb policy; - struct aa_policydb file; + struct aa_policydb *policy; + struct aa_policydb *file; struct aa_caps caps; struct aa_rlimit rlimits; @@ -159,7 +184,7 @@ struct aa_ruleset { */ struct aa_attachment { const char *xmatch_str; - struct aa_policydb xmatch; + struct aa_policydb *xmatch; unsigned int xmatch_len; int xattr_count; char **xattrs; @@ -267,10 +292,10 @@ static inline aa_state_t RULE_MEDIATES(struct aa_ruleset *rules, unsigned char class) { if (class <= AA_CLASS_LAST) - return rules->policy.start[class]; + return rules->policy->start[class]; else - return aa_dfa_match_len(rules->policy.dfa, - rules->policy.start[0], &class, 1); + return aa_dfa_match_len(rules->policy->dfa, + rules->policy->start[0], &class, 1); } static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF) @@ -280,7 +305,7 @@ static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF) if (!state) return DFA_NOMATCH; - return aa_dfa_match_len(rules->policy.dfa, state, (char *) &be_af, 2); + return aa_dfa_match_len(rules->policy->dfa, state, (char *) &be_af, 2); } static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head, diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index c0d0dbd7b4c4..0cdf4340b02d 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -92,8 +92,8 @@ static int profile_signal_perm(const struct cred *cred, ad->subj_cred = cred; ad->peer = peer; /* TODO: secondary cache check */ - state = aa_dfa_next(rules->policy.dfa, - rules->policy.start[AA_CLASS_SIGNAL], + state = aa_dfa_next(rules->policy->dfa, + rules->policy->start[AA_CLASS_SIGNAL], ad->signal); aa_label_match(profile, rules, peer, state, false, request, &perms); aa_apply_modes_to_perms(profile, &perms); diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 8a74e89b05f4..c71e4615dd46 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -1270,14 +1270,14 @@ static inline aa_state_t match_component(struct aa_profile *profile, const char *ns_name; if (profile->ns == tp->ns) - return aa_dfa_match(rules->policy.dfa, state, tp->base.hname); + return aa_dfa_match(rules->policy->dfa, state, tp->base.hname); /* try matching with namespace name and then profile */ ns_name = aa_ns_name(profile->ns, tp->ns, true); - state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1); - state = aa_dfa_match(rules->policy.dfa, state, ns_name); - state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1); - return aa_dfa_match(rules->policy.dfa, state, tp->base.hname); + state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1); + state = aa_dfa_match(rules->policy->dfa, state, ns_name); + state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1); + return aa_dfa_match(rules->policy->dfa, state, tp->base.hname); } /** @@ -1323,12 +1323,12 @@ next: label_for_each_cont(i, label, tp) { if (!aa_ns_visible(profile->ns, tp->ns, subns)) continue; - state = aa_dfa_match(rules->policy.dfa, state, "//&"); + state = aa_dfa_match(rules->policy->dfa, state, "//&"); state = match_component(profile, rules, tp, state); if (!state) goto fail; } - *perms = *aa_lookup_perms(&rules->policy, state); + *perms = *aa_lookup_perms(rules->policy, state); aa_apply_modes_to_perms(profile, perms); if ((perms->allow & request) != request) return -EACCES; @@ -1381,7 +1381,7 @@ static int label_components_match(struct aa_profile *profile, return 0; next: - tmp = *aa_lookup_perms(&rules->policy, state); + tmp = *aa_lookup_perms(rules->policy, state); aa_apply_modes_to_perms(profile, &tmp); aa_perms_accum(perms, &tmp); label_for_each_cont(i, label, tp) { @@ -1390,7 +1390,7 @@ next: state = match_component(profile, rules, tp, start); if (!state) goto fail; - tmp = *aa_lookup_perms(&rules->policy, state); + tmp = *aa_lookup_perms(rules->policy, state); aa_apply_modes_to_perms(profile, &tmp); aa_perms_accum(perms, &tmp); } diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index c87bccafff44..4c198d273f09 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -341,8 +341,8 @@ void aa_profile_match_label(struct aa_profile *profile, /* TODO: doesn't yet handle extended types */ aa_state_t state; - state = aa_dfa_next(rules->policy.dfa, - rules->policy.start[AA_CLASS_LABEL], + state = aa_dfa_next(rules->policy->dfa, + rules->policy->start[AA_CLASS_LABEL], type); aa_label_match(profile, rules, label, state, false, request, perms); } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 9e31a932a644..bcfe8b9cb4c1 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1887,6 +1887,69 @@ static int __init apparmor_nf_ip_init(void) __initcall(apparmor_nf_ip_init); #endif +static char nulldfa_src[] = { + #include "nulldfa.in" +}; +struct aa_dfa *nulldfa; + +static char stacksplitdfa_src[] = { + #include "stacksplitdfa.in" +}; +struct aa_dfa *stacksplitdfa; +struct aa_policydb *nullpdb; + +static int __init aa_setup_dfa_engine(void) +{ + int error = -ENOMEM; + + nullpdb = aa_alloc_pdb(GFP_KERNEL); + if (!nullpdb) + return -ENOMEM; + + nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src), + TO_ACCEPT1_FLAG(YYTD_DATA32) | + TO_ACCEPT2_FLAG(YYTD_DATA32)); + if (IS_ERR(nulldfa)) { + error = PTR_ERR(nulldfa); + goto fail; + } + nullpdb->dfa = aa_get_dfa(nulldfa); + nullpdb->perms = kcalloc(2, sizeof(struct aa_perms), GFP_KERNEL); + if (!nullpdb->perms) + goto fail; + nullpdb->size = 2; + + stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src, + sizeof(stacksplitdfa_src), + TO_ACCEPT1_FLAG(YYTD_DATA32) | + TO_ACCEPT2_FLAG(YYTD_DATA32)); + if (IS_ERR(stacksplitdfa)) { + error = PTR_ERR(stacksplitdfa); + goto fail; + } + + return 0; + +fail: + aa_put_pdb(nullpdb); + aa_put_dfa(nulldfa); + nullpdb = NULL; + nulldfa = NULL; + stacksplitdfa = NULL; + + return error; +} + +static void __init aa_teardown_dfa_engine(void) +{ + aa_put_dfa(stacksplitdfa); + aa_put_dfa(nulldfa); + aa_put_pdb(nullpdb); + nullpdb = NULL; + stacksplitdfa = NULL; + nulldfa = NULL; +} + static int __init apparmor_init(void) { int error; diff --git a/security/apparmor/match.c b/security/apparmor/match.c index 7bdcca2aed7d..517d77d3c34c 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c @@ -21,50 +21,6 @@ #define base_idx(X) ((X) & 0xffffff) -static char nulldfa_src[] = { - #include "nulldfa.in" -}; -struct aa_dfa *nulldfa; - -static char stacksplitdfa_src[] = { - #include "stacksplitdfa.in" -}; -struct aa_dfa *stacksplitdfa; - -int __init aa_setup_dfa_engine(void) -{ - int error; - - nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src), - TO_ACCEPT1_FLAG(YYTD_DATA32) | - TO_ACCEPT2_FLAG(YYTD_DATA32)); - if (IS_ERR(nulldfa)) { - error = PTR_ERR(nulldfa); - nulldfa = NULL; - return error; - } - - stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src, - sizeof(stacksplitdfa_src), - TO_ACCEPT1_FLAG(YYTD_DATA32) | - TO_ACCEPT2_FLAG(YYTD_DATA32)); - if (IS_ERR(stacksplitdfa)) { - aa_put_dfa(nulldfa); - nulldfa = NULL; - error = PTR_ERR(stacksplitdfa); - stacksplitdfa = NULL; - return error; - } - - return 0; -} - -void __init aa_teardown_dfa_engine(void) -{ - aa_put_dfa(stacksplitdfa); - aa_put_dfa(nulldfa); -} - /** * unpack_table - unpack a dfa table (one of accept, default, base, next check) * @blob: data to unpack (NOT NULL) diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 2bb77aacc49a..3455dd4b1f99 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -332,8 +332,8 @@ static int match_mnt_path_str(const struct cred *subj_cred, } error = -EACCES; - pos = do_match_mnt(&rules->policy, - rules->policy.start[AA_CLASS_MOUNT], + pos = do_match_mnt(rules->policy, + rules->policy->start[AA_CLASS_MOUNT], mntpnt, devname, type, flags, data, binary, &perms); if (pos) { info = mnt_info_table[pos]; @@ -606,10 +606,10 @@ static int profile_umount(const struct cred *subj_cred, if (error) goto audit; - state = aa_dfa_match(rules->policy.dfa, - rules->policy.start[AA_CLASS_MOUNT], + state = aa_dfa_match(rules->policy->dfa, + rules->policy->start[AA_CLASS_MOUNT], name); - perms = *aa_lookup_perms(&rules->policy, state); + perms = *aa_lookup_perms(rules->policy, state); if (AA_MAY_UMOUNT & ~perms.allow) error = -EACCES; @@ -680,12 +680,12 @@ static struct aa_label *build_pivotroot(const struct cred *subj_cred, goto audit; error = -EACCES; - state = aa_dfa_match(rules->policy.dfa, - rules->policy.start[AA_CLASS_MOUNT], + state = aa_dfa_match(rules->policy->dfa, + rules->policy->start[AA_CLASS_MOUNT], new_name); - state = aa_dfa_null_transition(rules->policy.dfa, state); - state = aa_dfa_match(rules->policy.dfa, state, old_name); - perms = *aa_lookup_perms(&rules->policy, state); + state = aa_dfa_null_transition(rules->policy->dfa, state); + state = aa_dfa_match(rules->policy->dfa, state, old_name); + perms = *aa_lookup_perms(rules->policy, state); if (AA_MAY_PIVOTROOT & perms.allow) error = 0; diff --git a/security/apparmor/net.c b/security/apparmor/net.c index 704c171232ab..87e934b2b548 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c @@ -127,9 +127,9 @@ int aa_profile_af_perm(struct aa_profile *profile, buffer[0] = cpu_to_be16(family); buffer[1] = cpu_to_be16((u16) type); - state = aa_dfa_match_len(rules->policy.dfa, state, (char *) &buffer, + state = aa_dfa_match_len(rules->policy->dfa, state, (char *) &buffer, 4); - perms = *aa_lookup_perms(&rules->policy, state); + perms = *aa_lookup_perms(rules->policy, state); aa_apply_modes_to_perms(profile, &perms); return aa_check_perms(profile, &perms, request, ad, audit_net_cb); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 6f80e1207d24..0b36bd6a6f33 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -98,6 +98,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) + * @kr: kref callback for freeing of a dfa (NOT NULL) + */ +void aa_pdb_free_kref(struct kref *kref) +{ + struct aa_policydb *pdb = container_of(kref, struct aa_policydb, count); + + aa_free_pdb(pdb); +} + + +struct aa_policydb *aa_alloc_pdb(gfp_t gfp) +{ + struct aa_policydb *pdb = kzalloc(sizeof(struct aa_policydb), gfp); + + if (!pdb) + return NULL; + + kref_init(&pdb->count); + + return pdb; +} + + /** * __add_profile - add a profiles to list and label tree * @list: list to add it to (NOT NULL) @@ -200,15 +235,15 @@ static void free_attachment(struct aa_attachment *attach) for (i = 0; i < attach->xattr_count; i++) kfree_sensitive(attach->xattrs[i]); kfree_sensitive(attach->xattrs); - aa_destroy_policydb(&attach->xmatch); + aa_put_pdb(attach->xmatch); } static void free_ruleset(struct aa_ruleset *rules) { int i; - aa_destroy_policydb(&rules->file); - aa_destroy_policydb(&rules->policy); + aa_put_pdb(rules->file); + aa_put_pdb(rules->policy); aa_free_cap_rules(&rules->caps); aa_free_rlimit_rules(&rules->rlimits); @@ -590,16 +625,8 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name, /* TODO: ideally we should inherit abi from parent */ profile->label.flags |= FLAG_NULL; rules = list_first_entry(&profile->rules, typeof(*rules), list); - rules->file.dfa = aa_get_dfa(nulldfa); - rules->file.perms = kcalloc(2, sizeof(struct aa_perms), gfp); - 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); - if (!rules->policy.perms) - goto fail; - rules->policy.size = 2; + rules->file = aa_get_pdb(nullpdb); + rules->policy = aa_get_pdb(nullpdb); if (parent) { profile->path_flags = parent->path_flags; @@ -610,11 +637,6 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name, } return profile; - -fail: - aa_free_profile(profile); - - return NULL; } /** diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 1eb98d6994e8..3fad34b68fdc 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -703,24 +703,29 @@ fail_reset: return -EPROTO; } -static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy, +static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy, bool required_dfa, bool required_trans, const char **info) { + struct aa_policydb *pdb; void *pos = e->pos; int i, flags, error = -EPROTO; ssize_t size; - size = unpack_perms_table(e, &policy->perms); + pdb = aa_alloc_pdb(GFP_KERNEL); + if (!pdb) + return -ENOMEM; + + size = unpack_perms_table(e, &pdb->perms); if (size < 0) { error = size; - policy->perms = NULL; + pdb->perms = NULL; *info = "failed to unpack - perms"; goto fail; } - policy->size = size; + pdb->size = size; - if (policy->perms) { + if (pdb->perms) { /* perms table present accept is index */ flags = TO_ACCEPT1_FLAG(YYTD_DATA32); } else { @@ -729,13 +734,13 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy, TO_ACCEPT2_FLAG(YYTD_DATA32); } - policy->dfa = unpack_dfa(e, flags); - if (IS_ERR(policy->dfa)) { - error = PTR_ERR(policy->dfa); - policy->dfa = NULL; + pdb->dfa = unpack_dfa(e, flags); + if (IS_ERR(pdb->dfa)) { + error = PTR_ERR(pdb->dfa); + pdb->dfa = NULL; *info = "failed to unpack - dfa"; goto fail; - } else if (!policy->dfa) { + } else if (!pdb->dfa) { if (required_dfa) { *info = "missing required dfa"; goto fail; @@ -749,18 +754,18 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy, * sadly start was given different names for file and policydb * but since it is optional we can try both */ - if (!aa_unpack_u32(e, &policy->start[0], "start")) + if (!aa_unpack_u32(e, &pdb->start[0], "start")) /* default start state */ - policy->start[0] = DFA_START; - if (!aa_unpack_u32(e, &policy->start[AA_CLASS_FILE], "dfa_start")) { + pdb->start[0] = DFA_START; + if (!aa_unpack_u32(e, &pdb->start[AA_CLASS_FILE], "dfa_start")) { /* default start state for xmatch and file dfa */ - policy->start[AA_CLASS_FILE] = DFA_START; + pdb->start[AA_CLASS_FILE] = DFA_START; } /* setup class index */ for (i = AA_CLASS_FILE + 1; i <= AA_CLASS_LAST; i++) { - policy->start[i] = aa_dfa_next(policy->dfa, policy->start[0], + pdb->start[i] = aa_dfa_next(pdb->dfa, pdb->start[0], i); } - if (!unpack_trans_table(e, &policy->trans) && required_trans) { + if (!unpack_trans_table(e, &pdb->trans) && required_trans) { *info = "failed to unpack profile transition table"; goto fail; } @@ -768,9 +773,11 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy, /* TODO: move compat mapping here, requires dfa merging first */ /* TODO: move verify here, it has to be done after compat mappings */ out: + *policy = pdb; return 0; fail: + aa_put_pdb(pdb); e->pos = pos; return error; } @@ -854,15 +861,15 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) } /* neither xmatch_len not xmatch_perms are optional if xmatch is set */ - if (profile->attach.xmatch.dfa) { + if (profile->attach.xmatch->dfa) { if (!aa_unpack_u32(e, &tmp, NULL)) { info = "missing xmatch len"; goto fail; } profile->attach.xmatch_len = tmp; - profile->attach.xmatch.start[AA_CLASS_XMATCH] = DFA_START; - if (!profile->attach.xmatch.perms) { - error = aa_compat_map_xmatch(&profile->attach.xmatch); + profile->attach.xmatch->start[AA_CLASS_XMATCH] = DFA_START; + if (!profile->attach.xmatch->perms) { + error = aa_compat_map_xmatch(profile->attach.xmatch); if (error) { info = "failed to convert xmatch permission table"; goto fail; @@ -979,16 +986,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) if (error) goto fail; /* Fixup: drop when we get rid of start array */ - if (aa_dfa_next(rules->policy.dfa, rules->policy.start[0], + if (aa_dfa_next(rules->policy->dfa, rules->policy->start[0], AA_CLASS_FILE)) - rules->policy.start[AA_CLASS_FILE] = - aa_dfa_next(rules->policy.dfa, - rules->policy.start[0], + rules->policy->start[AA_CLASS_FILE] = + aa_dfa_next(rules->policy->dfa, + rules->policy->start[0], AA_CLASS_FILE); if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) goto fail; - if (!rules->policy.perms) { - error = aa_compat_map_policy(&rules->policy, + if (!rules->policy->perms) { + error = aa_compat_map_policy(rules->policy, e->version); if (error) { info = "failed to remap policydb permission table"; @@ -996,44 +1003,25 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) } } } else { - rules->policy.dfa = aa_get_dfa(nulldfa); - rules->policy.perms = kcalloc(2, sizeof(struct aa_perms), - GFP_KERNEL); - if (!rules->policy.perms) - goto fail; - rules->policy.size = 2; + rules->policy = aa_get_pdb(nullpdb); } /* get file rules */ error = unpack_pdb(e, &rules->file, false, true, &info); if (error) { goto fail; - } else if (rules->file.dfa) { - if (!rules->file.perms) { - error = aa_compat_map_file(&rules->file); + } else if (rules->file->dfa) { + if (!rules->file->perms) { + error = aa_compat_map_file(rules->file); if (error) { info = "failed to remap file permission table"; goto fail; } } - } else if (rules->policy.dfa && - rules->policy.start[AA_CLASS_FILE]) { - rules->file.dfa = aa_get_dfa(rules->policy.dfa); - rules->file.start[AA_CLASS_FILE] = rules->policy.start[AA_CLASS_FILE]; - rules->file.perms = kcalloc(rules->policy.size, - sizeof(struct aa_perms), - GFP_KERNEL); - if (!rules->file.perms) - goto fail; - memcpy(rules->file.perms, rules->policy.perms, - rules->policy.size * sizeof(struct aa_perms)); - rules->file.size = rules->policy.size; + } else if (rules->policy->dfa && + rules->policy->start[AA_CLASS_FILE]) { + rules->file = aa_get_pdb(rules->policy); } else { - rules->file.dfa = aa_get_dfa(nulldfa); - rules->file.perms = kcalloc(2, sizeof(struct aa_perms), - GFP_KERNEL); - if (!rules->file.perms) - goto fail; - rules->file.size = 2; + rules->file = aa_get_pdb(nullpdb); } error = -EPROTO; if (aa_unpack_nameX(e, AA_STRUCT, "data")) { @@ -1240,32 +1228,32 @@ static int verify_profile(struct aa_profile *profile) if (!rules) return 0; - if (rules->file.dfa && !verify_dfa_accept_index(rules->file.dfa, - rules->file.size)) { + if (rules->file->dfa && !verify_dfa_accept_index(rules->file->dfa, + rules->file->size)) { audit_iface(profile, NULL, NULL, "Unpack: file Invalid named transition", NULL, -EPROTO); return -EPROTO; } - if (rules->policy.dfa && - !verify_dfa_accept_index(rules->policy.dfa, rules->policy.size)) { + if (rules->policy->dfa && + !verify_dfa_accept_index(rules->policy->dfa, rules->policy->size)) { audit_iface(profile, NULL, NULL, "Unpack: policy Invalid named transition", NULL, -EPROTO); return -EPROTO; } - if (!verify_perms(&rules->file)) { + if (!verify_perms(rules->file)) { audit_iface(profile, NULL, NULL, "Unpack: Invalid perm index", NULL, -EPROTO); return -EPROTO; } - if (!verify_perms(&rules->policy)) { + if (!verify_perms(rules->policy)) { audit_iface(profile, NULL, NULL, "Unpack: Invalid perm index", NULL, -EPROTO); return -EPROTO; } - if (!verify_perms(&profile->attach.xmatch)) { + if (!verify_perms(profile->attach.xmatch)) { audit_iface(profile, NULL, NULL, "Unpack: Invalid perm index", NULL, -EPROTO); return -EPROTO; -- cgit