diff options
| -rw-r--r-- | README | 13 | ||||
| -rw-r--r-- | common/cmd_nvedit.c | 31 | ||||
| -rw-r--r-- | common/env_common.c | 18 | ||||
| -rw-r--r-- | common/env_flags.c | 159 | ||||
| -rw-r--r-- | include/env_flags.h | 50 | ||||
| -rw-r--r-- | include/environment.h | 3 | ||||
| -rw-r--r-- | tools/env/fw_env.c | 74 | 
7 files changed, 330 insertions, 18 deletions
| @@ -3128,7 +3128,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|c] +		attributes = type_attribute[access_atribute]  		entry = variable_name[:attributes]  		list = entry[,list] @@ -3140,6 +3141,12 @@ Configuration Settings:  		i - IP 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  		Define this to a list (string) to define the ".flags"  		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  		".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  of environment data (variable area); in general, we support the  following configurations: diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 468b89cc9..e8dfbf5d8 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -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)  {  	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;  } @@ -456,13 +459,17 @@ static int print_static_flags(const char *var_name, const char *flags)  static int print_active_flags(ENTRY *entry)  {  	enum env_flags_vartype type; +	enum env_flags_varaccess access;  	if (entry->flags == 0)  		return 0;  	type = (enum env_flags_vartype)  		(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;  } @@ -480,17 +487,29 @@ int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  	env_flags_print_vartypes();  	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 */  	puts("Static flags:\n"); -	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type"); -	printf("\t%-20s %-20s\n", "-------------", "-------------"); +	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", +		"Variable Access"); +	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", +		"---------------");  	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags);  	puts("\n");  	/* walk through each variable and print the flags if non-default */  	puts("Active flags:\n"); -	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type"); -	printf("\t%-20s %-20s\n", "-------------", "-------------"); +	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", +		"Variable Access"); +	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", +		"---------------");  	hwalk_r(&env_htab, print_active_flags);  	return 0;  } diff --git a/common/env_common.c b/common/env_common.c index bb18070c5..906b41fcc 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -95,6 +95,24 @@ int getenv_yesno(const char *var)  		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)  {  	int flags = 0; diff --git a/common/env_flags.c b/common/env_flags.c index 09f93d59d..4caf12e69 100644 --- a/common/env_flags.c +++ b/common/env_flags.c @@ -43,6 +43,17 @@  #endif  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  static const char * const env_flags_vartype_names[] = {  	"string", @@ -54,6 +65,12 @@ static const char * const env_flags_vartype_names[] = {  	"MAC address",  #endif  }; +static const char * const env_flags_varaccess_names[] = { +	"any", +	"read-only", +	"write-once", +	"change-default", +};  /*   * Print the whole list of available type flags. @@ -70,12 +87,34 @@ 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.   */  const char *env_flags_get_vartype_name(enum env_flags_vartype 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 */  /* @@ -100,6 +139,46 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags)  	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)  {  	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X'); @@ -242,6 +321,23 @@ 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_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   * defined flags for that variable, if any.   */ @@ -262,6 +358,21 @@ int env_flags_validate_type(const char *name, const char *value)  }  /* + * 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   */  int env_flags_validate_env_set_params(int argc, char * const argv[]) @@ -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)  { -	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)  {  	const char *name; -#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \ -&& defined(CONFIG_ETHADDR)  	const char *oldval = NULL;  	if (op != env_op_create)  		oldval = item->data; -#endif  	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;  } diff --git a/include/env_flags.h b/include/env_flags.h index 7e72523f0..0bdae0783 100644 --- a/include/env_flags.h +++ b/include/env_flags.h @@ -36,9 +36,18 @@ enum env_flags_vartype {  	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_ATTR_MAX_LEN 2  #define ENV_FLAGS_VARTYPE_LOC 0 +#define ENV_FLAGS_VARACCESS_LOC 1  #ifndef CONFIG_ENV_FLAGS_LIST_STATIC  #define CONFIG_ENV_FLAGS_LIST_STATIC "" @@ -53,15 +62,31 @@ enum env_flags_vartype {   */  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.   */  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  /*   * Parse the flags string from a .flags attribute list into the vartype enum.   */  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  /* @@ -69,11 +94,25 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags);   */  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   * its flags (directly looked at the .flags var).   */  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   */  int env_flags_validate_env_set_params(int argc, char * const argv[]); @@ -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 flag); +#endif /* USE_HOSTCC */ +  /*   * These are the binary flags used in the environment entry->flags variable to   * 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) */ - -#endif /* USE_HOSTCC */ +#define ENV_FLAGS_VARACCESS_PREVENT_DELETE		0x00000008 +#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__ */ diff --git a/include/environment.h b/include/environment.h index 00e59ba78..e64b43d2d 100644 --- a/include/environment.h +++ b/include/environment.h @@ -181,6 +181,9 @@ unsigned char env_get_char_memory(int index);  /* Function that updates CRC of the enironment */  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 */  void set_default_env(const char *s); diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index 5be36fc35..a596a1b0d 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -182,6 +182,32 @@ char *fw_getenv (char *name)  }  /* + * 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   * environment variables   */ @@ -282,6 +308,7 @@ int fw_env_write(char *name, char *value)  	int len;  	char *env, *nxt;  	char *oldval = NULL; +	int deleting, creating, overwriting;  	/*  	 * search if variable with this name already exists @@ -299,10 +326,49 @@ int fw_env_write(char *name, char *value)  			break;  	} -	/* -	 * Delete any existing definition -	 */ -	if (oldval) { +	deleting = (oldval && !(value && strlen(value))); +	creating = (!oldval && (value && strlen(value))); +	overwriting = (oldval && (value && strlen(value))); + +	/* 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  		/*  		 * Ethernet Address and serial# can be set only once |