1
0
Fork 0

env: Add support for access control to .flags

Add support for read-only, write-once, and change-default.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
utp
Joe Hershberger 2012-12-11 22:16:34 -06:00 committed by Tom Rini
parent fffad71bc4
commit 267541f776
7 changed files with 330 additions and 18 deletions

13
README
View File

@ -3128,7 +3128,8 @@ Configuration Settings:
The format of the list is: The format of the list is:
type_attribute = [s|d|x|b|i|m] type_attribute = [s|d|x|b|i|m]
attributes = type_attribute access_atribute = [a|r|o|c]
attributes = type_attribute[access_atribute]
entry = variable_name[:attributes] entry = variable_name[:attributes]
list = entry[,list] list = entry[,list]
@ -3140,6 +3141,12 @@ Configuration Settings:
i - IP address i - IP address
m - MAC address m - MAC address
The access attributes are:
a - Any (default)
r - Read-only
o - Write-once
c - Change-default
- CONFIG_ENV_FLAGS_LIST_DEFAULT - CONFIG_ENV_FLAGS_LIST_DEFAULT
Define this to a list (string) to define the ".flags" Define this to a list (string) to define the ".flags"
envirnoment variable in the default or embedded environment. envirnoment variable in the default or embedded environment.
@ -3151,6 +3158,10 @@ Configuration Settings:
list, simply add an entry for the same variable name to the list, simply add an entry for the same variable name to the
".flags" variable. ".flags" variable.
- CONFIG_ENV_ACCESS_IGNORE_FORCE
If defined, don't allow the -f switch to env set override variable
access flags.
The following definitions that deal with the placement and management The following definitions that deal with the placement and management
of environment data (variable area); in general, we support the of environment data (variable area); in general, we support the
following configurations: following configurations:

View File

@ -447,8 +447,11 @@ int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
static int print_static_flags(const char *var_name, const char *flags) static int print_static_flags(const char *var_name, const char *flags)
{ {
enum env_flags_vartype type = env_flags_parse_vartype(flags); enum env_flags_vartype type = env_flags_parse_vartype(flags);
enum env_flags_varaccess access = env_flags_parse_varaccess(flags);
printf("\t%-20s %-20s\n", var_name, env_flags_get_vartype_name(type)); printf("\t%-20s %-20s %-20s\n", var_name,
env_flags_get_vartype_name(type),
env_flags_get_varaccess_name(access));
return 0; return 0;
} }
@ -456,13 +459,17 @@ static int print_static_flags(const char *var_name, const char *flags)
static int print_active_flags(ENTRY *entry) static int print_active_flags(ENTRY *entry)
{ {
enum env_flags_vartype type; enum env_flags_vartype type;
enum env_flags_varaccess access;
if (entry->flags == 0) if (entry->flags == 0)
return 0; return 0;
type = (enum env_flags_vartype) type = (enum env_flags_vartype)
(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK); (entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
printf("\t%-20s %-20s\n", entry->key, env_flags_get_vartype_name(type)); access = env_flags_parse_varaccess_from_binflags(entry->flags);
printf("\t%-20s %-20s %-20s\n", entry->key,
env_flags_get_vartype_name(type),
env_flags_get_varaccess_name(access));
return 0; return 0;
} }
@ -480,17 +487,29 @@ int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
env_flags_print_vartypes(); env_flags_print_vartypes();
puts("\n"); puts("\n");
/* Print the available variable access types */
printf("Available variable access flags (position %d):\n",
ENV_FLAGS_VARACCESS_LOC);
puts("\tFlag\tVariable Access Name\n");
puts("\t----\t--------------------\n");
env_flags_print_varaccess();
puts("\n");
/* Print the static flags that may exist */ /* Print the static flags that may exist */
puts("Static flags:\n"); puts("Static flags:\n");
printf("\t%-20s %-20s\n", "Variable Name", "Variable Type"); printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
printf("\t%-20s %-20s\n", "-------------", "-------------"); "Variable Access");
printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
"---------------");
env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags); env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags);
puts("\n"); puts("\n");
/* walk through each variable and print the flags if non-default */ /* walk through each variable and print the flags if non-default */
puts("Active flags:\n"); puts("Active flags:\n");
printf("\t%-20s %-20s\n", "Variable Name", "Variable Type"); printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
printf("\t%-20s %-20s\n", "-------------", "-------------"); "Variable Access");
printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
"---------------");
hwalk_r(&env_htab, print_active_flags); hwalk_r(&env_htab, print_active_flags);
return 0; return 0;
} }

View File

@ -95,6 +95,24 @@ int getenv_yesno(const char *var)
1 : 0; 1 : 0;
} }
/*
* Look up the variable from the default environment
*/
char *getenv_default(const char *name)
{
char *ret_val;
unsigned long really_valid = gd->env_valid;
unsigned long real_gd_flags = gd->flags;
/* Pretend that the image is bad. */
gd->flags &= ~GD_FLG_ENV_READY;
gd->env_valid = 0;
ret_val = getenv(name);
gd->env_valid = really_valid;
gd->flags = real_gd_flags;
return ret_val;
}
void set_default_env(const char *s) void set_default_env(const char *s)
{ {
int flags = 0; int flags = 0;

View File

@ -43,6 +43,17 @@
#endif #endif
static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
static const char env_flags_varaccess_rep[] = "aroc";
static const int env_flags_varaccess_mask[] = {
0,
ENV_FLAGS_VARACCESS_PREVENT_DELETE |
ENV_FLAGS_VARACCESS_PREVENT_CREATE |
ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
ENV_FLAGS_VARACCESS_PREVENT_DELETE |
ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
ENV_FLAGS_VARACCESS_PREVENT_DELETE |
ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR};
#ifdef CONFIG_CMD_ENV_FLAGS #ifdef CONFIG_CMD_ENV_FLAGS
static const char * const env_flags_vartype_names[] = { static const char * const env_flags_vartype_names[] = {
"string", "string",
@ -54,6 +65,12 @@ static const char * const env_flags_vartype_names[] = {
"MAC address", "MAC address",
#endif #endif
}; };
static const char * const env_flags_varaccess_names[] = {
"any",
"read-only",
"write-once",
"change-default",
};
/* /*
* Print the whole list of available type flags. * Print the whole list of available type flags.
@ -69,6 +86,20 @@ void env_flags_print_vartypes(void)
} }
} }
/*
* Print the whole list of available access flags.
*/
void env_flags_print_varaccess(void)
{
enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0;
while (curaccess != env_flags_varaccess_end) {
printf("\t%c -\t%s\n", env_flags_varaccess_rep[curaccess],
env_flags_varaccess_names[curaccess]);
curaccess++;
}
}
/* /*
* Return the name of the type. * Return the name of the type.
*/ */
@ -76,6 +107,14 @@ const char *env_flags_get_vartype_name(enum env_flags_vartype type)
{ {
return env_flags_vartype_names[type]; return env_flags_vartype_names[type];
} }
/*
* Return the name of the access.
*/
const char *env_flags_get_varaccess_name(enum env_flags_varaccess access)
{
return env_flags_varaccess_names[access];
}
#endif /* CONFIG_CMD_ENV_FLAGS */ #endif /* CONFIG_CMD_ENV_FLAGS */
/* /*
@ -100,6 +139,46 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags)
return env_flags_vartype_string; return env_flags_vartype_string;
} }
/*
* Parse the flags string from a .flags attribute list into the varaccess enum.
*/
enum env_flags_varaccess env_flags_parse_varaccess(const char *flags)
{
char *access;
if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
return env_flags_varaccess_any;
access = strchr(env_flags_varaccess_rep,
flags[ENV_FLAGS_VARACCESS_LOC]);
if (access != NULL)
return (enum env_flags_varaccess)
(access - &env_flags_varaccess_rep[0]);
printf("## Warning: Unknown environment variable access method '%c'\n",
flags[ENV_FLAGS_VARACCESS_LOC]);
return env_flags_varaccess_any;
}
/*
* Parse the binary flags from a hash table entry into the varaccess enum.
*/
enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags)
{
int i;
for (i = 0; i < sizeof(env_flags_varaccess_mask); i++)
if (env_flags_varaccess_mask[i] ==
(binflags & ENV_FLAGS_VARACCESS_BIN_MASK))
return (enum env_flags_varaccess)i;
printf("Warning: Non-standard access flags. (0x%x)\n",
binflags & ENV_FLAGS_VARACCESS_BIN_MASK);
return env_flags_varaccess_any;
}
static inline int is_hex_prefix(const char *value) static inline int is_hex_prefix(const char *value)
{ {
return value[0] == '0' && (value[1] == 'x' || value[1] == 'X'); return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
@ -241,6 +320,23 @@ enum env_flags_vartype env_flags_get_type(const char *name)
return env_flags_parse_vartype(flags); return env_flags_parse_vartype(flags);
} }
/*
* Look up the access of a variable directly from the .flags var.
*/
enum env_flags_varaccess env_flags_get_varaccess(const char *name)
{
const char *flags_list = getenv(ENV_FLAGS_VAR);
char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
if (env_flags_lookup(flags_list, name, flags))
return env_flags_varaccess_any;
if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
return env_flags_varaccess_any;
return env_flags_parse_varaccess(flags);
}
/* /*
* Validate that the proposed new value for "name" is valid according to the * Validate that the proposed new value for "name" is valid according to the
* defined flags for that variable, if any. * defined flags for that variable, if any.
@ -261,6 +357,21 @@ int env_flags_validate_type(const char *name, const char *value)
return 0; return 0;
} }
/*
* Validate that the proposed access to variable "name" is valid according to
* the defined flags for that variable, if any.
*/
int env_flags_validate_varaccess(const char *name, int check_mask)
{
enum env_flags_varaccess access;
int access_mask;
access = env_flags_get_varaccess(name);
access_mask = env_flags_varaccess_mask[access];
return (check_mask & access_mask) != 0;
}
/* /*
* Validate the parameters to "env set" directly * Validate the parameters to "env set" directly
*/ */
@ -292,7 +403,12 @@ int env_flags_validate_env_set_params(int argc, char * const argv[])
*/ */
static int env_parse_flags_to_bin(const char *flags) static int env_parse_flags_to_bin(const char *flags)
{ {
return env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK; int binflags;
binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK;
binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)];
return binflags;
} }
/* /*
@ -377,13 +493,10 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
int flag) int flag)
{ {
const char *name; const char *name;
#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \
&& defined(CONFIG_ETHADDR)
const char *oldval = NULL; const char *oldval = NULL;
if (op != env_op_create) if (op != env_op_create)
oldval = item->data; oldval = item->data;
#endif
name = item->key; name = item->key;
@ -422,6 +535,44 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
} }
} }
/* check for access permission */
#ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE
if (flag & H_FORCE)
return 0;
#endif
switch (op) {
case env_op_delete:
if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) {
printf("## Error: Can't delete \"%s\"\n", name);
return 1;
}
break;
case env_op_overwrite:
if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) {
printf("## Error: Can't overwrite \"%s\"\n", name);
return 1;
} else if (item->flags &
ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) {
const char *defval = getenv_default(name);
if (defval == NULL)
defval = "";
printf("oldval: %s defval: %s\n", oldval, defval);
if (strcmp(oldval, defval) != 0) {
printf("## Error: Can't overwrite \"%s\"\n",
name);
return 1;
}
}
break;
case env_op_create:
if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) {
printf("## Error: Can't create \"%s\"\n", name);
return 1;
}
break;
}
return 0; return 0;
} }

View File

@ -36,9 +36,18 @@ enum env_flags_vartype {
env_flags_vartype_end env_flags_vartype_end
}; };
enum env_flags_varaccess {
env_flags_varaccess_any,
env_flags_varaccess_readonly,
env_flags_varaccess_writeonce,
env_flags_varaccess_changedefault,
env_flags_varaccess_end
};
#define ENV_FLAGS_VAR ".flags" #define ENV_FLAGS_VAR ".flags"
#define ENV_FLAGS_ATTR_MAX_LEN 2 #define ENV_FLAGS_ATTR_MAX_LEN 2
#define ENV_FLAGS_VARTYPE_LOC 0 #define ENV_FLAGS_VARTYPE_LOC 0
#define ENV_FLAGS_VARACCESS_LOC 1
#ifndef CONFIG_ENV_FLAGS_LIST_STATIC #ifndef CONFIG_ENV_FLAGS_LIST_STATIC
#define CONFIG_ENV_FLAGS_LIST_STATIC "" #define CONFIG_ENV_FLAGS_LIST_STATIC ""
@ -52,27 +61,57 @@ enum env_flags_vartype {
* Print the whole list of available type flags. * Print the whole list of available type flags.
*/ */
void env_flags_print_vartypes(void); void env_flags_print_vartypes(void);
/*
* Print the whole list of available access flags.
*/
void env_flags_print_varaccess(void);
/* /*
* Return the name of the type. * Return the name of the type.
*/ */
const char *env_flags_get_vartype_name(enum env_flags_vartype type); const char *env_flags_get_vartype_name(enum env_flags_vartype type);
/*
* Return the name of the access.
*/
const char *env_flags_get_varaccess_name(enum env_flags_varaccess access);
#endif #endif
/* /*
* Parse the flags string from a .flags attribute list into the vartype enum. * Parse the flags string from a .flags attribute list into the vartype enum.
*/ */
enum env_flags_vartype env_flags_parse_vartype(const char *flags); enum env_flags_vartype env_flags_parse_vartype(const char *flags);
/*
* Parse the flags string from a .flags attribute list into the varaccess enum.
*/
enum env_flags_varaccess env_flags_parse_varaccess(const char *flags);
/*
* Parse the binary flags from a hash table entry into the varaccess enum.
*/
enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags);
#ifdef USE_HOSTCC #ifdef USE_HOSTCC
/* /*
* Look up the type of a variable directly from the .flags var. * Look up the type of a variable directly from the .flags var.
*/ */
enum env_flags_vartype env_flags_get_type(const char *name); enum env_flags_vartype env_flags_get_type(const char *name);
/*
* Look up the access of a variable directly from the .flags var.
*/
enum env_flags_varaccess env_flags_get_access(const char *name);
/* /*
* Validate the newval for its type to conform with the requirements defined by * Validate the newval for its type to conform with the requirements defined by
* its flags (directly looked at the .flags var). * its flags (directly looked at the .flags var).
*/ */
int env_flags_validate_type(const char *name, const char *newval); int env_flags_validate_type(const char *name, const char *newval);
/*
* Validate the newval for its access to conform with the requirements defined
* by its flags (directly looked at the .flags var).
*/
int env_flags_validate_access(const char *name, int check_mask);
/*
* Validate that the proposed access to variable "name" is valid according to
* the defined flags for that variable, if any.
*/
int env_flags_validate_varaccess(const char *name, int check_mask);
/* /*
* Validate the parameters passed to "env set" for type compliance * Validate the parameters passed to "env set" for type compliance
*/ */
@ -94,13 +133,18 @@ void env_flags_init(ENTRY *var_entry);
int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
int flag); int flag);
#endif /* USE_HOSTCC */
/* /*
* These are the binary flags used in the environment entry->flags variable to * These are the binary flags used in the environment entry->flags variable to
* decribe properties of veriables in the table * decribe properties of veriables in the table
*/ */
#define ENV_FLAGS_VARTYPE_BIN_MASK 0x00000007 #define ENV_FLAGS_VARTYPE_BIN_MASK 0x00000007
/* The actual variable type values use the enum value (within the mask) */ /* The actual variable type values use the enum value (within the mask) */
#define ENV_FLAGS_VARACCESS_PREVENT_DELETE 0x00000008
#endif /* USE_HOSTCC */ #define ENV_FLAGS_VARACCESS_PREVENT_CREATE 0x00000010
#define ENV_FLAGS_VARACCESS_PREVENT_OVERWR 0x00000020
#define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR 0x00000040
#define ENV_FLAGS_VARACCESS_BIN_MASK 0x00000078
#endif /* __ENV_FLAGS_H__ */ #endif /* __ENV_FLAGS_H__ */

View File

@ -181,6 +181,9 @@ unsigned char env_get_char_memory(int index);
/* Function that updates CRC of the enironment */ /* Function that updates CRC of the enironment */
void env_crc_update(void); void env_crc_update(void);
/* Look up the variable from the default environment */
char *getenv_default(const char *name);
/* [re]set to the default environment */ /* [re]set to the default environment */
void set_default_env(const char *s); void set_default_env(const char *s);

74
tools/env/fw_env.c vendored
View File

@ -181,6 +181,32 @@ char *fw_getenv (char *name)
return NULL; return NULL;
} }
/*
* 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;
}
/* /*
* Print the current definition of one, or more, or all * Print the current definition of one, or more, or all
* environment variables * environment variables
@ -282,6 +308,7 @@ int fw_env_write(char *name, char *value)
int len; int len;
char *env, *nxt; char *env, *nxt;
char *oldval = NULL; char *oldval = NULL;
int deleting, creating, overwriting;
/* /*
* search if variable with this name already exists * search if variable with this name already exists
@ -299,10 +326,49 @@ int fw_env_write(char *name, char *value)
break; break;
} }
/* deleting = (oldval && !(value && strlen(value)));
* Delete any existing definition creating = (!oldval && (value && strlen(value)));
*/ overwriting = (oldval && (value && strlen(value)));
if (oldval) {
/* check for permission */
if (deleting) {
if (env_flags_validate_varaccess(name,
ENV_FLAGS_VARACCESS_PREVENT_DELETE)) {
printf("Can't delete \"%s\"\n", name);
errno = EROFS;
return -1;
}
} else if (overwriting) {
if (env_flags_validate_varaccess(name,
ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) {
printf("Can't overwrite \"%s\"\n", name);
errno = EROFS;
return -1;
} else if (env_flags_validate_varaccess(name,
ENV_FLAGS_VARACCESS_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);
errno = EROFS;
return -1;
}
}
} else if (creating) {
if (env_flags_validate_varaccess(name,
ENV_FLAGS_VARACCESS_PREVENT_CREATE)) {
printf("Can't create \"%s\"\n", name);
errno = EROFS;
return -1;
}
} else
/* Nothing to do */
return 0;
if (deleting || overwriting) {
#ifndef CONFIG_ENV_OVERWRITE #ifndef CONFIG_ENV_OVERWRITE
/* /*
* Ethernet Address and serial# can be set only once * Ethernet Address and serial# can be set only once