[U-Boot] [PATCH 11/12] env: acl: Add support for access control to env ACL

Joe Hershberger joe.hershberger at ni.com
Fri Aug 17 22:49:45 CEST 2012


Add support for read-only and write-once.

Signed-off-by: Joe Hershberger <joe.hershberger at ni.com>
---
 README              | 13 +++++++++++-
 common/cmd_nvedit.c | 51 ++++++++++++++++++++++++++++++++++++++++++++
 common/env_acl.c    | 38 +++++++++++++++++++++++++++++++++
 include/env_acl.h   | 14 ++++++++++++
 tools/env/fw_env.c  | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 176 insertions(+), 1 deletion(-)

diff --git a/README b/README
index 2e34bcd..fa665f0 100644
--- a/README
+++ b/README
@@ -2094,6 +2094,11 @@ The following options need to be configured:
 		serial# is unaffected by this, i. e. it remains
 		read-only.]
 
+		The same can be accomplished in a more flexible way
+		for any variable by defining CONFIG_ENV_ACL and
+		specifying the type of access to allow to each
+		variable.
+
 - Protected RAM:
 		CONFIG_PRAM
 
@@ -2916,7 +2921,8 @@ Configuration Settings:
 
 	The format of the list is:
 		type_attribute = [s|d|x|b|i|m]
-		attributes = type_attribute
+		access_atribute = [a|r|o]
+		attributes = type_attribute[access_atribute]
 		entry = variable_name[:attributes]
 		list = entry[,list]
 
@@ -2928,6 +2934,11 @@ Configuration Settings:
 		i - IP address
 		m - MAC address
 
+	The access attributes are:
+		a - Any (default)
+		r - Read-only
+		o - Write-once (change default)
+
 	- CONFIG_ENV_ACL_DEFAULT
 		Define this to a list (string) to define the "acl" envirnoment
 		variable in the default or embedded environment.
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index b761b2c..13b6e08 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -200,6 +200,23 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
 }
 #endif
 
+#ifdef CONFIG_ENV_ACL
+/*
+ * Look up the variable from the default environment
+ */
+static char *getdefenv(const char *name)
+{
+	char *ret_val;
+	unsigned long really_valid = gd->env_valid;
+
+	/* Pretend that the image is bad. */
+	gd->env_valid = 0;
+	ret_val = getenv(name);
+	gd->env_valid = really_valid;
+	return ret_val;
+}
+#endif
+
 /*
  * Set a new environment variable,
  * or replace or delete an existing one.
@@ -237,6 +254,40 @@ int _do_env_set(int flag, int argc, char * const argv[])
 	creating = (!ep && ((argc >= 3) && argv[2] != NULL));
 	overwriting = (ep && ((argc >= 3) && argv[2] != NULL));
 
+#ifdef CONFIG_ENV_ACL
+	/* check for permission */
+	if (deleting) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_DELETE)) {
+			printf("## Error: Can't delete \"%s\"\n", name);
+			return 1;
+		}
+	} else if (overwriting) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_OVERWR)) {
+			printf("## Error: Can't overwrite \"%s\"\n", name);
+			return 1;
+		} else if (env_acl_validate_access(name,
+		    ENV_ACL_PREVENT_NONDEF_OVERWR)) {
+			const char *defval = getdefenv(name);
+
+			if (defval == NULL)
+				defval = "";
+			if (strcmp(ep->data, defval)
+			    != 0) {
+				printf("## Error: Can't overwrite \"%s\"\n",
+					name);
+				return 1;
+			}
+		}
+	} else if (creating) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_CREATE)) {
+			printf("## Error: Can't create \"%s\"\n", name);
+			return 1;
+		}
+	} else
+		/* Nothing to do */
+		return 0;
+#endif
+
 	/* Check for console redirection */
 	if (strcmp(name, "stdin") == 0)
 		console = stdin;
diff --git a/common/env_acl.c b/common/env_acl.c
index 7c86243..1a75e09 100644
--- a/common/env_acl.c
+++ b/common/env_acl.c
@@ -47,6 +47,12 @@
 
 static const char env_acl_static[] = CONFIG_ENV_ACL_STATIC "\0";
 static const char env_acl_type_rep[] = "sdxb" ENV_ACL_NET_TYPE_REPS;
+static const char env_acl_access_rep[] = "aro";
+static const char env_acl_access_mask[] = {
+	0,
+	ENV_ACL_PREVENT_DELETE | ENV_ACL_PREVENT_CREATE |
+		ENV_ACL_PREVENT_OVERWR,
+	ENV_ACL_PREVENT_DELETE | ENV_ACL_PREVENT_NONDEF_OVERWR};
 
 static int _env_acl_lookup_r(const char *name, char *attributes, int static_acl)
 {
@@ -147,6 +153,27 @@ enum env_acl_var_type env_acl_get_type(const char *name)
 	return ENV_ACL_VAR_TYPE_STRING;
 }
 
+enum env_acl_var_access env_acl_get_access(const char *name)
+{
+	char *access;
+	char attr[ENV_ACL_ATTR_MAX_LEN + 1];
+	if (env_acl_lookup_r(name, attr))
+		return ENV_ACL_VAR_ACCESS_ANY;
+
+	if (strlen(attr) <= ENV_ACL_ACCESS_LOC)
+		return ENV_ACL_VAR_ACCESS_ANY;
+
+	access = strchr(env_acl_access_rep, attr[ENV_ACL_ACCESS_LOC]);
+
+	if (access != NULL)
+		return (enum env_acl_var_access)
+			(access - &env_acl_access_rep[0]);
+
+	printf("## Warning: Unknown environment variable access method '%c'\n",
+		attr[ENV_ACL_ACCESS_LOC]);
+	return ENV_ACL_VAR_ACCESS_ANY;
+}
+
 static inline int is_hex_prefix(const char *value)
 {
 	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
@@ -249,6 +276,17 @@ int env_acl_validate_type(const char *name, const char *value)
 	return 0;
 }
 
+int env_acl_validate_access(const char *name, int check_mask)
+{
+	enum env_acl_var_access access;
+	int access_mask;
+
+	access = env_acl_get_access(name);
+	access_mask = env_acl_access_mask[access];
+
+	return (check_mask & access_mask) != 0;
+}
+
 int env_acl_validate_env_set_params(int argc, char * const argv[])
 {
 	if ((argc >= 3) && argv[2] != NULL) {
diff --git a/include/env_acl.h b/include/env_acl.h
index 9b0a199..09618f9 100644
--- a/include/env_acl.h
+++ b/include/env_acl.h
@@ -35,14 +35,28 @@ enum env_acl_var_type {
 #endif
 };
 
+enum env_acl_var_access {
+	ENV_ACL_VAR_ACCESS_ANY,
+	ENV_ACL_VAR_ACCESS_READ,
+	ENV_ACL_VAR_ACCESS_SET_ONCE,
+};
+
+#define ENV_ACL_PREVENT_DELETE		0x01
+#define ENV_ACL_PREVENT_CREATE		0x02
+#define ENV_ACL_PREVENT_OVERWR		0x04
+#define ENV_ACL_PREVENT_NONDEF_OVERWR	0x08
+
 #define ENV_ACL_LIST_DELIM	','
 #define ENV_ACL_ATTR_SEP	':'
 #define ENV_ACL_LIST_VAR_NAME	"acl"
 #define ENV_ACL_ATTR_MAX_LEN	2
 #define ENV_ACL_TYPE_LOC	0
+#define ENV_ACL_ACCESS_LOC	1
 
 enum env_acl_var_type env_acl_get_type(const char *name);
+enum env_acl_var_access env_acl_get_access(const char *name);
 int env_acl_validate_type(const char *name, const char *value);
+int env_acl_validate_access(const char *name, int check_mask);
 int env_acl_validate_env_set_params(int argc, char * const argv[]);
 
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index f7807b5..60ff06c 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -268,6 +268,34 @@ char *fw_getenv (char *name)
 	return NULL;
 }
 
+#ifdef CONFIG_ENV_ACL
+/*
+ * Search the default environment for a variable.
+ * Return the value, if found, or NULL, if not found.
+ */
+char *fw_getdefenv(char *name)
+{
+	char *env, *nxt;
+
+	for (env = default_environment; *env; env = nxt + 1) {
+		char *val;
+
+		for (nxt = env; *nxt; ++nxt) {
+			if (nxt >= &default_environment[ENV_SIZE]) {
+				fprintf(stderr, "## Error: "
+					"default environment not terminated\n");
+				return NULL;
+			}
+		}
+		val = envmatch(name, env);
+		if (!val)
+			continue;
+		return val;
+	}
+	return NULL;
+}
+#endif
+
 /*
  * Print the current definition of one, or more, or all
  * environment variables
@@ -391,6 +419,39 @@ int fw_env_write(char *name, char *value)
 	creating = (!oldval && (value && strlen(value)));
 	overwriting = (oldval && (value && strlen(value)));
 
+#ifdef CONFIG_ENV_ACL
+	/* check for permission */
+	if (deleting) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_DELETE)) {
+			printf("Can't delete \"%s\"\n", name);
+			return 1;
+		}
+	} else if (overwriting) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_OVERWR)) {
+			printf("Can't overwrite \"%s\"\n", name);
+			return 1;
+		} else if (env_acl_validate_access(name,
+		    ENV_ACL_PREVENT_NONDEF_OVERWR)) {
+			const char *defval = fw_getdefenv(name);
+
+			if (defval == NULL)
+				defval = "";
+			if (strcmp(oldval, defval)
+			    != 0) {
+				printf("Can't overwrite \"%s\"\n", name);
+				return 1;
+			}
+		}
+	} else if (creating) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_CREATE)) {
+			printf("Can't create \"%s\"\n", name);
+			return 1;
+		}
+	} else
+		/* Nothing to do */
+		return 0;
+#endif
+
 	if (deleting || overwriting) {
 #ifndef CONFIG_ENV_OVERWRITE
 		/*
-- 
1.7.11.5



More information about the U-Boot mailing list