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

Commit 3b3b0e4f authored by Eric Paris's avatar Eric Paris Committed by Linus Torvalds
Browse files

LSM: shrink sizeof LSM specific portion of common_audit_data



Linus found that the gigantic size of the common audit data caused a big
perf hit on something as simple as running stat() in a loop.  This patch
requires LSMs to declare the LSM specific portion separately rather than
doing it in a union.  Thus each LSM can be responsible for shrinking their
portion and don't have to pay a penalty just because other LSMs have a
bigger space requirement.

Signed-off-by: default avatarEric Paris <eparis@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 95694129
Loading
Loading
Loading
Loading
+4 −50
Original line number Diff line number Diff line
@@ -72,61 +72,15 @@ struct common_audit_data {
	/* this union contains LSM specific data */
	union {
#ifdef CONFIG_SECURITY_SMACK
		/* SMACK data */
		struct smack_audit_data {
			const char *function;
			char *subject;
			char *object;
			char *request;
			int result;
		} smack_audit_data;
		struct smack_audit_data *smack_audit_data;
#endif
#ifdef CONFIG_SECURITY_SELINUX
		/* SELinux data */
		struct {
			u32 ssid;
			u32 tsid;
			u16 tclass;
			u32 requested;
			u32 audited;
			u32 denied;
			/*
			 * auditdeny is a bit tricky and unintuitive.  See the
			 * comments in avc.c for it's meaning and usage.
			 */
			u32 auditdeny;
			struct av_decision *avd;
			int result;
		} selinux_audit_data;
		struct selinux_audit_data *selinux_audit_data;
#endif
#ifdef CONFIG_SECURITY_APPARMOR
		struct {
			int error;
			int op;
			int type;
			void *profile;
			const char *name;
			const char *info;
			union {
				void *target;
				struct {
					long pos;
					void *target;
				} iface;
				struct {
					int rlim;
					unsigned long max;
				} rlim;
				struct {
					const char *target;
					u32 request;
					u32 denied;
					uid_t ouid;
				} fs;
			};
		} apparmor_audit_data;
		struct apparmor_audit_data *apparmor_audit_data;
#endif
	};
	}; /* per LSM data pointer union */
	/* these callback will be implemented by a specific LSM */
	void (*lsm_pre_audit)(struct audit_buffer *, void *);
	void (*lsm_post_audit)(struct audit_buffer *, void *);
+19 −19
Original line number Diff line number Diff line
@@ -115,23 +115,23 @@ static void audit_pre(struct audit_buffer *ab, void *ca)

	if (aa_g_audit_header) {
		audit_log_format(ab, "apparmor=");
		audit_log_string(ab, aa_audit_type[sa->aad.type]);
		audit_log_string(ab, aa_audit_type[sa->aad->type]);
	}

	if (sa->aad.op) {
	if (sa->aad->op) {
		audit_log_format(ab, " operation=");
		audit_log_string(ab, op_table[sa->aad.op]);
		audit_log_string(ab, op_table[sa->aad->op]);
	}

	if (sa->aad.info) {
	if (sa->aad->info) {
		audit_log_format(ab, " info=");
		audit_log_string(ab, sa->aad.info);
		if (sa->aad.error)
			audit_log_format(ab, " error=%d", sa->aad.error);
		audit_log_string(ab, sa->aad->info);
		if (sa->aad->error)
			audit_log_format(ab, " error=%d", sa->aad->error);
	}

	if (sa->aad.profile) {
		struct aa_profile *profile = sa->aad.profile;
	if (sa->aad->profile) {
		struct aa_profile *profile = sa->aad->profile;
		pid_t pid;
		rcu_read_lock();
		pid = rcu_dereference(tsk->real_parent)->pid;
@@ -145,9 +145,9 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
		audit_log_untrustedstring(ab, profile->base.hname);
	}

	if (sa->aad.name) {
	if (sa->aad->name) {
		audit_log_format(ab, " name=");
		audit_log_untrustedstring(ab, sa->aad.name);
		audit_log_untrustedstring(ab, sa->aad->name);
	}
}

@@ -159,7 +159,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
void aa_audit_msg(int type, struct common_audit_data *sa,
		  void (*cb) (struct audit_buffer *, void *))
{
	sa->aad.type = type;
	sa->aad->type = type;
	sa->lsm_pre_audit = audit_pre;
	sa->lsm_post_audit = cb;
	common_lsm_audit(sa);
@@ -184,7 +184,7 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
	BUG_ON(!profile);

	if (type == AUDIT_APPARMOR_AUTO) {
		if (likely(!sa->aad.error)) {
		if (likely(!sa->aad->error)) {
			if (AUDIT_MODE(profile) != AUDIT_ALL)
				return 0;
			type = AUDIT_APPARMOR_AUDIT;
@@ -196,21 +196,21 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
	if (AUDIT_MODE(profile) == AUDIT_QUIET ||
	    (type == AUDIT_APPARMOR_DENIED &&
	     AUDIT_MODE(profile) == AUDIT_QUIET))
		return sa->aad.error;
		return sa->aad->error;

	if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
		type = AUDIT_APPARMOR_KILL;

	if (!unconfined(profile))
		sa->aad.profile = profile;
		sa->aad->profile = profile;

	aa_audit_msg(type, sa, cb);

	if (sa->aad.type == AUDIT_APPARMOR_KILL)
	if (sa->aad->type == AUDIT_APPARMOR_KILL)
		(void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);

	if (sa->aad.type == AUDIT_APPARMOR_ALLOWED)
		return complain_error(sa->aad.error);
	if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
		return complain_error(sa->aad->error);

	return sa->aad.error;
	return sa->aad->error;
}
+4 −2
Original line number Diff line number Diff line
@@ -64,11 +64,13 @@ static int audit_caps(struct aa_profile *profile, struct task_struct *task,
	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;
	sa.aad->op = OP_CAPABLE;
	sa.aad->error = error;

	if (likely(!error)) {
		/* test if auditing is being forced */
+28 −26
Original line number Diff line number Diff line
@@ -67,22 +67,22 @@ static void file_audit_cb(struct audit_buffer *ab, void *va)
	struct common_audit_data *sa = va;
	uid_t fsuid = current_fsuid();

	if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
	if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) {
		audit_log_format(ab, " requested_mask=");
		audit_file_mask(ab, sa->aad.fs.request);
		audit_file_mask(ab, sa->aad->fs.request);
	}
	if (sa->aad.fs.denied & AA_AUDIT_FILE_MASK) {
	if (sa->aad->fs.denied & AA_AUDIT_FILE_MASK) {
		audit_log_format(ab, " denied_mask=");
		audit_file_mask(ab, sa->aad.fs.denied);
		audit_file_mask(ab, sa->aad->fs.denied);
	}
	if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
	if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) {
		audit_log_format(ab, " fsuid=%d", fsuid);
		audit_log_format(ab, " ouid=%d", sa->aad.fs.ouid);
		audit_log_format(ab, " ouid=%d", sa->aad->fs.ouid);
	}

	if (sa->aad.fs.target) {
	if (sa->aad->fs.target) {
		audit_log_format(ab, " target=");
		audit_log_untrustedstring(ab, sa->aad.fs.target);
		audit_log_untrustedstring(ab, sa->aad->fs.target);
	}
}

@@ -107,45 +107,47 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
{
	int type = AUDIT_APPARMOR_AUTO;
	struct common_audit_data sa;
	struct apparmor_audit_data aad = {0,};
	COMMON_AUDIT_DATA_INIT(&sa, NONE);
	sa.aad.op = op,
	sa.aad.fs.request = request;
	sa.aad.name = name;
	sa.aad.fs.target = target;
	sa.aad.fs.ouid = ouid;
	sa.aad.info = info;
	sa.aad.error = error;

	if (likely(!sa.aad.error)) {
	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;
		sa.aad->fs.request &= mask;

		if (likely(!sa.aad.fs.request))
		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;
		sa.aad->fs.request = sa.aad->fs.request & ~perms->allow;

		if (sa.aad.fs.request & perms->kill)
		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) &&
		if ((sa.aad->fs.request & perms->quiet) &&
		    AUDIT_MODE(profile) != AUDIT_NOQUIET &&
		    AUDIT_MODE(profile) != AUDIT_ALL)
			sa.aad.fs.request &= ~perms->quiet;
			sa.aad->fs.request &= ~perms->quiet;

		if (!sa.aad.fs.request)
			return COMPLAIN_MODE(profile) ? 0 : sa.aad.error;
		if (!sa.aad->fs.request)
			return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
	}

	sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow;
	sa.aad->fs.denied = sa.aad->fs.request & ~perms->allow;
	return aa_audit(type, profile, gfp, &sa, file_audit_cb);
}

+27 −1
Original line number Diff line number Diff line
@@ -103,7 +103,33 @@ enum aa_ops {
};


/* define a short hand for apparmor_audit_data portion of common_audit_data */
struct apparmor_audit_data {
	int error;
	int op;
	int type;
	void *profile;
	const char *name;
	const char *info;
	union {
		void *target;
		struct {
			long pos;
			void *target;
		} iface;
		struct {
			int rlim;
			unsigned long max;
		} rlim;
		struct {
			const char *target;
			u32 request;
			u32 denied;
			uid_t ouid;
		} fs;
	};
};

/* define a short hand for apparmor_audit_data structure */
#define aad apparmor_audit_data

void aa_audit_msg(int type, struct common_audit_data *sa,
Loading