/** * aa_apply_modes_to_perms - apply namespace and profile flags to perms * @profile: that perms where computed from * @perms: perms to apply mode modifiers to * * TODO: split into profile and ns based flags for when accumulating perms */ void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms) { switch (AUDIT_MODE(profile)) { case AUDIT_ALL: perms->audit = ALL_PERMS_MASK; /* fall through */ case AUDIT_NOQUIET: perms->quiet = 0; break; case AUDIT_QUIET: perms->audit = 0; /* fall through */ case AUDIT_QUIET_DENIED: perms->quiet = ALL_PERMS_MASK; break; } if (KILL_MODE(profile)) perms->kill = ALL_PERMS_MASK; else if (COMPLAIN_MODE(profile)) perms->complain = ALL_PERMS_MASK; /* TODO: else if (PROMPT_MODE(profile)) perms->prompt = ALL_PERMS_MASK; */ }
/** * audit_net - audit network access * @profile: profile being enforced (NOT NULL) * @op: operation being checked * @family: network family * @type: network type * @protocol: network protocol * @sk: socket auditing is being applied to * @error: error code for failure else 0 * * Returns: %0 or sa->error else other errorcode on failure */ static int audit_net(struct aa_profile *profile, int op, u16 family, int type, int protocol, struct sock *sk, int error) { int audit_type = AUDIT_APPARMOR_AUTO; DEFINE_AUDIT_NET(sa, op, sk, family, type, protocol); aad(&sa)->error = error; if (likely(!aad(&sa)->error)) { u16 audit_mask = profile->net.audit[sa.u.net->family]; if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && !(1 << aad(&sa)->net.type & audit_mask))) return 0; audit_type = AUDIT_APPARMOR_AUDIT; } else { u16 quiet_mask = profile->net.quiet[sa.u.net->family]; u16 kill_mask = 0; u16 denied = (1 << aad(&sa)->net.type); if (denied & kill_mask) audit_type = AUDIT_APPARMOR_KILL; if ((denied & quiet_mask) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error; } return aa_audit(audit_type, profile, &sa, audit_net_cb); }
/** * aa_capable - test permission to use capability * @task: task doing capability test against (NOT NULL) * @profile: profile confining @task (NOT NULL) * @cap: capability to be tested * @audit: whether an audit record should be generated * * Look up capability in profile capability set. * * Returns: 0 on success, or else an error code. */ int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap, int audit) { int error = profile_capable(profile, cap); if (!audit) { if (COMPLAIN_MODE(profile)) return complain_error(error); return error; } return audit_caps(profile, task, cap, error); }
int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, gfp_t gfp, int op, u32 request, const char *name, const char *target, uid_t ouid, const char *info, int error) { int type = AUDIT_APPARMOR_AUTO; struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; COMMON_AUDIT_DATA_INIT(&sa, NONE); sa.aad = &aad; aad.op = op, aad.fs.request = request; aad.name = name; aad.fs.target = target; aad.fs.ouid = ouid; aad.info = info; aad.error = error; if (likely(!sa.aad->error)) { u32 mask = perms->audit; if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) mask = 0xffff; /* */ sa.aad->fs.request &= mask; if (likely(!sa.aad->fs.request)) return 0; type = AUDIT_APPARMOR_AUDIT; } else { /* */ sa.aad->fs.request = sa.aad->fs.request & ~perms->allow; if (sa.aad->fs.request & perms->kill) type = AUDIT_APPARMOR_KILL; /* */ if ((sa.aad->fs.request & perms->quiet) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) sa.aad->fs.request &= ~perms->quiet; if (!sa.aad->fs.request) return COMPLAIN_MODE(profile) ? 0 : sa.aad->error; } sa.aad->fs.denied = sa.aad->fs.request & ~perms->allow; return aa_audit(type, profile, gfp, &sa, file_audit_cb); }
/** * aa_audit_file - handle the auditing of file operations * @profile: the profile being enforced (NOT NULL) * @perms: the permissions computed for the request (NOT NULL) * @gfp: allocation flags * @op: operation being mediated * @request: permissions requested * @name: name of object being mediated (MAYBE NULL) * @target: name of target (MAYBE NULL) * @ouid: object uid * @info: extra information message (MAYBE NULL) * @error: 0 if operation allowed else failure error code * * Returns: %0 or error on failure */ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, gfp_t gfp, int op, u32 request, const char *name, const char *target, kuid_t ouid, const char *info, int error) { int type = AUDIT_APPARMOR_AUTO; struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; sa.type = LSM_AUDIT_DATA_NONE; sa.aad = &aad; aad.op = op, aad.fs.request = request; aad.name = name; aad.fs.target = target; aad.fs.ouid = ouid; aad.info = info; aad.error = error; if (likely(!sa.aad->error)) { u32 mask = perms->audit; if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) mask = 0xffff; /* mask off perms that are not being force audited */ sa.aad->fs.request &= mask; if (likely(!sa.aad->fs.request)) return 0; type = AUDIT_APPARMOR_AUDIT; } else { /* only report permissions that were denied */ sa.aad->fs.request = sa.aad->fs.request & ~perms->allow; if (sa.aad->fs.request & perms->kill) type = AUDIT_APPARMOR_KILL; /* quiet known rejects, assumes quiet and kill do not overlap */ if ((sa.aad->fs.request & perms->quiet) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) sa.aad->fs.request &= ~perms->quiet; if (!sa.aad->fs.request) return COMPLAIN_MODE(profile) ? 0 : sa.aad->error; } sa.aad->fs.denied = sa.aad->fs.request & ~perms->allow; return aa_audit(type, profile, gfp, &sa, file_audit_cb); }
/** * audit_caps - audit a capability * @profile: profile confining task (NOT NULL) * @task: task capability test was performed against (NOT NULL) * @cap: capability tested * @error: error code returned by test * * Do auditing of capability and handle, audit/complain/kill modes switching * and duplicate message elimination. * * Returns: 0 or sa->error on success, error code on failure */ static int audit_caps(struct aa_profile *profile, struct task_struct *task, int cap, int error) { struct audit_cache *ent; int type = AUDIT_APPARMOR_AUTO; struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; COMMON_AUDIT_DATA_INIT(&sa, CAP); sa.aad = &aad; sa.tsk = task; sa.u.cap = cap; sa.aad->op = OP_CAPABLE; sa.aad->error = error; if (likely(!error)) { /* test if auditing is being forced */ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && !cap_raised(profile->caps.audit, cap))) return 0; type = AUDIT_APPARMOR_AUDIT; } else if (KILL_MODE(profile) || cap_raised(profile->caps.kill, cap)) { type = AUDIT_APPARMOR_KILL; } else if (cap_raised(profile->caps.quiet, cap) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) { /* quiet auditing */ return error; } /* Do simple duplicate message elimination */ ent = &get_cpu_var(audit_cache); if (profile == ent->profile && cap_raised(ent->caps, cap)) { put_cpu_var(audit_cache); if (COMPLAIN_MODE(profile)) return complain_error(error); return error; } else { aa_put_profile(ent->profile); ent->profile = aa_get_profile(profile); cap_raise(ent->caps, cap); } put_cpu_var(audit_cache); return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb); }
/** * audit_net - audit network access * @profile: profile being enforced (NOT NULL) * @op: operation being checked * @family: network family * @type: network type * @protocol: network protocol * @sk: socket auditing is being applied to * @error: error code for failure else 0 * * Returns: %0 or sa->error else other errorcode on failure */ static int audit_net(struct aa_profile *profile, int op, u16 family, int type, int protocol, struct sock *sk, int error) { int audit_type = AUDIT_APPARMOR_AUTO; struct common_audit_data sa; struct apparmor_audit_data aad = { }; struct lsm_network_audit net = { }; if (sk) { sa.type = LSM_AUDIT_DATA_NET; } else { sa.type = LSM_AUDIT_DATA_NONE; } /* todo fill in socket addr info */ sa.aad = &aad; sa.u.net = &net; sa.aad->op = op, sa.u.net->family = family; sa.u.net->sk = sk; sa.aad->net.type = type; sa.aad->net.protocol = protocol; sa.aad->error = error; if (likely(!sa.aad->error)) { u16 audit_mask = profile->net.audit[sa.u.net->family]; if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && !(1 << sa.aad->net.type & audit_mask))) return 0; audit_type = AUDIT_APPARMOR_AUDIT; } else { u16 quiet_mask = profile->net.quiet[sa.u.net->family]; u16 kill_mask = 0; u16 denied = (1 << sa.aad->net.type) & ~quiet_mask; if (denied & kill_mask) audit_type = AUDIT_APPARMOR_KILL; if ((denied & quiet_mask) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) return COMPLAIN_MODE(profile) ? 0 : sa.aad->error; } return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb); }
/** * profile_capable - test if profile allows use of capability @cap * @profile: profile being enforced (NOT NULL, NOT unconfined) * @cap: capability to test if allowed * @sa: audit data (MAY BE NULL indicating no auditing) * * Returns: 0 if allowed else -EPERM */ static int profile_capable(struct aa_profile *profile, int cap, struct common_audit_data *sa) { int error; if (cap_raised(profile->caps.allow, cap) && !cap_raised(profile->caps.denied, cap)) error = 0; else error = -EPERM; if (!sa) { if (COMPLAIN_MODE(profile)) return complain_error(error); return error; } return audit_caps(sa, profile, cap, error); }
/** * audit_caps - audit a capability * @sa: audit data * @profile: profile being tested for confinement (NOT NULL) * @cap: capability tested * @error: error code returned by test * * Do auditing of capability and handle, audit/complain/kill modes switching * and duplicate message elimination. * * Returns: 0 or sa->error on success, error code on failure */ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, int cap, int error) { struct audit_cache *ent; int type = AUDIT_APPARMOR_AUTO; aad(sa)->error = error; if (likely(!error)) { /* test if auditing is being forced */ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && !cap_raised(profile->caps.audit, cap))) return 0; type = AUDIT_APPARMOR_AUDIT; } else if (KILL_MODE(profile) || cap_raised(profile->caps.kill, cap)) { type = AUDIT_APPARMOR_KILL; } else if (cap_raised(profile->caps.quiet, cap) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) { /* quiet auditing */ return error; } /* Do simple duplicate message elimination */ ent = &get_cpu_var(audit_cache); if (profile == ent->profile && cap_raised(ent->caps, cap)) { put_cpu_var(audit_cache); if (COMPLAIN_MODE(profile)) return complain_error(error); return error; } else { aa_put_profile(ent->profile); ent->profile = aa_get_profile(profile); cap_raise(ent->caps, cap); } put_cpu_var(audit_cache); return aa_audit(type, profile, sa, audit_cb); }
/** * profile_capable - test if profile allows use of capability @cap * @profile: profile being enforced (NOT NULL, NOT unconfined) * @cap: capability to test if allowed * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated * @sa: audit data (MAY BE NULL indicating no auditing) * * Returns: 0 if allowed else -EPERM */ static int profile_capable(struct aa_profile *profile, int cap, unsigned int opts, struct common_audit_data *sa) { int error; if (cap_raised(profile->caps.allow, cap) && !cap_raised(profile->caps.denied, cap)) error = 0; else error = -EPERM; if (opts & CAP_OPT_NOAUDIT) { if (!COMPLAIN_MODE(profile)) return error; /* audit the cap request in complain mode but note that it * should be optional. */ aad(sa)->info = "optional: no audit"; } return audit_caps(sa, profile, cap, 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 - Log an audit event to the audit subsystem * @type: audit type for the message * @profile: profile to check against * @sa: audit event * @cb: optional callback fn for type specific fields * * Handle default message switching based off of audit mode flags * * Returns: error on failure */ int aa_audit(int type, struct aa_profile *profile, struct aa_audit *sa, void (*cb) (struct audit_buffer *, struct aa_audit *)) { struct audit_context *audit_cxt; audit_cxt = aa_g_logsyscall ? current->audit_context : NULL; if (type == AUDIT_APPARMOR_AUTO) { if (likely(!sa->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->error; return aa_audit_base(type, profile, sa, audit_cxt, cb); }
/** * 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) * @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, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *)) { BUG_ON(!profile); if (type == AUDIT_APPARMOR_AUTO) { if (likely(!aad(sa)->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 aad(sa)->error; if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) type = AUDIT_APPARMOR_KILL; aad(sa)->label = &profile->label; aa_audit_msg(type, sa, cb); if (aad(sa)->type == AUDIT_APPARMOR_KILL) (void)send_sig_info(SIGKILL, NULL, sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ? sa->u.tsk : current); if (aad(sa)->type == AUDIT_APPARMOR_ALLOWED) return complain_error(aad(sa)->error); return aad(sa)->error; }