From 748e4f3d702def1a4bff191e0cf93b6a05340f01 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Fri, 10 May 2024 07:41:34 +0000
Subject: [PATCH] add gpio led uart

---
 kernel/security/apparmor/policy_unpack.c |  276 ++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 231 insertions(+), 45 deletions(-)

diff --git a/kernel/security/apparmor/policy_unpack.c b/kernel/security/apparmor/policy_unpack.c
index 612f737..10896d6 100644
--- a/kernel/security/apparmor/policy_unpack.c
+++ b/kernel/security/apparmor/policy_unpack.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * AppArmor security module
  *
@@ -7,11 +8,6 @@
  * Copyright (C) 1998-2008 Novell/SUSE
  * Copyright 2009-2010 Canonical Ltd.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
  * AppArmor uses a serialized binary format for loading policy. To find
  * policy format documentation see Documentation/admin-guide/LSM/apparmor.rst
  * All policy is validated before it is used.
@@ -20,6 +16,7 @@
 #include <asm/unaligned.h>
 #include <linux/ctype.h>
 #include <linux/errno.h>
+#include <linux/zlib.h>
 
 #include "include/apparmor.h"
 #include "include/audit.h"
@@ -143,9 +140,11 @@
 {
 	if (l->size != r->size)
 		return false;
+	if (l->compressed_size != r->compressed_size)
+		return false;
 	if (aa_g_hash_policy && memcmp(l->hash, r->hash, aa_hash_size()) != 0)
 		return false;
-	return memcmp(l->data, r->data, r->size) == 0;
+	return memcmp(l->data, r->data, r->compressed_size ?: r->size) == 0;
 }
 
 /*
@@ -164,10 +163,10 @@
 		aa_put_ns(ns);
 	}
 
-	kzfree(d->hash);
-	kzfree(d->name);
+	kfree_sensitive(d->hash);
+	kfree_sensitive(d->name);
 	kvfree(d->data);
-	kzfree(d);
+	kfree_sensitive(d);
 }
 
 void aa_loaddata_kref(struct kref *kref)
@@ -244,11 +243,11 @@
 static bool unpack_X(struct aa_ext *e, enum aa_code code)
 {
 	if (!inbounds(e, 1))
-		return 0;
+		return false;
 	if (*(u8 *) e->pos != code)
-		return 0;
+		return false;
 	e->pos++;
-	return 1;
+	return true;
 }
 
 /**
@@ -262,10 +261,10 @@
  * name element in the stream.  If @name is NULL any name element will be
  * skipped and only the typecode will be tested.
  *
- * Returns 1 on success (both type code and name tests match) and the read
+ * Returns true on success (both type code and name tests match) and the read
  * head is advanced past the headers
  *
- * Returns: 0 if either match fails, the read head does not move
+ * Returns: false if either match fails, the read head does not move
  */
 static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
 {
@@ -290,11 +289,29 @@
 
 	/* now check if type code matches */
 	if (unpack_X(e, code))
-		return 1;
+		return true;
 
 fail:
 	e->pos = pos;
-	return 0;
+	return false;
+}
+
+static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name)
+{
+	void *pos = e->pos;
+
+	if (unpack_nameX(e, AA_U8, name)) {
+		if (!inbounds(e, sizeof(u8)))
+			goto fail;
+		if (data)
+			*data = get_unaligned((u8 *)e->pos);
+		e->pos += sizeof(u8);
+		return true;
+	}
+
+fail:
+	e->pos = pos;
+	return false;
 }
 
 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
@@ -307,12 +324,12 @@
 		if (data)
 			*data = le32_to_cpu(get_unaligned((__le32 *) e->pos));
 		e->pos += sizeof(u32);
-		return 1;
+		return true;
 	}
 
 fail:
 	e->pos = pos;
-	return 0;
+	return false;
 }
 
 static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
@@ -325,12 +342,12 @@
 		if (data)
 			*data = le64_to_cpu(get_unaligned((__le64 *) e->pos));
 		e->pos += sizeof(u64);
-		return 1;
+		return true;
 	}
 
 fail:
 	e->pos = pos;
-	return 0;
+	return false;
 }
 
 static size_t unpack_array(struct aa_ext *e, const char *name)
@@ -455,7 +472,7 @@
  * @e: serialized data extent information  (NOT NULL)
  * @profile: profile to add the accept table to (NOT NULL)
  *
- * Returns: 1 if table successfully unpacked
+ * Returns: true if table successfully unpacked
  */
 static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
 {
@@ -518,12 +535,12 @@
 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
 			goto fail;
 	}
-	return 1;
+	return true;
 
 fail:
 	aa_free_domain_entries(&profile->file.trans);
 	e->pos = saved_pos;
-	return 0;
+	return false;
 }
 
 static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
@@ -548,11 +565,55 @@
 			goto fail;
 	}
 
-	return 1;
+	return true;
 
 fail:
 	e->pos = pos;
-	return 0;
+	return false;
+}
+
+static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
+{
+	void *pos = e->pos;
+	int i, size;
+
+	if (unpack_nameX(e, AA_STRUCT, "secmark")) {
+		size = unpack_array(e, NULL);
+
+		profile->secmark = kcalloc(size, sizeof(struct aa_secmark),
+					   GFP_KERNEL);
+		if (!profile->secmark)
+			goto fail;
+
+		profile->secmark_count = size;
+
+		for (i = 0; i < size; i++) {
+			if (!unpack_u8(e, &profile->secmark[i].audit, NULL))
+				goto fail;
+			if (!unpack_u8(e, &profile->secmark[i].deny, NULL))
+				goto fail;
+			if (!unpack_strdup(e, &profile->secmark[i].label, NULL))
+				goto fail;
+		}
+		if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+			goto fail;
+		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+			goto fail;
+	}
+
+	return true;
+
+fail:
+	if (profile->secmark) {
+		for (i = 0; i < size; i++)
+			kfree(profile->secmark[i].label);
+		kfree(profile->secmark);
+		profile->secmark_count = 0;
+		profile->secmark = NULL;
+	}
+
+	e->pos = pos;
+	return false;
 }
 
 static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
@@ -582,11 +643,11 @@
 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
 			goto fail;
 	}
-	return 1;
+	return true;
 
 fail:
 	e->pos = pos;
-	return 0;
+	return false;
 }
 
 static u32 strhash(const void *data, u32 len, u32 seed)
@@ -685,12 +746,18 @@
 		profile->label.flags |= FLAG_HAT;
 	if (!unpack_u32(e, &tmp, NULL))
 		goto fail;
-	if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG))
+	if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) {
 		profile->mode = APPARMOR_COMPLAIN;
-	else if (tmp == PACKED_MODE_KILL)
+	} else if (tmp == PACKED_MODE_ENFORCE) {
+		profile->mode = APPARMOR_ENFORCE;
+	} else if (tmp == PACKED_MODE_KILL) {
 		profile->mode = APPARMOR_KILL;
-	else if (tmp == PACKED_MODE_UNCONFINED)
+	} else if (tmp == PACKED_MODE_UNCONFINED) {
 		profile->mode = APPARMOR_UNCONFINED;
+		profile->label.flags |= FLAG_UNCONFINED;
+	} else {
+		goto fail;
+	}
 	if (!unpack_u32(e, &tmp, NULL))
 		goto fail;
 	if (tmp)
@@ -750,6 +817,11 @@
 
 	if (!unpack_rlimits(e, profile)) {
 		info = "failed to unpack profile rlimits";
+		goto fail;
+	}
+
+	if (!unpack_secmark(e, profile)) {
+		info = "failed to unpack profile secmark rules";
 		goto fail;
 	}
 
@@ -824,7 +896,7 @@
 		while (unpack_strdup(e, &key, NULL)) {
 			data = kzalloc(sizeof(*data), GFP_KERNEL);
 			if (!data) {
-				kzfree(key);
+				kfree_sensitive(key);
 				goto fail;
 			}
 
@@ -832,13 +904,18 @@
 			data->size = unpack_blob(e, &data->data, NULL);
 			data->data = kvmemdup(data->data, data->size);
 			if (data->size && !data->data) {
-				kzfree(data->key);
-				kzfree(data);
+				kfree_sensitive(data->key);
+				kfree_sensitive(data);
 				goto fail;
 			}
 
-			rhashtable_insert_fast(profile->data, &data->head,
-					       profile->data->p);
+			if (rhashtable_insert_fast(profile->data, &data->head,
+						   profile->data->p)) {
+				kfree_sensitive(data->key);
+				kfree_sensitive(data);
+				info = "failed to insert data to table";
+				goto fail;
+			}
 		}
 
 		if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
@@ -892,7 +969,7 @@
 	 * if not specified use previous version
 	 * Mask off everything that is not kernel abi version
 	 */
-	if (VERSION_LT(e->version, v5) || VERSION_GT(e->version, v7)) {
+	if (VERSION_LT(e->version, v5) || VERSION_GT(e->version, v8)) {
 		audit_iface(NULL, NULL, NULL, "unsupported interface version",
 			    e, error);
 		return error;
@@ -905,11 +982,14 @@
 				    e, error);
 			return error;
 		}
-		if (*ns && strcmp(*ns, name))
+		if (*ns && strcmp(*ns, name)) {
 			audit_iface(NULL, NULL, NULL, "invalid ns change", e,
 				    error);
-		else if (!*ns)
-			*ns = name;
+		} else if (!*ns) {
+			*ns = kstrdup(name, GFP_KERNEL);
+			if (!*ns)
+				return -ENOMEM;
+		}
 	}
 
 	return 0;
@@ -921,8 +1001,8 @@
 	xtype = xindex & AA_X_TYPE_MASK;
 	index = xindex & AA_X_INDEX_MASK;
 	if (xtype == AA_X_TABLE && index >= table_size)
-		return 0;
-	return 1;
+		return false;
+	return true;
 }
 
 /* verify dfa xindexes are in range of transition tables */
@@ -931,11 +1011,11 @@
 	int i;
 	for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
 		if (!verify_xindex(dfa_user_xindex(dfa, i), table_size))
-			return 0;
+			return false;
 		if (!verify_xindex(dfa_other_xindex(dfa, i), table_size))
-			return 0;
+			return false;
 	}
-	return 1;
+	return true;
 }
 
 /**
@@ -964,7 +1044,7 @@
 		aa_put_profile(ent->old);
 		aa_put_profile(ent->new);
 		kfree(ent->ns_name);
-		kzfree(ent);
+		kfree_sensitive(ent);
 	}
 }
 
@@ -974,6 +1054,105 @@
 	if (ent)
 		INIT_LIST_HEAD(&ent->list);
 	return ent;
+}
+
+static int deflate_compress(const char *src, size_t slen, char **dst,
+			    size_t *dlen)
+{
+	int error;
+	struct z_stream_s strm;
+	void *stgbuf, *dstbuf;
+	size_t stglen = deflateBound(slen);
+
+	memset(&strm, 0, sizeof(strm));
+
+	if (stglen < slen)
+		return -EFBIG;
+
+	strm.workspace = kvzalloc(zlib_deflate_workspacesize(MAX_WBITS,
+							     MAX_MEM_LEVEL),
+				  GFP_KERNEL);
+	if (!strm.workspace)
+		return -ENOMEM;
+
+	error = zlib_deflateInit(&strm, aa_g_rawdata_compression_level);
+	if (error != Z_OK) {
+		error = -ENOMEM;
+		goto fail_deflate_init;
+	}
+
+	stgbuf = kvzalloc(stglen, GFP_KERNEL);
+	if (!stgbuf) {
+		error = -ENOMEM;
+		goto fail_stg_alloc;
+	}
+
+	strm.next_in = src;
+	strm.avail_in = slen;
+	strm.next_out = stgbuf;
+	strm.avail_out = stglen;
+
+	error = zlib_deflate(&strm, Z_FINISH);
+	if (error != Z_STREAM_END) {
+		error = -EINVAL;
+		goto fail_deflate;
+	}
+	error = 0;
+
+	if (is_vmalloc_addr(stgbuf)) {
+		dstbuf = kvzalloc(strm.total_out, GFP_KERNEL);
+		if (dstbuf) {
+			memcpy(dstbuf, stgbuf, strm.total_out);
+			kvfree(stgbuf);
+		}
+	} else
+		/*
+		 * If the staging buffer was kmalloc'd, then using krealloc is
+		 * probably going to be faster. The destination buffer will
+		 * always be smaller, so it's just shrunk, avoiding a memcpy
+		 */
+		dstbuf = krealloc(stgbuf, strm.total_out, GFP_KERNEL);
+
+	if (!dstbuf) {
+		error = -ENOMEM;
+		goto fail_deflate;
+	}
+
+	*dst = dstbuf;
+	*dlen = strm.total_out;
+
+fail_stg_alloc:
+	zlib_deflateEnd(&strm);
+fail_deflate_init:
+	kvfree(strm.workspace);
+	return error;
+
+fail_deflate:
+	kvfree(stgbuf);
+	goto fail_stg_alloc;
+}
+
+static int compress_loaddata(struct aa_loaddata *data)
+{
+
+	AA_BUG(data->compressed_size > 0);
+
+	/*
+	 * Shortcut the no compression case, else we increase the amount of
+	 * storage required by a small amount
+	 */
+	if (aa_g_rawdata_compression_level != 0) {
+		void *udata = data->data;
+		int error = deflate_compress(udata, data->size, &data->data,
+					     &data->compressed_size);
+		if (error)
+			return error;
+
+		kvfree(udata);
+	} else
+		data->compressed_size = data->size;
+
+	return 0;
 }
 
 /**
@@ -1044,6 +1223,9 @@
 			goto fail;
 		}
 	}
+	error = compress_loaddata(udata);
+	if (error)
+		goto fail;
 	return 0;
 
 fail_profile:
@@ -1057,3 +1239,7 @@
 
 	return error;
 }
+
+#ifdef CONFIG_SECURITY_APPARMOR_KUNIT_TEST
+#include "policy_unpack_test.c"
+#endif /* CONFIG_SECURITY_APPARMOR_KUNIT_TEST */

--
Gitblit v1.6.2