diff options
author | John Johansen <john.johansen@canonical.com> | 2017-06-09 08:14:28 -0700 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2017-06-10 17:11:38 -0700 |
commit | 637f688dc3dc304a89f441d76f49a0e35bc49c08 (patch) | |
tree | 78fee8a7aa212140c4c6b6a9b722bbba61802cab /security/apparmor/lib.c | |
parent | f1bd904175e8190ce14aedee37e207ab51fe3b30 (diff) |
apparmor: switch from profiles to using labels on contexts
Begin the actual switch to using domain labels by storing them on
the context and converting the label to a singular profile where
possible.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor/lib.c')
-rw-r--r-- | security/apparmor/lib.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 0ceecdbb4658..08ca26bcca77 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -247,6 +247,32 @@ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, } /** + * aa_audit_perms_cb - generic callback fn for auditing perms + * @ab: audit buffer (NOT NULL) + * @va: audit struct to audit values of (NOT NULL) + */ +static void aa_audit_perms_cb(struct audit_buffer *ab, void *va) +{ + struct common_audit_data *sa = va; + + if (aad(sa)->request) { + audit_log_format(ab, " requested_mask="); + aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs, + PERMS_CHRS_MASK, aa_file_perm_names, + PERMS_NAMES_MASK); + } + if (aad(sa)->denied) { + audit_log_format(ab, "denied_mask="); + aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs, + PERMS_CHRS_MASK, aa_file_perm_names, + PERMS_NAMES_MASK); + } + audit_log_format(ab, " peer="); + aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, + FLAGS_NONE, GFP_ATOMIC); +} + +/** * aa_apply_modes_to_perms - apply namespace and profile flags to perms * @profile: that perms where computed from * @perms: perms to apply mode modifiers to @@ -310,6 +336,143 @@ void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, } /** + * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms + * @accum - perms struct to accumulate into + * @addend - perms struct to add to @accum + */ +void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend) +{ + accum->deny |= addend->deny; + accum->allow &= addend->allow & ~addend->deny; + accum->audit |= addend->audit & addend->allow; + accum->quiet &= addend->quiet & ~addend->allow; + accum->kill |= addend->kill & ~addend->allow; + accum->stop |= addend->stop & ~addend->allow; + accum->complain |= addend->complain & ~addend->allow & ~addend->deny; + accum->cond |= addend->cond & ~addend->allow & ~addend->deny; + accum->hide &= addend->hide & ~addend->allow; + accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny; +} + +/** + * aa_perms_accum - accumulate perms, masking off overlapping perms + * @accum - perms struct to accumulate into + * @addend - perms struct to add to @accum + */ +void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend) +{ + accum->deny |= addend->deny; + accum->allow &= addend->allow & ~accum->deny; + accum->audit |= addend->audit & accum->allow; + accum->quiet &= addend->quiet & ~accum->allow; + accum->kill |= addend->kill & ~accum->allow; + accum->stop |= addend->stop & ~accum->allow; + accum->complain |= addend->complain & ~accum->allow & ~accum->deny; + accum->cond |= addend->cond & ~accum->allow & ~accum->deny; + accum->hide &= addend->hide & ~accum->allow; + accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny; +} + +void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label, + int type, u32 request, struct aa_perms *perms) +{ + /* TODO: doesn't yet handle extended types */ + unsigned int state; + + state = aa_dfa_next(profile->policy.dfa, + profile->policy.start[AA_CLASS_LABEL], + type); + aa_label_match(profile, label, state, false, request, perms); +} + + +/* currently unused */ +int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, + u32 request, int type, u32 *deny, + struct common_audit_data *sa) +{ + struct aa_perms perms; + + aad(sa)->label = &profile->label; + aad(sa)->peer = &target->label; + aad(sa)->request = request; + + aa_profile_match_label(profile, &target->label, type, request, &perms); + aa_apply_modes_to_perms(profile, &perms); + *deny |= request & perms.deny; + return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb); +} + +/** + * aa_check_perms - do audit mode selection based on perms set + * @profile: profile being checked + * @perms: perms computed for the request + * @request: requested perms + * @deny: Returns: explicit deny set + * @sa: initialized audit structure (MAY BE NULL if not auditing) + * @cb: callback fn for tpye specific fields (MAY BE NULL) + * + * Returns: 0 if permission else error code + * + * Note: profile audit modes need to be set before calling by setting the + * perm masks appropriately. + * + * If not auditing then complain mode is not enabled and the + * error code will indicate whether there was an explicit deny + * with a positive value. + */ +int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, + u32 request, struct common_audit_data *sa, + void (*cb)(struct audit_buffer *, void *)) +{ + int type, error; + bool stop = false; + u32 denied = request & (~perms->allow | perms->deny); + + if (likely(!denied)) { + /* mask off perms that are not being force audited */ + request &= perms->audit; + if (!request || !sa) + return 0; + + type = AUDIT_APPARMOR_AUDIT; + error = 0; + } else { + error = -EACCES; + + if (denied & perms->kill) + type = AUDIT_APPARMOR_KILL; + else if (denied == (denied & perms->complain)) + type = AUDIT_APPARMOR_ALLOWED; + else + type = AUDIT_APPARMOR_DENIED; + + if (denied & perms->stop) + stop = true; + if (denied == (denied & perms->hide)) + error = -ENOENT; + + denied &= ~perms->quiet; + if (!sa || !denied) + return error; + } + + if (sa) { + aad(sa)->label = &profile->label; + aad(sa)->request = request; + aad(sa)->denied = denied; + aad(sa)->error = error; + aa_audit_msg(type, sa, cb); + } + + if (type == AUDIT_APPARMOR_ALLOWED) + error = 0; + + return error; +} + + +/** * aa_policy_init - initialize a policy structure * @policy: policy to initialize (NOT NULL) * @prefix: prefix name if any is required. (MAYBE NULL) |