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

Commit 44c2d9bd authored by KaiGai Kohei's avatar KaiGai Kohei Committed by James Morris
Browse files

Add audit messages on type boundary violations



The attached patch adds support to generate audit messages on two cases.

The first one is a case when a multi-thread process tries to switch its
performing security context using setcon(3), but new security context is
not bounded by the old one.

  type=SELINUX_ERR msg=audit(1245311998.599:17):        \
      op=security_bounded_transition result=denied      \
      oldcontext=system_u:system_r:httpd_t:s0           \
      newcontext=system_u:system_r:guest_webapp_t:s0

The other one is a case when security_compute_av() masked any permissions
due to the type boundary violation.

  type=SELINUX_ERR msg=audit(1245312836.035:32):	\
      op=security_compute_av reason=bounds              \
      scontext=system_u:object_r:user_webapp_t:s0       \
      tcontext=system_u:object_r:shadow_t:s0:c0         \
      tclass=file perms=getattr,open

Signed-off-by: default avatarKaiGai Kohei <kaigai@ak.jp.nec.com>
Acked-by: default avatarStephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent caabbdc0
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -137,7 +137,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
 * @tclass: target security class
 * @av: access vector
 */
void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
{
	const char **common_pts = NULL;
	u32 common_base = 0;
+0 −3
Original line number Diff line number Diff line
@@ -127,9 +127,6 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
		     u32 events, u32 ssid, u32 tsid,
		     u16 tclass, u32 perms);

/* Shows permission in human readable form */
void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);

/* Exported to selinuxfs */
int avc_get_hash_stats(char *page);
extern unsigned int avc_cache_threshold;
+117 −19
Original line number Diff line number Diff line
@@ -22,6 +22,11 @@
 *
 *  Added validation of kernel classes and permissions
 *
 * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
 *
 *  Added support for bounds domain and audit messaged on masked permissions
 *
 * Copyright (C) 2008, 2009 NEC Corporation
 * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
 * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
@@ -278,6 +283,95 @@ static int constraint_expr_eval(struct context *scontext,
	return s[0];
}

/*
 * security_dump_masked_av - dumps masked permissions during
 * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
 */
static int dump_masked_av_helper(void *k, void *d, void *args)
{
	struct perm_datum *pdatum = d;
	char **permission_names = args;

	BUG_ON(pdatum->value < 1 || pdatum->value > 32);

	permission_names[pdatum->value - 1] = (char *)k;

	return 0;
}

static void security_dump_masked_av(struct context *scontext,
				    struct context *tcontext,
				    u16 tclass,
				    u32 permissions,
				    const char *reason)
{
	struct common_datum *common_dat;
	struct class_datum *tclass_dat;
	struct audit_buffer *ab;
	char *tclass_name;
	char *scontext_name = NULL;
	char *tcontext_name = NULL;
	char *permission_names[32];
	int index, length;
	bool need_comma = false;

	if (!permissions)
		return;

	tclass_name = policydb.p_class_val_to_name[tclass - 1];
	tclass_dat = policydb.class_val_to_struct[tclass - 1];
	common_dat = tclass_dat->comdatum;

	/* init permission_names */
	if (common_dat &&
	    hashtab_map(common_dat->permissions.table,
			dump_masked_av_helper, permission_names) < 0)
		goto out;

	if (hashtab_map(tclass_dat->permissions.table,
			dump_masked_av_helper, permission_names) < 0)
		goto out;

	/* get scontext/tcontext in text form */
	if (context_struct_to_string(scontext,
				     &scontext_name, &length) < 0)
		goto out;

	if (context_struct_to_string(tcontext,
				     &tcontext_name, &length) < 0)
		goto out;

	/* audit a message */
	ab = audit_log_start(current->audit_context,
			     GFP_ATOMIC, AUDIT_SELINUX_ERR);
	if (!ab)
		goto out;

	audit_log_format(ab, "op=security_compute_av reason=%s "
			 "scontext=%s tcontext=%s tclass=%s perms=",
			 reason, scontext_name, tcontext_name, tclass_name);

	for (index = 0; index < 32; index++) {
		u32 mask = (1 << index);

		if ((mask & permissions) == 0)
			continue;

		audit_log_format(ab, "%s%s",
				 need_comma ? "," : "",
				 permission_names[index]
				 ? permission_names[index] : "????");
		need_comma = true;
	}
	audit_log_end(ab);
out:
	/* release scontext/tcontext */
	kfree(tcontext_name);
	kfree(scontext_name);

	return;
}

/*
 * security_boundary_permission - drops violated permissions
 * on boundary constraint.
@@ -347,28 +441,12 @@ static void type_attribute_bounds_av(struct context *scontext,
	}

	if (masked) {
		struct audit_buffer *ab;
		char *stype_name
			= policydb.p_type_val_to_name[source->value - 1];
		char *ttype_name
			= policydb.p_type_val_to_name[target->value - 1];
		char *tclass_name
			= policydb.p_class_val_to_name[tclass - 1];

		/* mask violated permissions */
		avd->allowed &= ~masked;

		/* notice to userspace via audit message */
		ab = audit_log_start(current->audit_context,
				     GFP_ATOMIC, AUDIT_SELINUX_ERR);
		if (!ab)
			return;

		audit_log_format(ab, "av boundary violation: "
				 "source=%s target=%s tclass=%s",
				 stype_name, ttype_name, tclass_name);
		avc_dump_av(ab, tclass, masked);
		audit_log_end(ab);
		/* audit masked permissions */
		security_dump_masked_av(scontext, tcontext,
					tclass, masked, "bounds");
	}
}

@@ -711,6 +789,26 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
		}
		index = type->bounds;
	}

	if (rc) {
		char *old_name = NULL;
		char *new_name = NULL;
		int length;

		if (!context_struct_to_string(old_context,
					      &old_name, &length) &&
		    !context_struct_to_string(new_context,
					      &new_name, &length)) {
			audit_log(current->audit_context,
				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
				  "op=security_bounded_transition "
				  "result=denied "
				  "oldcontext=%s newcontext=%s",
				  old_name, new_name);
		}
		kfree(new_name);
		kfree(old_name);
	}
out:
	read_unlock(&policy_rwlock);