[PATCH 6/6] env: Add support for explicit write access list

Harald Seiler hws at denx.de
Thu Jun 25 20:12:57 CEST 2020


Hi Marek,

On Wed, 2020-06-03 at 02:01 +0200, Marek Vasut wrote:
> This option marks any U-Boot variable which does not have explicit 'w'
> writeable flag set as read-only. This way the environment can be locked
> down and only variables explicitly configured to be writeable can ever
> be changed by either 'env import', 'env set' or loading user environment
> from environment storage.

I haven't yet been able to get to the bottom of it but this patch seems to
regress the `envtools` build for me.  Here is the rather weird error message:

       HOSTCC  tools/env/fw_env_main.o
     In file included from tools/env/fw_env.c:15:
     include/env_flags.h:27:22: error: missing binary operator before token "("
      #if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
                           ^

Any idea what could be the cause for this?

-- 
Harald

> Signed-off-by: Marek Vasut <marex at denx.de>
> ---
>  env/Kconfig         |  8 ++++
>  env/flags.c         | 92 +++++++++++++++++++++++++++++++++++++++------
>  include/env_flags.h |  6 ++-
>  lib/hashtable.c     |  5 ++-
>  4 files changed, 98 insertions(+), 13 deletions(-)
> 
> diff --git a/env/Kconfig b/env/Kconfig
> index 8166e5df91..f53a1457fb 100644
> --- a/env/Kconfig
> +++ b/env/Kconfig
> @@ -613,6 +613,14 @@ config ENV_APPEND
>  	  with newly imported data. This may be used in combination with static
>  	  flags to e.g. to protect variables which must not be modified.
>  
> +config ENV_WRITEABLE_LIST
> +	bool "Permit write access only to listed variables"
> +	default n
> +	help
> +	  If defined, only environment variables which explicitly set the 'w'
> +	  writeable flag can be written and modified at runtime. No variables
> +	  can be otherwise created, written or imported into the environment.
> +
>  config ENV_ACCESS_IGNORE_FORCE
>  	bool "Block forced environment operations"
>  	default n
> diff --git a/env/flags.c b/env/flags.c
> index f7a53775c4..a2f6c1a3ec 100644
> --- a/env/flags.c
> +++ b/env/flags.c
> @@ -28,8 +28,15 @@
>  #define ENV_FLAGS_NET_VARTYPE_REPS ""
>  #endif
>  
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +#define ENV_FLAGS_WRITEABLE_VARACCESS_REPS "w"
> +#else
> +#define ENV_FLAGS_WRITEABLE_VARACCESS_REPS ""
> +#endif
> +
>  static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
> -static const char env_flags_varaccess_rep[] = "aroc";
> +static const char env_flags_varaccess_rep[] =
> +	"aroc" ENV_FLAGS_WRITEABLE_VARACCESS_REPS;
>  static const int env_flags_varaccess_mask[] = {
>  	0,
>  	ENV_FLAGS_VARACCESS_PREVENT_DELETE |
> @@ -38,7 +45,11 @@ static const int env_flags_varaccess_mask[] = {
>  	ENV_FLAGS_VARACCESS_PREVENT_DELETE |
>  		ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
>  	ENV_FLAGS_VARACCESS_PREVENT_DELETE |
> -		ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR};
> +		ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR,
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +	ENV_FLAGS_VARACCESS_WRITEABLE,
> +#endif
> +	};
>  
>  #ifdef CONFIG_CMD_ENV_FLAGS
>  static const char * const env_flags_vartype_names[] = {
> @@ -56,6 +67,9 @@ static const char * const env_flags_varaccess_names[] = {
>  	"read-only",
>  	"write-once",
>  	"change-default",
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +	"writeable",
> +#endif
>  };
>  
>  /*
> @@ -130,21 +144,33 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags)
>   */
>  enum env_flags_varaccess env_flags_parse_varaccess(const char *flags)
>  {
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +	enum env_flags_varaccess va_default = env_flags_varaccess_readonly;
> +#else
> +	enum env_flags_varaccess va_default = env_flags_varaccess_any;
> +#endif
> +	enum env_flags_varaccess va;
>  	char *access;
>  
>  	if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
> -		return env_flags_varaccess_any;
> +		return va_default;
>  
>  	access = strchr(env_flags_varaccess_rep,
>  		flags[ENV_FLAGS_VARACCESS_LOC]);
>  
> -	if (access != NULL)
> -		return (enum env_flags_varaccess)
> +	if (access != NULL) {
> +		va = (enum env_flags_varaccess)
>  			(access - &env_flags_varaccess_rep[0]);
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +		if (va != env_flags_varaccess_writeable)
> +			return env_flags_varaccess_readonly;
> +#endif
> +		return va;
> +	}
>  
>  	printf("## Warning: Unknown environment variable access method '%c'\n",
>  		flags[ENV_FLAGS_VARACCESS_LOC]);
> -	return env_flags_varaccess_any;
> +	return va_default;
>  }
>  
>  /*
> @@ -152,17 +178,29 @@ enum env_flags_varaccess env_flags_parse_varaccess(const char *flags)
>   */
>  enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags)
>  {
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +	enum env_flags_varaccess va_default = env_flags_varaccess_readonly;
> +#else
> +	enum env_flags_varaccess va_default = env_flags_varaccess_any;
> +#endif
> +	enum env_flags_varaccess va;
>  	int i;
>  
>  	for (i = 0; i < ARRAY_SIZE(env_flags_varaccess_mask); i++)
>  		if (env_flags_varaccess_mask[i] ==
> -		    (binflags & ENV_FLAGS_VARACCESS_BIN_MASK))
> -			return (enum env_flags_varaccess)i;
> +		    (binflags & ENV_FLAGS_VARACCESS_BIN_MASK)) {
> +			va = (enum env_flags_varaccess)i;
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +			if (va != env_flags_varaccess_writeable)
> +				return env_flags_varaccess_readonly;
> +#endif
> +			return va;
> +	}
>  
>  	printf("Warning: Non-standard access flags. (0x%x)\n",
>  		binflags & ENV_FLAGS_VARACCESS_BIN_MASK);
>  
> -	return env_flags_varaccess_any;
> +	return va_default;
>  }
>  
>  static inline int is_hex_prefix(const char *value)
> @@ -325,14 +363,20 @@ enum env_flags_vartype env_flags_get_type(const char *name)
>   */
>  enum env_flags_varaccess env_flags_get_varaccess(const char *name)
>  {
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +	const char *flags_list = NULL;
> +	enum env_flags_varaccess va_default = env_flags_varaccess_readonly;
> +#else
>  	const char *flags_list = env_get(ENV_FLAGS_VAR);
> +	enum env_flags_varaccess va_default = env_flags_varaccess_any;
> +#endif
>  	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
>  
>  	if (env_flags_lookup(flags_list, name, flags))
> -		return env_flags_varaccess_any;
> +		return va_default;
>  
>  	if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
> -		return env_flags_varaccess_any;
> +		return va_default;
>  
>  	return env_flags_parse_varaccess(flags);
>  }
> @@ -426,7 +470,11 @@ void env_flags_init(struct env_entry *var_entry)
>  	int ret = 1;
>  
>  	if (first_call) {
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +		flags_list = ENV_FLAGS_LIST_STATIC;
> +#else
>  		flags_list = env_get(ENV_FLAGS_VAR);
> +#endif
>  		first_call = 0;
>  	}
>  	/* look in the ".flags" and static for a reference to this variable */
> @@ -435,6 +483,16 @@ void env_flags_init(struct env_entry *var_entry)
>  	/* if any flags were found, set the binary form to the entry */
>  	if (!ret && strlen(flags))
>  		var_entry->flags = env_parse_flags_to_bin(flags);
> +
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +	/* Anything which is not explicitly writeable is read-only */
> +	if (!(var_entry->flags & ENV_FLAGS_VARACCESS_WRITEABLE)) {
> +		var_entry->flags &= ~ENV_FLAGS_VARACCESS_BIN_MASK;
> +		var_entry->flags |= ENV_FLAGS_VARACCESS_PREVENT_DELETE |
> +				ENV_FLAGS_VARACCESS_PREVENT_CREATE |
> +				ENV_FLAGS_VARACCESS_PREVENT_OVERWR;
> +	}
> +#endif
>  }
>  
>  /*
> @@ -523,6 +581,18 @@ int env_flags_validate(const struct env_entry *item, const char *newval,
>  	}
>  
>  	/* check for access permission */
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +	if (flag & H_DEFAULT)
> +		return 0;	/* Default env is always OK */
> +
> +	/* Writeable variables can be overwritten, anything else can not */
> +	if (op == env_op_overwrite &&
> +	    item->flags & ENV_FLAGS_VARACCESS_WRITEABLE)
> +		return 0;
> +
> +	return 1;
> +#endif
> +
>  #ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE
>  	if (flag & H_FORCE) {
>  		printf("## Error: Can't force access to \"%s\"\n", name);
> diff --git a/include/env_flags.h b/include/env_flags.h
> index 725841a891..62c3dd9fa0 100644
> --- a/include/env_flags.h
> +++ b/include/env_flags.h
> @@ -24,6 +24,9 @@ enum env_flags_varaccess {
>  	env_flags_varaccess_readonly,
>  	env_flags_varaccess_writeonce,
>  	env_flags_varaccess_changedefault,
> +#if CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +	env_flags_varaccess_writeable,
> +#endif
>  	env_flags_varaccess_end
>  };
>  
> @@ -173,6 +176,7 @@ int env_flags_validate(const struct env_entry *item, const char *newval,
>  #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
> +#define ENV_FLAGS_VARACCESS_WRITEABLE			0x00000080
> +#define ENV_FLAGS_VARACCESS_BIN_MASK			0x000000f8
>  
>  #endif /* __ENV_FLAGS_H__ */
> diff --git a/lib/hashtable.c b/lib/hashtable.c
> index 24aef5a085..bebad9d382 100644
> --- a/lib/hashtable.c
> +++ b/lib/hashtable.c
> @@ -946,9 +946,12 @@ int himport_r(struct hsearch_data *htab,
>  		e.data = value;
>  
>  		hsearch_r(e, ENV_ENTER, &rv, htab, flag);
> -		if (rv == NULL)
> +#if !CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)
> +		if (rv == NULL) {
>  			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
>  				name, value);
> +		}
> +#endif
>  
>  		debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n",
>  			htab, htab->filled, htab->size,



More information about the U-Boot mailing list