[PATCH 1/2] tunables: Fix environment variable processing for setuid binaries

Florian Weimer fweimer@redhat.com
Wed Feb 1 18:26:00 GMT 2017


On 02/01/2017 12:37 PM, Siddhesh Poyarekar wrote:

> 	* elf/dl-tunable-types.h (tunable_seclevel_t): New enum.
> 	* elf/dl-tunables.c (tunables_strdup): Remove.
> 	(get_next_env): Also return the previous envp.
> 	(copy_to_heap): New function.
> 	(parse_tunables): Erase tunables of category
> 	TUNABLES_SECLEVEL_SXID_ERASE.
> 	(maybe_enable_malloc_check): Make MALLOC_CHECK_
> 	TUNABLE_SECLEVEL_NONE if /etc/setuid-debug is accessible.
> 	(__tunables_init)[TUNABLES_FRONTEND ==
> 	TUNABLES_FRONTEND_valstring]: Update GLIBC_TUNABLES envvar
> 	after parsing.
> 	[TUNABLES_FRONTEND != TUNABLES_FRONTEND_valstring]: Erase
> 	tunable envvars of category TUNABLES_SECLEVEL_SXID_ERASE.
> 	* elf/dl-tunables.h (struct _tunable): Change member is_secure
> 	to security_level.
> 	* elf/dl-tunables.list: Add security_level annotations for all
> 	tunables.
> 	* scripts/gen-tunables.awk: Recognize and generate enum values
> 	for security_level.
> 	* elf/tst-env-setuid.c: New test case.
> 	* elf/tst-env-setuid-tunables: new test case.
> 	* elf/Makefile (tests-static): Add them.

Changelog needs reference to bug 21073.

>  #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
> +# define ALLOC_SIZE 4096
> +/* Allocate bytes on heap to store tunable values copied over from the
> +   valstring.  We use a hardcoded ALLOC_SIZE to avoid querying the page size,
> +   since it may not be available this early in the startup process.  */

I still don't think this micro-optimization is worthwhile.  If we want 
to avoid allocations, we should avoid the copies (they would only be 
needed for strings and for variable rewriting under AT_SECURE).

> -	      tunable_initialize (cur, value);
> +	      /* If we are in a secure context (AT_SECURE) then ignore the tunable
> +		 unless it is explicitly marked as secure.  Tunable values take
> +		 precendence over their envvar aliases.  */
> +	      if (__libc_enable_secure)
> +		{
> +		  if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
> +		    {
> +		      if (p[len] == '\0')
> +			{
> +			  /* Last tunable in the valstring.  Null-terminate and
> +			     return.  */
> +			  *name = '\0';
> +			  return;
> +			}
> +		      else
> +			{
> +			  char *q = &p[len + 1];
> +			  p = name;
> +			  while (*q != '\0')
> +			    *name++ = *q++;
> +			  name[0] = '\0';
> +			  len = 0;
> +			}
> +		    }
> +
> +		  if (cur->security_level != TUNABLE_SECLEVEL_NONE)
> +		    break;
> +		}
> +
> +	      char *val = copy_to_heap (value, len);
> +	      if (val != NULL)
> +		tunable_initialize (cur, val);
>  	      break;
>  	    }
>  	}
>
> -      if (end == ':')
> +      if (p[len] == '\0')
> +	return;
> +      else
>  	p += len + 1;
> -      else
> -	return;
>      }
>  }

I believe this correctly rewrites the string.  But reusing the “name” 
variable in the move-forward loop is confusing.  Maybe also add a 
comment to explain what the loop is doing.

> diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c
> new file mode 100644
> index 0000000..7def663
> --- /dev/null
> +++ b/elf/tst-env-setuid.c
> @@ -0,0 +1,282 @@
> +/* Copyright (C) 2017 Free Software Foundation, Inc.


Copyright should start in, uh, 2012 because Â…

> +/* Copies the executable into a restricted directory, so that we can
> +   safely make it SGID with the TARGET group ID.  Then runs the
> +   executable.  */
> +static int
> +run_executable_sgid (gid_t target)

Â… this code looks familiar.

We should probably consolidate this functionality in support/ for 2.26.

Thanks,
Florian



More information about the Libc-alpha mailing list