[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