]>
Commit | Line | Data |
---|---|---|
b886d83c | 1 | // SPDX-License-Identifier: GPL-2.0-only |
0ed3b28a JJ |
2 | /* |
3 | * AppArmor security module | |
4 | * | |
5 | * This file contains AppArmor ipc mediation | |
6 | * | |
7 | * Copyright (C) 1998-2008 Novell/SUSE | |
b2d09ae4 | 8 | * Copyright 2009-2017 Canonical Ltd. |
0ed3b28a JJ |
9 | */ |
10 | ||
11 | #include <linux/gfp.h> | |
12 | #include <linux/ptrace.h> | |
13 | ||
14 | #include "include/audit.h" | |
15 | #include "include/capability.h" | |
d8889d49 | 16 | #include "include/cred.h" |
0ed3b28a | 17 | #include "include/policy.h" |
33f8bf58 | 18 | #include "include/ipc.h" |
cd1dbf76 | 19 | #include "include/sig_names.h" |
0ed3b28a | 20 | |
290f458a JJ |
21 | /** |
22 | * audit_ptrace_mask - convert mask to permission string | |
290f458a | 23 | * @mask: permission mask to convert |
f1d9b23c RGB |
24 | * |
25 | * Returns: pointer to static string | |
290f458a | 26 | */ |
f1d9b23c | 27 | static const char *audit_ptrace_mask(u32 mask) |
290f458a JJ |
28 | { |
29 | switch (mask) { | |
30 | case MAY_READ: | |
f1d9b23c | 31 | return "read"; |
290f458a | 32 | case MAY_WRITE: |
f1d9b23c | 33 | return "trace"; |
290f458a | 34 | case AA_MAY_BE_READ: |
f1d9b23c | 35 | return "readby"; |
290f458a | 36 | case AA_MAY_BE_TRACED: |
f1d9b23c | 37 | return "tracedby"; |
290f458a | 38 | } |
f1d9b23c | 39 | return ""; |
290f458a JJ |
40 | } |
41 | ||
0ed3b28a | 42 | /* call back to audit ptrace fields */ |
637f688d | 43 | static void audit_ptrace_cb(struct audit_buffer *ab, void *va) |
0ed3b28a JJ |
44 | { |
45 | struct common_audit_data *sa = va; | |
b2d09ae4 | 46 | |
290f458a | 47 | if (aad(sa)->request & AA_PTRACE_PERM_MASK) { |
f1d9b23c RGB |
48 | audit_log_format(ab, " requested_mask=\"%s\"", |
49 | audit_ptrace_mask(aad(sa)->request)); | |
290f458a JJ |
50 | |
51 | if (aad(sa)->denied & AA_PTRACE_PERM_MASK) { | |
f1d9b23c RGB |
52 | audit_log_format(ab, " denied_mask=\"%s\"", |
53 | audit_ptrace_mask(aad(sa)->denied)); | |
290f458a JJ |
54 | } |
55 | } | |
ef88a7ac | 56 | audit_log_format(ab, " peer="); |
637f688d JJ |
57 | aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, |
58 | FLAGS_NONE, GFP_ATOMIC); | |
0ed3b28a JJ |
59 | } |
60 | ||
0dda0b3f | 61 | /* assumes check for PROFILE_MEDIATES is already done */ |
290f458a JJ |
62 | /* TODO: conditionals */ |
63 | static int profile_ptrace_perm(struct aa_profile *profile, | |
0dda0b3f JJ |
64 | struct aa_label *peer, u32 request, |
65 | struct common_audit_data *sa) | |
290f458a JJ |
66 | { |
67 | struct aa_perms perms = { }; | |
68 | ||
0dda0b3f JJ |
69 | aad(sa)->peer = peer; |
70 | aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, | |
290f458a JJ |
71 | &perms); |
72 | aa_apply_modes_to_perms(profile, &perms); | |
73 | return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); | |
74 | } | |
75 | ||
0dda0b3f JJ |
76 | static int profile_tracee_perm(struct aa_profile *tracee, |
77 | struct aa_label *tracer, u32 request, | |
78 | struct common_audit_data *sa) | |
0ed3b28a | 79 | { |
0dda0b3f JJ |
80 | if (profile_unconfined(tracee) || unconfined(tracer) || |
81 | !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) | |
82 | return 0; | |
83 | ||
84 | return profile_ptrace_perm(tracee, tracer, request, sa); | |
85 | } | |
86 | ||
87 | static int profile_tracer_perm(struct aa_profile *tracer, | |
88 | struct aa_label *tracee, u32 request, | |
89 | struct common_audit_data *sa) | |
90 | { | |
91 | if (profile_unconfined(tracer)) | |
92 | return 0; | |
93 | ||
290f458a | 94 | if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) |
0dda0b3f JJ |
95 | return profile_ptrace_perm(tracer, tracee, request, sa); |
96 | ||
97 | /* profile uses the old style capability check for ptrace */ | |
98 | if (&tracer->label == tracee) | |
b2d09ae4 | 99 | return 0; |
0ed3b28a | 100 | |
b2d09ae4 | 101 | aad(sa)->label = &tracer->label; |
0dda0b3f | 102 | aad(sa)->peer = tracee; |
b2d09ae4 | 103 | aad(sa)->request = 0; |
c1a85a00 MM |
104 | aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, |
105 | CAP_OPT_NONE); | |
ef88a7ac | 106 | |
b2d09ae4 | 107 | return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); |
0ed3b28a JJ |
108 | } |
109 | ||
110 | /** | |
111 | * aa_may_ptrace - test if tracer task can trace the tracee | |
b2d09ae4 JJ |
112 | * @tracer: label of the task doing the tracing (NOT NULL) |
113 | * @tracee: task label to be traced | |
114 | * @request: permission request | |
0ed3b28a JJ |
115 | * |
116 | * Returns: %0 else error code if permission denied or error | |
117 | */ | |
b2d09ae4 JJ |
118 | int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, |
119 | u32 request) | |
0ed3b28a | 120 | { |
0dda0b3f JJ |
121 | struct aa_profile *profile; |
122 | u32 xrequest = request << PTRACE_PERM_SHIFT; | |
b2d09ae4 | 123 | DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); |
0ed3b28a | 124 | |
0dda0b3f JJ |
125 | return xcheck_labels(tracer, tracee, profile, |
126 | profile_tracer_perm(profile, tracee, request, &sa), | |
127 | profile_tracee_perm(profile, tracer, xrequest, &sa)); | |
0ed3b28a JJ |
128 | } |
129 | ||
0ed3b28a | 130 | |
cd1dbf76 JJ |
131 | static inline int map_signal_num(int sig) |
132 | { | |
133 | if (sig > SIGRTMAX) | |
134 | return SIGUNKNOWN; | |
135 | else if (sig >= SIGRTMIN) | |
3acfd5f5 | 136 | return sig - SIGRTMIN + SIGRT_BASE; |
f7dc4c9a | 137 | else if (sig < MAXMAPPED_SIG) |
cd1dbf76 JJ |
138 | return sig_map[sig]; |
139 | return SIGUNKNOWN; | |
140 | } | |
141 | ||
142 | /** | |
f1d9b23c | 143 | * audit_signal_mask - convert mask to permission string |
cd1dbf76 | 144 | * @mask: permission mask to convert |
f1d9b23c RGB |
145 | * |
146 | * Returns: pointer to static string | |
cd1dbf76 | 147 | */ |
f1d9b23c | 148 | static const char *audit_signal_mask(u32 mask) |
cd1dbf76 JJ |
149 | { |
150 | if (mask & MAY_READ) | |
f1d9b23c | 151 | return "receive"; |
cd1dbf76 | 152 | if (mask & MAY_WRITE) |
f1d9b23c RGB |
153 | return "send"; |
154 | return ""; | |
cd1dbf76 JJ |
155 | } |
156 | ||
157 | /** | |
158 | * audit_cb - call back for signal specific audit fields | |
159 | * @ab: audit_buffer (NOT NULL) | |
160 | * @va: audit struct to audit values of (NOT NULL) | |
161 | */ | |
162 | static void audit_signal_cb(struct audit_buffer *ab, void *va) | |
163 | { | |
164 | struct common_audit_data *sa = va; | |
165 | ||
166 | if (aad(sa)->request & AA_SIGNAL_PERM_MASK) { | |
f1d9b23c RGB |
167 | audit_log_format(ab, " requested_mask=\"%s\"", |
168 | audit_signal_mask(aad(sa)->request)); | |
cd1dbf76 | 169 | if (aad(sa)->denied & AA_SIGNAL_PERM_MASK) { |
f1d9b23c RGB |
170 | audit_log_format(ab, " denied_mask=\"%s\"", |
171 | audit_signal_mask(aad(sa)->denied)); | |
cd1dbf76 JJ |
172 | } |
173 | } | |
3acfd5f5 JJ |
174 | if (aad(sa)->signal == SIGUNKNOWN) |
175 | audit_log_format(ab, "signal=unknown(%d)", | |
176 | aad(sa)->unmappedsig); | |
177 | else if (aad(sa)->signal < MAXMAPPED_SIGNAME) | |
cd1dbf76 JJ |
178 | audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]); |
179 | else | |
180 | audit_log_format(ab, " signal=rtmin+%d", | |
3acfd5f5 | 181 | aad(sa)->signal - SIGRT_BASE); |
cd1dbf76 JJ |
182 | audit_log_format(ab, " peer="); |
183 | aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, | |
184 | FLAGS_NONE, GFP_ATOMIC); | |
185 | } | |
186 | ||
cd1dbf76 | 187 | static int profile_signal_perm(struct aa_profile *profile, |
3dc6b1ce | 188 | struct aa_label *peer, u32 request, |
cd1dbf76 JJ |
189 | struct common_audit_data *sa) |
190 | { | |
191 | struct aa_perms perms; | |
3dc6b1ce | 192 | unsigned int state; |
cd1dbf76 JJ |
193 | |
194 | if (profile_unconfined(profile) || | |
195 | !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL)) | |
196 | return 0; | |
197 | ||
3dc6b1ce JJ |
198 | aad(sa)->peer = peer; |
199 | /* TODO: secondary cache check <profile, profile, perm> */ | |
200 | state = aa_dfa_next(profile->policy.dfa, | |
201 | profile->policy.start[AA_CLASS_SIGNAL], | |
202 | aad(sa)->signal); | |
203 | aa_label_match(profile, peer, state, false, request, &perms); | |
cd1dbf76 JJ |
204 | aa_apply_modes_to_perms(profile, &perms); |
205 | return aa_check_perms(profile, &perms, request, sa, audit_signal_cb); | |
206 | } | |
207 | ||
cd1dbf76 JJ |
208 | int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig) |
209 | { | |
3dc6b1ce | 210 | struct aa_profile *profile; |
cd1dbf76 JJ |
211 | DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SIGNAL); |
212 | ||
213 | aad(&sa)->signal = map_signal_num(sig); | |
3acfd5f5 | 214 | aad(&sa)->unmappedsig = sig; |
3dc6b1ce JJ |
215 | return xcheck_labels(sender, target, profile, |
216 | profile_signal_perm(profile, target, MAY_WRITE, &sa), | |
217 | profile_signal_perm(profile, sender, MAY_READ, &sa)); | |
cd1dbf76 | 218 | } |