diff options
Diffstat (limited to 'security/apparmor/ipc.c')
| -rw-r--r-- | security/apparmor/ipc.c | 156 |
1 files changed, 80 insertions, 76 deletions
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index c51d2266587e..df5712cea685 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -1,112 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * * This file contains AppArmor ipc mediation * * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. + * Copyright 2009-2017 Canonical Ltd. */ #include <linux/gfp.h> -#include <linux/ptrace.h> #include "include/audit.h" #include "include/capability.h" -#include "include/context.h" +#include "include/cred.h" #include "include/policy.h" #include "include/ipc.h" +#include "include/sig_names.h" + -/* call back to audit ptrace fields */ -static void audit_cb(struct audit_buffer *ab, void *va) +static inline int map_signal_num(int sig) { - struct common_audit_data *sa = va; - audit_log_format(ab, " target="); - audit_log_untrustedstring(ab, sa->aad->target); + if (sig > SIGRTMAX) + return SIGUNKNOWN; + else if (sig >= SIGRTMIN) + return sig - SIGRTMIN + SIGRT_BASE; + else if (sig < MAXMAPPED_SIG) + return sig_map[sig]; + return SIGUNKNOWN; } /** - * aa_audit_ptrace - do auditing for ptrace - * @profile: profile being enforced (NOT NULL) - * @target: profile being traced (NOT NULL) - * @error: error condition + * audit_signal_mask - convert mask to permission string + * @mask: permission mask to convert * - * Returns: %0 or error code + * Returns: pointer to static string */ -static int aa_audit_ptrace(struct aa_profile *profile, - struct aa_profile *target, int error) +static const char *audit_signal_mask(u32 mask) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.op = OP_PTRACE; - aad.target = target; - aad.error = error; - - return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa, - audit_cb); + if (mask & MAY_READ) + return "receive"; + if (mask & MAY_WRITE) + return "send"; + return ""; } /** - * aa_may_ptrace - test if tracer task can trace the tracee - * @tracer_task: task who will do the tracing (NOT NULL) - * @tracer: profile of the task doing the tracing (NOT NULL) - * @tracee: task to be traced - * @mode: whether PTRACE_MODE_READ || PTRACE_MODE_ATTACH - * - * Returns: %0 else error code if permission denied or error + * audit_signal_cb() - call back for signal specific audit fields + * @ab: audit_buffer (NOT NULL) + * @va: audit struct to audit values of (NOT NULL) */ -int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer, - struct aa_profile *tracee, unsigned int mode) +static void audit_signal_cb(struct audit_buffer *ab, void *va) { - /* TODO: currently only based on capability, not extended ptrace - * rules, - * Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH - */ + struct common_audit_data *sa = va; + struct apparmor_audit_data *ad = aad(sa); - if (unconfined(tracer) || tracer == tracee) - return 0; - /* log this capability request */ - return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1); + if (ad->request & AA_SIGNAL_PERM_MASK) { + audit_log_format(ab, " requested_mask=\"%s\"", + audit_signal_mask(ad->request)); + if (ad->denied & AA_SIGNAL_PERM_MASK) { + audit_log_format(ab, " denied_mask=\"%s\"", + audit_signal_mask(ad->denied)); + } + } + if (ad->signal == SIGUNKNOWN) + audit_log_format(ab, "signal=unknown(%d)", + ad->unmappedsig); + else if (ad->signal < MAXMAPPED_SIGNAME) + audit_log_format(ab, " signal=%s", sig_names[ad->signal]); + else + audit_log_format(ab, " signal=rtmin+%d", + ad->signal - SIGRT_BASE); + audit_log_format(ab, " peer="); + aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, + FLAGS_NONE, GFP_ATOMIC); } -/** - * aa_ptrace - do ptrace permission check and auditing - * @tracer: task doing the tracing (NOT NULL) - * @tracee: task being traced (NOT NULL) - * @mode: ptrace mode either PTRACE_MODE_READ || PTRACE_MODE_ATTACH - * - * Returns: %0 else error code if permission denied or error - */ -int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, - unsigned int mode) +static int profile_signal_perm(const struct cred *cred, + struct aa_profile *profile, + struct aa_label *peer, u32 request, + struct apparmor_audit_data *ad) { - /* - * tracer can ptrace tracee when - * - tracer is unconfined || - * - tracer is in complain mode - * - tracer has rules allowing it to trace tracee currently this is: - * - confined by the same profile || - * - tracer profile has CAP_SYS_PTRACE - */ + struct aa_ruleset *rules = profile->label.rules[0]; + struct aa_perms perms; + aa_state_t state; - struct aa_profile *tracer_p = aa_get_task_profile(tracer); - int error = 0; - - if (!unconfined(tracer_p)) { - struct aa_profile *tracee_p = aa_get_task_profile(tracee); + if (profile_unconfined(profile)) + return 0; - error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode); - error = aa_audit_ptrace(tracer_p, tracee_p, error); + ad->subj_cred = cred; + ad->peer = peer; + /* TODO: secondary cache check <profile, profile, perm> */ + state = RULE_MEDIATES(rules, AA_CLASS_SIGNAL); + if (!state) + return 0; + state = aa_dfa_next(rules->policy->dfa, state, ad->signal); + aa_label_match(profile, rules, peer, state, false, request, &perms); + aa_apply_modes_to_perms(profile, &perms); + return aa_check_perms(profile, &perms, request, ad, audit_signal_cb); +} - aa_put_profile(tracee_p); - } - aa_put_profile(tracer_p); +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); - return error; + ad.signal = map_signal_num(sig); + ad.unmappedsig = sig; + return xcheck_labels(sender, target, profile, + profile_signal_perm(subj_cred, profile, target, + MAY_WRITE, &ad), + profile_signal_perm(target_cred, profile, sender, + MAY_READ, &ad)); } |
