This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC][PATCH] Sanitize the environment for setuid/setgid processes


ChangeLog:

2010-11-19  Pavel Labushev  <p.labushev@gmail.com>

	* elf/dl-envsec.c: New file.
	* elf/dl-support.c (_dl_non_dynamic_init): If __libc_enable_secure
	then sanitize the environment.
	* elf/Makefile: add envsec to dl-routines list.
	* elf/rtld.c (process_envvars): If __libc_enable_secure
	then sanitize the environment.
	* sysdeps/generic/ldsodefs.h: Add prototype for _dl_env_sanitize.
	* sysdeps/generic/unsecvars.h: Define PRIVENV_WHITELIST_FILE and
	PRIVENV_BLACKLIST_FILE.


Description:

This patch implements whitelist or blacklist based system-wide environment
sanitization for suid/sgid processes under centralized control of software
distributions or system administrators.

The goal is to mitigate the security impact of bugs in any environment
handling code (that potentially could be exploited in a context of some
suid/sgid process) by removing every (not) listed environment variable
before it would be handled.

The patch is mostly based on the existing code in:
* elf/dl-environ.c (unsetenv)
* elf/rtld.c (dl_main: the /etc/ld.so.preload parsing code)

How it works:

If the whitelist file /etc/privenv-allow exists and is readable, a suid/sgid
process unsets every variable if its name is not listed in that file.

Otherwise, if the blacklist file /etc/privenv-deny exists and is readable, a
suid/sgid process unsets every variable if its name is in the blacklist.

If the file is readable but cannot be read, that could mean an attacker did
lower RLIMIT_NOFILE or open too much file descriptors inherited after
execve(2) to avoid the environment sanitization. In such case a suid/sgid
process performs _exit(EACCES).

(However, an empty file also could not be mapped and read, which, I think,
is a corner case and should be avoided by writing a single whitespace
character or a comment like "# Do not remove this line." to the file.
Another way is to modify _dl_sysdep_read_whole_file function so it would set
errno to distinguish open(2) and mmap(2) failures. I'm not sure if it's more
acceptable solution, thus I didn't implement it, but I would in case it is.)

There's no performance or any runtime impact for non-suid/sgid processes.

For suid/sgid processes the performance impact is minimal and comparable to
the one for parsing of /etc/ld.so.preload and the UNSECURE_ENVVARS
filtering. If no whitelist nor blacklist file exist, the overhead is only
two access(2) syscalls.

The sanitization code is invoked very close to the similar UNSECURE_ENVVARS
filtering code, but before the LD_* environment variables handling code.
That makes it possible to mitigate the security impact of bugs like the
recent ones disclosed by Tavis Ormandy in the LD_AUDIT handling code.

The contents of whitelist and blacklist files can be changed by system
administrators without rebuilding glibc. Therefore they could do more strict
environment sanitization and change the white/blacklist file contents on
demand, which is not the case with UNSECURE_ENVVARS.

Why should it be implemented in glibc and not in the kernel:

The kernel security people I consulted with say it should be in userspace
because:
* The kernel haven't to have special cases for environment variables that
are defined and implemented in userspace.
* It's more expensive for the kernel to do it, because it has to copy all
environment variables to the kernel just to inspect them.

And I would add that glibc is supposed to be running on different kernels,
and it would require far more effort to implement the sanitization in every
kernel.

-----

Testing:

There's no tests for /etc/ld.so.preload nor /etc/suid-debug nor even
__libc_enable_secure. Should the environment sanitization be tested regardless?

The only way I see we can test the sanitization is with a small suid
application that will be started in a prepared chroot environment containing
/etc/privenv-* files and will check for any unexpected contents in its
environment. So the questions are:

This would work only when the testing is done as root. Is that acceptable?

Should the test fail or be skipped if it was started by an unprivileged user?

And which user should own the suid binary? nobody?


Copyright:

I'd like to assign copyright for all future glibc submissions. So I didn't
add my personal copyright notices to the patch. What should I do to assign
my copyright to FSF? I'm self-employed, and this patch isn't a part of any
work I do for my customers.

Attachment: privenv-sanitize.patch
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]