int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, unsigned int mode) { /* */ struct aa_profile *tracer_p; /* */ const struct cred *cred = get_task_cred(tracer); int error = 0; tracer_p = aa_cred_profile(cred); if (!unconfined(tracer_p)) { /* */ const struct cred *lcred = get_task_cred(tracee); struct aa_profile *tracee_p = aa_cred_profile(lcred); error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode); error = aa_audit_ptrace(tracer_p, tracee_p, error); put_cred(lcred); } put_cred(cred); return error; }
/** * 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) { /* * 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_profile *tracer_p; /* cred released below */ const struct cred *cred = get_task_cred(tracer); int error = 0; tracer_p = aa_cred_profile(cred); if (!unconfined(tracer_p)) { /* lcred released below */ const struct cred *lcred = get_task_cred(tracee); struct aa_profile *tracee_p = aa_cred_profile(lcred); error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode); error = aa_audit_ptrace(tracer_p, tracee_p, error); put_cred(lcred); } put_cred(cred); return error; }
/** * aa_getprocattr - Return the profile information for @profile * @profile: the profile to print profile info about (NOT NULL) * @string: Returns - string containing the profile info (NOT NULL) * * Returns: length of @string on success else error on failure * * Requires: profile != NULL * * Creates a string containing the namespace_name://profile_name for * @profile. * * Returns: size of string placed in @string else error code on failure */ int aa_getprocattr(struct aa_profile *profile, char **string) { char *str; int len = 0, mode_len = 0, ns_len = 0, name_len; const char *mode_str = aa_profile_mode_names[profile->mode]; const char *ns_name = NULL; struct aa_namespace *ns = profile->ns; struct aa_namespace *current_ns = __aa_current_profile()->ns; char *s; if (!aa_ns_visible(current_ns, ns)) return -EACCES; ns_name = aa_ns_name(current_ns, ns); ns_len = strlen(ns_name); /* if the visible ns_name is > 0 increase size for : :// seperator */ if (ns_len) ns_len += 4; /* unconfined profiles don't have a mode string appended */ if (!unconfined(profile)) mode_len = strlen(mode_str) + 3; /* + 3 for _() */ name_len = strlen(profile->base.hname); len = mode_len + ns_len + name_len + 1; /* + 1 for \n */ s = str = kmalloc(len + 1, GFP_KERNEL); /* + 1 \0 */ if (!str) return -ENOMEM; if (ns_len) { /* skip over prefix current_ns->base.hname and separating // */ sprintf(s, ":%s://", ns_name); s += ns_len; } if (unconfined(profile)) /* mode string not being appended */ sprintf(s, "%s\n", profile->base.hname); else sprintf(s, "%s (%s)\n", profile->base.hname, mode_str); *string = str; /* NOTE: len does not include \0 of string, not saved as part of file */ return len; }
static int profile_tracee_perm(struct aa_profile *tracee, struct aa_label *tracer, u32 request, struct common_audit_data *sa) { if (profile_unconfined(tracee) || unconfined(tracer) || !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) return 0; return profile_ptrace_perm(tracee, tracer, request, sa); }
/** * 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 */ int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer, struct aa_profile *tracee, unsigned int mode) { /* TODO: currently only based on capability, not extended ptrace * rules, * Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH */ if (unconfined(tracer) || tracer == tracee) return 0; /* log this capability request */ return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1); }
int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer, struct aa_profile *tracee, unsigned int mode) { /* */ if (unconfined(tracer) || tracer == tracee) return 0; /* */ return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1); }
static int aa_label_sk_perm(struct aa_label *label, int op, u32 request, struct sock *sk) { struct aa_profile *profile; AA_BUG(!label); AA_BUG(!sk); if (unconfined(label)) return 0; return fn_for_each_confined(label, profile, aa_profile_af_perm(profile, op, sk->sk_family, sk->sk_type, sk->sk_protocol, sk)); }
/** * aa_revalidate_sk - Revalidate access to a sock * @op: operation being checked * @sk: sock being revalidated (NOT NULL) * * Returns: %0 else error if permission denied */ int aa_revalidate_sk(int op, struct sock *sk) { struct aa_profile *profile; int error = 0; /* aa_revalidate_sk should not be called from interrupt context * don't mediate these calls as they are not task related */ if (in_interrupt()) return 0; profile = __aa_current_profile(); if (!unconfined(profile)) error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type, sk->sk_protocol, sk); return error; }
static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, struct sock *sk) { int error = 0; AA_BUG(!label); AA_BUG(!sk); if (!unconfined(label)) { struct aa_profile *profile; DEFINE_AUDIT_SK(sa, op, sk); error = fn_for_each_confined(label, profile, aa_profile_af_sk_perm(profile, &sa, request, sk)); } return error; }
/** * aa_audit - Log a profile based audit event to the audit subsystem * @type: audit type for the message * @profile: profile to check against (NOT NULL) * @gfp: allocation flags to use * @sa: audit event (NOT NULL) * @cb: optional callback fn for type specific fields (MAYBE NULL) * * Handle default message switching based off of audit mode flags * * Returns: error on failure */ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *)) { BUG_ON(!profile); if (type == AUDIT_APPARMOR_AUTO) { if (likely(!sa->aad->error)) { if (AUDIT_MODE(profile) != AUDIT_ALL) return 0; type = AUDIT_APPARMOR_AUDIT; } else if (COMPLAIN_MODE(profile)) type = AUDIT_APPARMOR_ALLOWED; else type = AUDIT_APPARMOR_DENIED; } if (AUDIT_MODE(profile) == AUDIT_QUIET || (type == AUDIT_APPARMOR_DENIED && AUDIT_MODE(profile) == AUDIT_QUIET)) return sa->aad->error; if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) type = AUDIT_APPARMOR_KILL; if (!unconfined(profile)) sa->aad->profile = profile; aa_audit_msg(type, sa, cb); if (sa->aad->type == AUDIT_APPARMOR_KILL) (void)send_sig_info(SIGKILL, NULL, sa->u.tsk ? sa->u.tsk : current); if (sa->aad->type == AUDIT_APPARMOR_ALLOWED) return complain_error(sa->aad->error); return sa->aad->error; }
/** * aa_audit_base - core AppArmor function. * @type: type of audit message (see include/linux/apparmor.h) * @profile: active profile for event (MAY BE NULL) * @sa: audit structure containing data to audit * @audit_cxt: audit_cxt that event is under * @cb: audit cb for this event * * Record an audit message for data is @sa, and handle deal with kill and * complain messages switches. * * Returns: 0 or sa->error on success, else error */ static int aa_audit_base(int type, struct aa_profile *profile, struct aa_audit *sa, struct audit_context *audit_cxt, void (*cb) (struct audit_buffer *, struct aa_audit *)) { struct audit_buffer *ab = NULL; struct task_struct *task = sa->task ? sa->task : current; if (profile && DO_KILL(profile) && type == AUDIT_APPARMOR_DENIED) type = AUDIT_APPARMOR_KILL; /* ab freed below in audit_log_end */ ab = audit_log_start(audit_cxt, sa->gfp_mask, type); if (!ab) { AA_ERROR("(%d) Unable to log event of type (%d)\n", -ENOMEM, type); sa->error = -ENOMEM; goto out; } if (aa_g_audit_header) { audit_log_format(ab, " type="); audit_log_string(ab, aa_audit_type[type - AUDIT_APPARMOR_AUDIT]); } if (sa->operation) { audit_log_format(ab, " operation="); audit_log_string(ab, sa->operation); } if (sa->info) { audit_log_format(ab, " info="); audit_log_string(ab, sa->info); if (sa->error) audit_log_format(ab, " error=%d", sa->error); } audit_log_format(ab, " pid=%d", task->pid); if (profile && !unconfined(profile)) { pid_t pid; rcu_read_lock(); pid = task->real_parent->pid; rcu_read_unlock(); audit_log_format(ab, " parent=%d", pid); audit_log_format(ab, " profile="); audit_log_untrustedstring(ab, profile->base.hname); if (profile->ns != root_ns) { audit_log_format(ab, " namespace="); audit_log_untrustedstring(ab, profile->ns->base.hname); } } if (cb) cb(ab, sa); audit_log_end(ab); out: if (type == AUDIT_APPARMOR_KILL) (void)send_sig_info(SIGKILL, NULL, task); return type == AUDIT_APPARMOR_ALLOWED ? 0 : sa->error; }