Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c70c86c4 authored by John Johansen's avatar John Johansen
Browse files

apparmor: move capability checks to using labels

parent 317d9a05
Loading
Loading
Loading
Loading
+38 −19
Original line number Diff line number Diff line
@@ -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
@@ -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 */
@@ -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
 *
@@ -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;
}
+4 −2
Original line number Diff line number Diff line
@@ -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
@@ -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;
@@ -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)
{
+1 −1
Original line number Diff line number Diff line
@@ -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);
}

/**
+14 −6
Original line number Diff line number Diff line
@@ -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);
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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;