|
12 | 12 | * should return to the previous cred if it has not been modified. |
13 | 13 | */ |
14 | 14 |
|
| 15 | +#include <linux/gfp.h> |
| 16 | +#include <linux/ptrace.h> |
| 17 | + |
| 18 | +#include "include/audit.h" |
15 | 19 | #include "include/cred.h" |
| 20 | +#include "include/policy.h" |
16 | 21 | #include "include/task.h" |
17 | 22 |
|
18 | 23 | /** |
@@ -177,3 +182,112 @@ int aa_restore_previous_label(u64 token) |
177 | 182 |
|
178 | 183 | return 0; |
179 | 184 | } |
| 185 | + |
| 186 | +/** |
| 187 | + * audit_ptrace_mask - convert mask to permission string |
| 188 | + * @mask: permission mask to convert |
| 189 | + * |
| 190 | + * Returns: pointer to static string |
| 191 | + */ |
| 192 | +static const char *audit_ptrace_mask(u32 mask) |
| 193 | +{ |
| 194 | + switch (mask) { |
| 195 | + case MAY_READ: |
| 196 | + return "read"; |
| 197 | + case MAY_WRITE: |
| 198 | + return "trace"; |
| 199 | + case AA_MAY_BE_READ: |
| 200 | + return "readby"; |
| 201 | + case AA_MAY_BE_TRACED: |
| 202 | + return "tracedby"; |
| 203 | + } |
| 204 | + return ""; |
| 205 | +} |
| 206 | + |
| 207 | +/* call back to audit ptrace fields */ |
| 208 | +static void audit_ptrace_cb(struct audit_buffer *ab, void *va) |
| 209 | +{ |
| 210 | + struct common_audit_data *sa = va; |
| 211 | + |
| 212 | + if (aad(sa)->request & AA_PTRACE_PERM_MASK) { |
| 213 | + audit_log_format(ab, " requested_mask=\"%s\"", |
| 214 | + audit_ptrace_mask(aad(sa)->request)); |
| 215 | + |
| 216 | + if (aad(sa)->denied & AA_PTRACE_PERM_MASK) { |
| 217 | + audit_log_format(ab, " denied_mask=\"%s\"", |
| 218 | + audit_ptrace_mask(aad(sa)->denied)); |
| 219 | + } |
| 220 | + } |
| 221 | + audit_log_format(ab, " peer="); |
| 222 | + aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, |
| 223 | + FLAGS_NONE, GFP_ATOMIC); |
| 224 | +} |
| 225 | + |
| 226 | +/* assumes check for PROFILE_MEDIATES is already done */ |
| 227 | +/* TODO: conditionals */ |
| 228 | +static int profile_ptrace_perm(struct aa_profile *profile, |
| 229 | + struct aa_label *peer, u32 request, |
| 230 | + struct common_audit_data *sa) |
| 231 | +{ |
| 232 | + struct aa_perms perms = { }; |
| 233 | + |
| 234 | + aad(sa)->peer = peer; |
| 235 | + aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, |
| 236 | + &perms); |
| 237 | + aa_apply_modes_to_perms(profile, &perms); |
| 238 | + return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); |
| 239 | +} |
| 240 | + |
| 241 | +static int profile_tracee_perm(struct aa_profile *tracee, |
| 242 | + struct aa_label *tracer, u32 request, |
| 243 | + struct common_audit_data *sa) |
| 244 | +{ |
| 245 | + if (profile_unconfined(tracee) || unconfined(tracer) || |
| 246 | + !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) |
| 247 | + return 0; |
| 248 | + |
| 249 | + return profile_ptrace_perm(tracee, tracer, request, sa); |
| 250 | +} |
| 251 | + |
| 252 | +static int profile_tracer_perm(struct aa_profile *tracer, |
| 253 | + struct aa_label *tracee, u32 request, |
| 254 | + struct common_audit_data *sa) |
| 255 | +{ |
| 256 | + if (profile_unconfined(tracer)) |
| 257 | + return 0; |
| 258 | + |
| 259 | + if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) |
| 260 | + return profile_ptrace_perm(tracer, tracee, request, sa); |
| 261 | + |
| 262 | + /* profile uses the old style capability check for ptrace */ |
| 263 | + if (&tracer->label == tracee) |
| 264 | + return 0; |
| 265 | + |
| 266 | + aad(sa)->label = &tracer->label; |
| 267 | + aad(sa)->peer = tracee; |
| 268 | + aad(sa)->request = 0; |
| 269 | + aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, |
| 270 | + CAP_OPT_NONE); |
| 271 | + |
| 272 | + return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); |
| 273 | +} |
| 274 | + |
| 275 | +/** |
| 276 | + * aa_may_ptrace - test if tracer task can trace the tracee |
| 277 | + * @tracer: label of the task doing the tracing (NOT NULL) |
| 278 | + * @tracee: task label to be traced |
| 279 | + * @request: permission request |
| 280 | + * |
| 281 | + * Returns: %0 else error code if permission denied or error |
| 282 | + */ |
| 283 | +int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, |
| 284 | + u32 request) |
| 285 | +{ |
| 286 | + struct aa_profile *profile; |
| 287 | + u32 xrequest = request << PTRACE_PERM_SHIFT; |
| 288 | + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); |
| 289 | + |
| 290 | + return xcheck_labels(tracer, tracee, profile, |
| 291 | + profile_tracer_perm(profile, tracee, request, &sa), |
| 292 | + profile_tracee_perm(profile, tracer, xrequest, &sa)); |
| 293 | +} |
0 commit comments