/** * 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); }
/** * audit_resource - audit setting resource limit * @profile: profile being enforced (NOT NULL) * @resoure: rlimit being auditing * @value: value being set * @error: error value * * Returns: 0 or sa->error else other error code on failure */ static int audit_resource(struct aa_profile *profile, unsigned int resource, unsigned long value, int error) { DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETRLIMIT); aad(&sa)->rlim.rlim = resource; aad(&sa)->rlim.max = value; aad(&sa)->error = error; return aa_audit(AUDIT_APPARMOR_AUTO, profile, &sa, audit_cb); }
/** * aa_audit_ptrace - do auditing for ptrace * @profile: profile being enforced (NOT NULL) * @target: profile being traced (NOT NULL) * @error: error condition * * Returns: %0 or error code */ static int aa_audit_ptrace(struct aa_profile *profile, struct aa_profile *target, int error) { struct common_audit_data sa; COMMON_AUDIT_DATA_INIT(&sa, NONE); sa.aad.op = OP_PTRACE; sa.aad.target = target; sa.aad.error = error; return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa, 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) * @op: operation being mediated * @request: permissions requested * @name: name of object being mediated (MAYBE NULL) * @target: name of target (MAYBE NULL) * @tlabel: target label (MAY BE 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 aa_perms *perms, const char *op, u32 request, const char *name, const char *target, struct aa_label *tlabel, kuid_t ouid, const char *info, int error) { int type = AUDIT_APPARMOR_AUTO; DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_TASK, op); sa.u.tsk = NULL; aad(&sa)->request = request; aad(&sa)->name = name; aad(&sa)->fs.target = target; aad(&sa)->peer = tlabel; aad(&sa)->fs.ouid = ouid; aad(&sa)->info = info; aad(&sa)->error = error; sa.u.tsk = NULL; if (likely(!aad(&sa)->error)) { u32 mask = perms->audit; if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) mask = 0xffff; /* mask off perms that are not being force audited */ aad(&sa)->request &= mask; if (likely(!aad(&sa)->request)) return 0; type = AUDIT_APPARMOR_AUDIT; } else { /* only report permissions that were denied */ aad(&sa)->request = aad(&sa)->request & ~perms->allow; AA_BUG(!aad(&sa)->request); if (aad(&sa)->request & perms->kill) type = AUDIT_APPARMOR_KILL; /* quiet known rejects, assumes quiet and kill do not overlap */ if ((aad(&sa)->request & perms->quiet) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) aad(&sa)->request &= ~perms->quiet; if (!aad(&sa)->request) return aad(&sa)->error; } aad(&sa)->denied = aad(&sa)->request & ~perms->allow; return aa_audit(type, profile, &sa, file_audit_cb); }
/** * audit_mount - handle the auditing of mount operations * @profile: the profile being enforced (NOT NULL) * @op: operation being mediated (NOT NULL) * @name: name of object being mediated (MAYBE NULL) * @src_name: src_name of object being mediated (MAYBE_NULL) * @type: type of filesystem (MAYBE_NULL) * @trans: name of trans (MAYBE NULL) * @flags: filesystem independent mount flags * @data: filesystem mount flags * @request: permissions requested * @perms: the permissions computed for the request (NOT NULL) * @info: extra information message (MAYBE NULL) * @error: 0 if operation allowed else failure error code * * Returns: %0 or error on failure */ static int audit_mount(struct aa_profile *profile, const char *op, const char *name, const char *src_name, const char *type, const char *trans, unsigned long flags, const void *data, u32 request, struct aa_perms *perms, const char *info, int error) { int audit_type = AUDIT_APPARMOR_AUTO; DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op); if (likely(!error)) { u32 mask = perms->audit; if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) mask = 0xffff; /* mask off perms that are not being force audited */ request &= mask; if (likely(!request)) return 0; audit_type = AUDIT_APPARMOR_AUDIT; } else { /* only report permissions that were denied */ request = request & ~perms->allow; if (request & perms->kill) audit_type = AUDIT_APPARMOR_KILL; /* quiet known rejects, assumes quiet and kill do not overlap */ if ((request & perms->quiet) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) request &= ~perms->quiet; if (!request) return error; } aad(&sa)->name = name; aad(&sa)->mnt.src_name = src_name; aad(&sa)->mnt.type = type; aad(&sa)->mnt.trans = trans; aad(&sa)->mnt.flags = flags; if (data && (perms->audit & AA_AUDIT_DATA)) aad(&sa)->mnt.data = data; aad(&sa)->info = info; aad(&sa)->error = error; return aa_audit(audit_type, profile, &sa, audit_cb); }
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_resource - audit setting resource limit * @profile: profile being enforced (NOT NULL) * @resoure: rlimit being auditing * @value: value being set * @error: error value * * Returns: 0 or sa->error else other error code on failure */ static int audit_resource(struct aa_profile *profile, unsigned int resource, unsigned long value, int error) { struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; sa.type = LSM_AUDIT_DATA_NONE; sa.aad = &aad; aad.op = OP_SETRLIMIT, aad.rlim.rlim = resource; aad.rlim.max = value; aad.error = error; return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa, 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); }
static int cross_ptrace_perm(struct aa_profile *tracer, struct aa_profile *tracee, u32 request, struct common_audit_data *sa) { if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) return xcheck(profile_ptrace_perm(tracer, tracee, request, sa), profile_ptrace_perm(tracee, tracer, request << PTRACE_PERM_SHIFT, sa)); /* policy uses the old style capability check for ptrace */ if (profile_unconfined(tracer) || tracer == tracee) return 0; aad(sa)->label = &tracer->label; aad(sa)->target = tracee->base.hname; aad(sa)->request = 0; aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); }
/** * 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); }
static int profile_tracer_perm(struct aa_profile *tracer, struct aa_label *tracee, u32 request, struct common_audit_data *sa) { if (profile_unconfined(tracer)) return 0; if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) return profile_ptrace_perm(tracer, tracee, request, sa); /* profile uses the old style capability check for ptrace */ if (&tracer->label == tracee) return 0; aad(sa)->label = &tracer->label; aad(sa)->peer = tracee; aad(sa)->request = 0; aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, CAP_OPT_NONE); return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); }