1*b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 20ed3b28aSJohn Johansen /* 30ed3b28aSJohn Johansen * AppArmor security module 40ed3b28aSJohn Johansen * 50ed3b28aSJohn Johansen * This file contains AppArmor ipc mediation 60ed3b28aSJohn Johansen * 70ed3b28aSJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 8b2d09ae4SJohn Johansen * Copyright 2009-2017 Canonical Ltd. 90ed3b28aSJohn Johansen */ 100ed3b28aSJohn Johansen 110ed3b28aSJohn Johansen #include <linux/gfp.h> 120ed3b28aSJohn Johansen #include <linux/ptrace.h> 130ed3b28aSJohn Johansen 140ed3b28aSJohn Johansen #include "include/audit.h" 150ed3b28aSJohn Johansen #include "include/capability.h" 16d8889d49SJohn Johansen #include "include/cred.h" 170ed3b28aSJohn Johansen #include "include/policy.h" 1833f8bf58SJames Morris #include "include/ipc.h" 19cd1dbf76SJohn Johansen #include "include/sig_names.h" 200ed3b28aSJohn Johansen 21290f458aSJohn Johansen /** 22290f458aSJohn Johansen * audit_ptrace_mask - convert mask to permission string 23290f458aSJohn Johansen * @buffer: buffer to write string to (NOT NULL) 24290f458aSJohn Johansen * @mask: permission mask to convert 25290f458aSJohn Johansen */ 26290f458aSJohn Johansen static void audit_ptrace_mask(struct audit_buffer *ab, u32 mask) 27290f458aSJohn Johansen { 28290f458aSJohn Johansen switch (mask) { 29290f458aSJohn Johansen case MAY_READ: 30290f458aSJohn Johansen audit_log_string(ab, "read"); 31290f458aSJohn Johansen break; 32290f458aSJohn Johansen case MAY_WRITE: 33290f458aSJohn Johansen audit_log_string(ab, "trace"); 34290f458aSJohn Johansen break; 35290f458aSJohn Johansen case AA_MAY_BE_READ: 36290f458aSJohn Johansen audit_log_string(ab, "readby"); 37290f458aSJohn Johansen break; 38290f458aSJohn Johansen case AA_MAY_BE_TRACED: 39290f458aSJohn Johansen audit_log_string(ab, "tracedby"); 40290f458aSJohn Johansen break; 41290f458aSJohn Johansen } 42290f458aSJohn Johansen } 43290f458aSJohn Johansen 440ed3b28aSJohn Johansen /* call back to audit ptrace fields */ 45637f688dSJohn Johansen static void audit_ptrace_cb(struct audit_buffer *ab, void *va) 460ed3b28aSJohn Johansen { 470ed3b28aSJohn Johansen struct common_audit_data *sa = va; 48b2d09ae4SJohn Johansen 49290f458aSJohn Johansen if (aad(sa)->request & AA_PTRACE_PERM_MASK) { 50290f458aSJohn Johansen audit_log_format(ab, " requested_mask="); 51290f458aSJohn Johansen audit_ptrace_mask(ab, aad(sa)->request); 52290f458aSJohn Johansen 53290f458aSJohn Johansen if (aad(sa)->denied & AA_PTRACE_PERM_MASK) { 54290f458aSJohn Johansen audit_log_format(ab, " denied_mask="); 55290f458aSJohn Johansen audit_ptrace_mask(ab, aad(sa)->denied); 56290f458aSJohn Johansen } 57290f458aSJohn Johansen } 58ef88a7acSJohn Johansen audit_log_format(ab, " peer="); 59637f688dSJohn Johansen aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, 60637f688dSJohn Johansen FLAGS_NONE, GFP_ATOMIC); 610ed3b28aSJohn Johansen } 620ed3b28aSJohn Johansen 630dda0b3fSJohn Johansen /* assumes check for PROFILE_MEDIATES is already done */ 64290f458aSJohn Johansen /* TODO: conditionals */ 65290f458aSJohn Johansen static int profile_ptrace_perm(struct aa_profile *profile, 660dda0b3fSJohn Johansen struct aa_label *peer, u32 request, 67290f458aSJohn Johansen struct common_audit_data *sa) 68290f458aSJohn Johansen { 69290f458aSJohn Johansen struct aa_perms perms = { }; 70290f458aSJohn Johansen 710dda0b3fSJohn Johansen aad(sa)->peer = peer; 720dda0b3fSJohn Johansen aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, 73290f458aSJohn Johansen &perms); 74290f458aSJohn Johansen aa_apply_modes_to_perms(profile, &perms); 75290f458aSJohn Johansen return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); 76290f458aSJohn Johansen } 77290f458aSJohn Johansen 780dda0b3fSJohn Johansen static int profile_tracee_perm(struct aa_profile *tracee, 790dda0b3fSJohn Johansen struct aa_label *tracer, u32 request, 80b2d09ae4SJohn Johansen struct common_audit_data *sa) 810ed3b28aSJohn Johansen { 820dda0b3fSJohn Johansen if (profile_unconfined(tracee) || unconfined(tracer) || 830dda0b3fSJohn Johansen !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) 840dda0b3fSJohn Johansen return 0; 850dda0b3fSJohn Johansen 860dda0b3fSJohn Johansen return profile_ptrace_perm(tracee, tracer, request, sa); 870dda0b3fSJohn Johansen } 880dda0b3fSJohn Johansen 890dda0b3fSJohn Johansen static int profile_tracer_perm(struct aa_profile *tracer, 900dda0b3fSJohn Johansen struct aa_label *tracee, u32 request, 910dda0b3fSJohn Johansen struct common_audit_data *sa) 920dda0b3fSJohn Johansen { 930dda0b3fSJohn Johansen if (profile_unconfined(tracer)) 940dda0b3fSJohn Johansen return 0; 950dda0b3fSJohn Johansen 96290f458aSJohn Johansen if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) 970dda0b3fSJohn Johansen return profile_ptrace_perm(tracer, tracee, request, sa); 980dda0b3fSJohn Johansen 990dda0b3fSJohn Johansen /* profile uses the old style capability check for ptrace */ 1000dda0b3fSJohn Johansen if (&tracer->label == tracee) 101b2d09ae4SJohn Johansen return 0; 1020ed3b28aSJohn Johansen 103b2d09ae4SJohn Johansen aad(sa)->label = &tracer->label; 1040dda0b3fSJohn Johansen aad(sa)->peer = tracee; 105b2d09ae4SJohn Johansen aad(sa)->request = 0; 106c1a85a00SMicah Morton aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 107c1a85a00SMicah Morton CAP_OPT_NONE); 108ef88a7acSJohn Johansen 109b2d09ae4SJohn Johansen return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); 1100ed3b28aSJohn Johansen } 1110ed3b28aSJohn Johansen 1120ed3b28aSJohn Johansen /** 1130ed3b28aSJohn Johansen * aa_may_ptrace - test if tracer task can trace the tracee 114b2d09ae4SJohn Johansen * @tracer: label of the task doing the tracing (NOT NULL) 115b2d09ae4SJohn Johansen * @tracee: task label to be traced 116b2d09ae4SJohn Johansen * @request: permission request 1170ed3b28aSJohn Johansen * 1180ed3b28aSJohn Johansen * Returns: %0 else error code if permission denied or error 1190ed3b28aSJohn Johansen */ 120b2d09ae4SJohn Johansen int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, 121b2d09ae4SJohn Johansen u32 request) 1220ed3b28aSJohn Johansen { 1230dda0b3fSJohn Johansen struct aa_profile *profile; 1240dda0b3fSJohn Johansen u32 xrequest = request << PTRACE_PERM_SHIFT; 125b2d09ae4SJohn Johansen DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); 1260ed3b28aSJohn Johansen 1270dda0b3fSJohn Johansen return xcheck_labels(tracer, tracee, profile, 1280dda0b3fSJohn Johansen profile_tracer_perm(profile, tracee, request, &sa), 1290dda0b3fSJohn Johansen profile_tracee_perm(profile, tracer, xrequest, &sa)); 1300ed3b28aSJohn Johansen } 1310ed3b28aSJohn Johansen 1320ed3b28aSJohn Johansen 133cd1dbf76SJohn Johansen static inline int map_signal_num(int sig) 134cd1dbf76SJohn Johansen { 135cd1dbf76SJohn Johansen if (sig > SIGRTMAX) 136cd1dbf76SJohn Johansen return SIGUNKNOWN; 137cd1dbf76SJohn Johansen else if (sig >= SIGRTMIN) 1383acfd5f5SJohn Johansen return sig - SIGRTMIN + SIGRT_BASE; 139f7dc4c9aSJohn Johansen else if (sig < MAXMAPPED_SIG) 140cd1dbf76SJohn Johansen return sig_map[sig]; 141cd1dbf76SJohn Johansen return SIGUNKNOWN; 142cd1dbf76SJohn Johansen } 143cd1dbf76SJohn Johansen 144cd1dbf76SJohn Johansen /** 145cd1dbf76SJohn Johansen * audit_file_mask - convert mask to permission string 146cd1dbf76SJohn Johansen * @buffer: buffer to write string to (NOT NULL) 147cd1dbf76SJohn Johansen * @mask: permission mask to convert 148cd1dbf76SJohn Johansen */ 149cd1dbf76SJohn Johansen static void audit_signal_mask(struct audit_buffer *ab, u32 mask) 150cd1dbf76SJohn Johansen { 151cd1dbf76SJohn Johansen if (mask & MAY_READ) 152cd1dbf76SJohn Johansen audit_log_string(ab, "receive"); 153cd1dbf76SJohn Johansen if (mask & MAY_WRITE) 154cd1dbf76SJohn Johansen audit_log_string(ab, "send"); 155cd1dbf76SJohn Johansen } 156cd1dbf76SJohn Johansen 157cd1dbf76SJohn Johansen /** 158cd1dbf76SJohn Johansen * audit_cb - call back for signal specific audit fields 159cd1dbf76SJohn Johansen * @ab: audit_buffer (NOT NULL) 160cd1dbf76SJohn Johansen * @va: audit struct to audit values of (NOT NULL) 161cd1dbf76SJohn Johansen */ 162cd1dbf76SJohn Johansen static void audit_signal_cb(struct audit_buffer *ab, void *va) 163cd1dbf76SJohn Johansen { 164cd1dbf76SJohn Johansen struct common_audit_data *sa = va; 165cd1dbf76SJohn Johansen 166cd1dbf76SJohn Johansen if (aad(sa)->request & AA_SIGNAL_PERM_MASK) { 167cd1dbf76SJohn Johansen audit_log_format(ab, " requested_mask="); 168cd1dbf76SJohn Johansen audit_signal_mask(ab, aad(sa)->request); 169cd1dbf76SJohn Johansen if (aad(sa)->denied & AA_SIGNAL_PERM_MASK) { 170cd1dbf76SJohn Johansen audit_log_format(ab, " denied_mask="); 171cd1dbf76SJohn Johansen audit_signal_mask(ab, aad(sa)->denied); 172cd1dbf76SJohn Johansen } 173cd1dbf76SJohn Johansen } 1743acfd5f5SJohn Johansen if (aad(sa)->signal == SIGUNKNOWN) 1753acfd5f5SJohn Johansen audit_log_format(ab, "signal=unknown(%d)", 1763acfd5f5SJohn Johansen aad(sa)->unmappedsig); 1773acfd5f5SJohn Johansen else if (aad(sa)->signal < MAXMAPPED_SIGNAME) 178cd1dbf76SJohn Johansen audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]); 179cd1dbf76SJohn Johansen else 180cd1dbf76SJohn Johansen audit_log_format(ab, " signal=rtmin+%d", 1813acfd5f5SJohn Johansen aad(sa)->signal - SIGRT_BASE); 182cd1dbf76SJohn Johansen audit_log_format(ab, " peer="); 183cd1dbf76SJohn Johansen aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, 184cd1dbf76SJohn Johansen FLAGS_NONE, GFP_ATOMIC); 185cd1dbf76SJohn Johansen } 186cd1dbf76SJohn Johansen 187cd1dbf76SJohn Johansen static int profile_signal_perm(struct aa_profile *profile, 1883dc6b1ceSJohn Johansen struct aa_label *peer, u32 request, 189cd1dbf76SJohn Johansen struct common_audit_data *sa) 190cd1dbf76SJohn Johansen { 191cd1dbf76SJohn Johansen struct aa_perms perms; 1923dc6b1ceSJohn Johansen unsigned int state; 193cd1dbf76SJohn Johansen 194cd1dbf76SJohn Johansen if (profile_unconfined(profile) || 195cd1dbf76SJohn Johansen !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL)) 196cd1dbf76SJohn Johansen return 0; 197cd1dbf76SJohn Johansen 1983dc6b1ceSJohn Johansen aad(sa)->peer = peer; 1993dc6b1ceSJohn Johansen /* TODO: secondary cache check <profile, profile, perm> */ 2003dc6b1ceSJohn Johansen state = aa_dfa_next(profile->policy.dfa, 2013dc6b1ceSJohn Johansen profile->policy.start[AA_CLASS_SIGNAL], 2023dc6b1ceSJohn Johansen aad(sa)->signal); 2033dc6b1ceSJohn Johansen aa_label_match(profile, peer, state, false, request, &perms); 204cd1dbf76SJohn Johansen aa_apply_modes_to_perms(profile, &perms); 205cd1dbf76SJohn Johansen return aa_check_perms(profile, &perms, request, sa, audit_signal_cb); 206cd1dbf76SJohn Johansen } 207cd1dbf76SJohn Johansen 208cd1dbf76SJohn Johansen int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig) 209cd1dbf76SJohn Johansen { 2103dc6b1ceSJohn Johansen struct aa_profile *profile; 211cd1dbf76SJohn Johansen DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SIGNAL); 212cd1dbf76SJohn Johansen 213cd1dbf76SJohn Johansen aad(&sa)->signal = map_signal_num(sig); 2143acfd5f5SJohn Johansen aad(&sa)->unmappedsig = sig; 2153dc6b1ceSJohn Johansen return xcheck_labels(sender, target, profile, 2163dc6b1ceSJohn Johansen profile_signal_perm(profile, target, MAY_WRITE, &sa), 2173dc6b1ceSJohn Johansen profile_signal_perm(profile, sender, MAY_READ, &sa)); 218cd1dbf76SJohn Johansen } 219