Loading security/apparmor/capability.c +38 −19 Original line number Diff line number Diff line Loading @@ -48,15 +48,16 @@ static DEFINE_PER_CPU(struct audit_cache, audit_cache); static void audit_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; audit_log_format(ab, " capname="); audit_log_untrustedstring(ab, capability_names[sa->u.cap]); } /** * audit_caps - audit a capability * @sa: audit data * @profile: profile being tested for confinement (NOT NULL) * @cap: capability tested @audit: whether an audit record should be generated * @error: error code returned by test * * Do auditing of capability and handle, audit/complain/kill modes switching Loading @@ -64,16 +65,13 @@ static void audit_cb(struct audit_buffer *ab, void *va) * * Returns: 0 or sa->error on success, error code on failure */ static int audit_caps(struct aa_profile *profile, int cap, int audit, int error) 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; DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); sa.u.cap = cap; aad(&sa)->error = error; if (audit == SECURITY_CAP_NOAUDIT) aad(&sa)->info = "optional: no audit"; aad(sa)->error = error; if (likely(!error)) { /* test if auditing is being forced */ Loading Loading @@ -105,24 +103,44 @@ static int audit_caps(struct aa_profile *profile, int cap, int audit, } put_cpu_var(audit_cache); return aa_audit(type, profile, &sa, audit_cb); 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 * @audit: whether an audit record should be 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) static int profile_capable(struct aa_profile *profile, int cap, int audit, struct common_audit_data *sa) { return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM; int error; if (cap_raised(profile->caps.allow, cap) && !cap_raised(profile->caps.denied, cap)) error = 0; else error = -EPERM; if (audit == SECURITY_CAP_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_capable - test permission to use capability * @profile: profile being tested against (NOT NULL) * @label: label being tested for capability (NOT NULL) * @cap: capability to be tested * @audit: whether an audit record should be generated * Loading @@ -130,14 +148,15 @@ static int profile_capable(struct aa_profile *profile, int cap) * * Returns: 0 on success, or else an error code. */ int aa_capable(struct aa_profile *profile, int cap, int audit) int aa_capable(struct aa_label *label, int cap, int audit) { int error = profile_capable(profile, cap); struct aa_profile *profile; int error = 0; DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); if (audit == SECURITY_CAP_NOAUDIT) { if (!COMPLAIN_MODE(profile)) return error; } sa.u.cap = cap; error = fn_for_each_confined(label, profile, profile_capable(profile, cap, audit, &sa)); return audit_caps(profile, cap, audit, error); return error; } security/apparmor/include/capability.h +4 −2 Original line number Diff line number Diff line Loading @@ -19,11 +19,12 @@ #include "apparmorfs.h" struct aa_profile; struct aa_label; /* aa_caps - confinement data for capabilities * @allowed: capabilities mask * @audit: caps that are to be audited * @denied: caps that are explicitly denied * @quiet: caps that should not be audited * @kill: caps that when requested will result in the task being killed * @extended: caps that are subject finer grained mediation Loading @@ -31,6 +32,7 @@ struct aa_profile; struct aa_caps { kernel_cap_t allow; kernel_cap_t audit; kernel_cap_t denied; kernel_cap_t quiet; kernel_cap_t kill; kernel_cap_t extended; Loading @@ -38,7 +40,7 @@ struct aa_caps { extern struct aa_sfs_entry aa_sfs_entry_caps[]; int aa_capable(struct aa_profile *profile, int cap, int audit); int aa_capable(struct aa_label *label, int cap, int audit); static inline void aa_free_cap_rules(struct aa_caps *caps) { Loading security/apparmor/ipc.c +1 −1 Original line number Diff line number Diff line Loading @@ -68,7 +68,7 @@ int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee, if (profile_unconfined(tracer) || tracer == tracee) return 0; /* log this capability request */ return aa_capable(tracer, CAP_SYS_PTRACE, 1); return aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); } /** Loading security/apparmor/lsm.c +14 −6 Original line number Diff line number Diff line Loading @@ -117,20 +117,28 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { struct aa_label *label; struct aa_profile *profile; const struct cred *cred; rcu_read_lock(); cred = __task_cred(target); label = aa_get_newest_cred_label(cred); profile = labels_profile(label); /* * cap_capget is stacked ahead of this and will * initialize effective and permitted. */ if (!profile_unconfined(profile) && !COMPLAIN_MODE(profile)) { *effective = cap_intersect(*effective, profile->caps.allow); *permitted = cap_intersect(*permitted, profile->caps.allow); if (!unconfined(label)) { struct aa_profile *profile; struct label_it i; label_for_each_confined(i, label, profile) { if (COMPLAIN_MODE(profile)) continue; *effective = cap_intersect(*effective, profile->caps.allow); *permitted = cap_intersect(*permitted, profile->caps.allow); } } rcu_read_unlock(); aa_put_label(label); Loading @@ -146,7 +154,7 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, label = aa_get_newest_cred_label(cred); if (!unconfined(label)) error = aa_capable(labels_profile(label), cap, audit); error = aa_capable(label, cap, audit); aa_put_label(label); return error; Loading security/apparmor/resource.c +1 −1 Original line number Diff line number Diff line Loading @@ -100,7 +100,7 @@ int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task, * task has CAP_SYS_RESOURCE. */ if ((profile != labels_profile(task_label) && aa_capable(profile, CAP_SYS_RESOURCE, 1)) || aa_capable(&profile->label, CAP_SYS_RESOURCE, 1)) || (profile->rlimits.mask & (1 << resource) && new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)) error = -EACCES; Loading Loading
security/apparmor/capability.c +38 −19 Original line number Diff line number Diff line Loading @@ -48,15 +48,16 @@ static DEFINE_PER_CPU(struct audit_cache, audit_cache); static void audit_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; audit_log_format(ab, " capname="); audit_log_untrustedstring(ab, capability_names[sa->u.cap]); } /** * audit_caps - audit a capability * @sa: audit data * @profile: profile being tested for confinement (NOT NULL) * @cap: capability tested @audit: whether an audit record should be generated * @error: error code returned by test * * Do auditing of capability and handle, audit/complain/kill modes switching Loading @@ -64,16 +65,13 @@ static void audit_cb(struct audit_buffer *ab, void *va) * * Returns: 0 or sa->error on success, error code on failure */ static int audit_caps(struct aa_profile *profile, int cap, int audit, int error) 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; DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); sa.u.cap = cap; aad(&sa)->error = error; if (audit == SECURITY_CAP_NOAUDIT) aad(&sa)->info = "optional: no audit"; aad(sa)->error = error; if (likely(!error)) { /* test if auditing is being forced */ Loading Loading @@ -105,24 +103,44 @@ static int audit_caps(struct aa_profile *profile, int cap, int audit, } put_cpu_var(audit_cache); return aa_audit(type, profile, &sa, audit_cb); 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 * @audit: whether an audit record should be 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) static int profile_capable(struct aa_profile *profile, int cap, int audit, struct common_audit_data *sa) { return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM; int error; if (cap_raised(profile->caps.allow, cap) && !cap_raised(profile->caps.denied, cap)) error = 0; else error = -EPERM; if (audit == SECURITY_CAP_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_capable - test permission to use capability * @profile: profile being tested against (NOT NULL) * @label: label being tested for capability (NOT NULL) * @cap: capability to be tested * @audit: whether an audit record should be generated * Loading @@ -130,14 +148,15 @@ static int profile_capable(struct aa_profile *profile, int cap) * * Returns: 0 on success, or else an error code. */ int aa_capable(struct aa_profile *profile, int cap, int audit) int aa_capable(struct aa_label *label, int cap, int audit) { int error = profile_capable(profile, cap); struct aa_profile *profile; int error = 0; DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); if (audit == SECURITY_CAP_NOAUDIT) { if (!COMPLAIN_MODE(profile)) return error; } sa.u.cap = cap; error = fn_for_each_confined(label, profile, profile_capable(profile, cap, audit, &sa)); return audit_caps(profile, cap, audit, error); return error; }
security/apparmor/include/capability.h +4 −2 Original line number Diff line number Diff line Loading @@ -19,11 +19,12 @@ #include "apparmorfs.h" struct aa_profile; struct aa_label; /* aa_caps - confinement data for capabilities * @allowed: capabilities mask * @audit: caps that are to be audited * @denied: caps that are explicitly denied * @quiet: caps that should not be audited * @kill: caps that when requested will result in the task being killed * @extended: caps that are subject finer grained mediation Loading @@ -31,6 +32,7 @@ struct aa_profile; struct aa_caps { kernel_cap_t allow; kernel_cap_t audit; kernel_cap_t denied; kernel_cap_t quiet; kernel_cap_t kill; kernel_cap_t extended; Loading @@ -38,7 +40,7 @@ struct aa_caps { extern struct aa_sfs_entry aa_sfs_entry_caps[]; int aa_capable(struct aa_profile *profile, int cap, int audit); int aa_capable(struct aa_label *label, int cap, int audit); static inline void aa_free_cap_rules(struct aa_caps *caps) { Loading
security/apparmor/ipc.c +1 −1 Original line number Diff line number Diff line Loading @@ -68,7 +68,7 @@ int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee, if (profile_unconfined(tracer) || tracer == tracee) return 0; /* log this capability request */ return aa_capable(tracer, CAP_SYS_PTRACE, 1); return aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); } /** Loading
security/apparmor/lsm.c +14 −6 Original line number Diff line number Diff line Loading @@ -117,20 +117,28 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { struct aa_label *label; struct aa_profile *profile; const struct cred *cred; rcu_read_lock(); cred = __task_cred(target); label = aa_get_newest_cred_label(cred); profile = labels_profile(label); /* * cap_capget is stacked ahead of this and will * initialize effective and permitted. */ if (!profile_unconfined(profile) && !COMPLAIN_MODE(profile)) { *effective = cap_intersect(*effective, profile->caps.allow); *permitted = cap_intersect(*permitted, profile->caps.allow); if (!unconfined(label)) { struct aa_profile *profile; struct label_it i; label_for_each_confined(i, label, profile) { if (COMPLAIN_MODE(profile)) continue; *effective = cap_intersect(*effective, profile->caps.allow); *permitted = cap_intersect(*permitted, profile->caps.allow); } } rcu_read_unlock(); aa_put_label(label); Loading @@ -146,7 +154,7 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, label = aa_get_newest_cred_label(cred); if (!unconfined(label)) error = aa_capable(labels_profile(label), cap, audit); error = aa_capable(label, cap, audit); aa_put_label(label); return error; Loading
security/apparmor/resource.c +1 −1 Original line number Diff line number Diff line Loading @@ -100,7 +100,7 @@ int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task, * task has CAP_SYS_RESOURCE. */ if ((profile != labels_profile(task_label) && aa_capable(profile, CAP_SYS_RESOURCE, 1)) || aa_capable(&profile->label, CAP_SYS_RESOURCE, 1)) || (profile->rlimits.mask & (1 << resource) && new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)) error = -EACCES; Loading