kern/109836: Security patch for rtld, a lack of environment sanitization

Guasconi Vincent tyoptyop at gmail.com
Sun Mar 4 06:50:03 UTC 2007


>Number:         109836
>Category:       kern
>Synopsis:       Security patch for rtld, a lack of environment sanitization
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Sun Mar 04 06:50:03 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Guasconi Vincent
>Release:        7.0
>Organization:
Student
>Environment:
FreeBSD 7.0-CURRENT-200609 (GENERIC)
>Description:
Hi!

I'm french so excuse my english :p.
Here's a security problem I solved (I think).

<---------->
Lack of environment sanitization in the FreeBSD, OpenBSD, NetBSD
dynamic loaders.

Impact:  Serious. May lead to privilege escalation.

A class of security vulnerabilities has resurfaced in the dynamic loaders
of FreeBSD, OpenBSD, and NetBSD in the sanitization of environment
variables for suid and sgid binaries.
[...]
Due to either badly implemented sanitization or a lack of it, a setuid
binary may execute other processes with a tainted environment.

No attempt is made to clear dangerous variables. The
FreeBSD dynamic loaders simply do not process the variables
when ruid does not equal euid.
<---------->
complete source :
http://lists.grok.org.uk/pipermail/full-disclosure/2006-November/050829.html


Already fix in NetBSD since 3 months :
http://cvsweb.netbsd.org/bsdweb.cgi/src/libexec/ld.elf_so/rtld.c.diff?r1=1.110&r2=1.111&f=h

-- 
Guasconi Vincent
French student.
http://altmylife.blogspot.com [fr]

>How-To-Repeat:

vulnerable root-suid program example:

main()
{
 setuid(0);
 execl("/usr/bin/id","id",0);
}

evil shared library:

__attribute__ ((constructor)) main()
{
 printf("[+] Hello from shared library land\n");
 execle("/bin/sh","sh",0,0);
}

>Fix:

So here's the patch for libexec/rtld-elf/rtld.c 1.120 (my first so be cool ^-^).
I've test it on my FreeBSD 7.0-CURRENT-200609 (GENERIC),
it works perfectly.
I don't know if you need I reproduce it for 6.2? I'm not really aware of the procedure.


26c26
<  * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.120 2007/01/09 17:50:05 jhb Exp $
---
>  * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.120 2007/03/04 04:42:00 jhb Exp $
140a141,142
> static void rtld_env_destroyer(char **);
> static void rtld_unsetenv(const char *, char **);
360,361c362,366
<     } else
<       dangerous_ld_env = 0;
---
>     } else {
>       /* issetugid isn't able to catch a setuid() so... */
>       rtld_env_destroyer(env);
>       dangerous_ld_env = 0;
>     }
3325a3331,3374
> }
> 
> /* ... Let's start the war. */
> /* env destructor in case of issetugid, security fix. */
> static void
> rtld_env_destroyer(char **env)
> {
>  ld_debug = NULL;
>  ld_library_path = NULL;
>  libmap_disable = 0;
>  libmap_override = NULL;
>  ld_preload = NULL;
>  rtld_unsetenv(LD_ "DEBUG", env);
>  rtld_unsetenv(LD_ "LIBRARY_PATH", env);
>  rtld_unsetenv(LD_ "LIBMAP_DISABLE", env);
>  rtld_unsetenv(LD_ "LIBMAP", env);
>  rtld_unsetenv(LD_ "PRELOAD", env);
>  return ;
> }
> 
> /* Thanks to OpenBSD */
> /* unset all var occurences from env */
> static void
> rtld_unsetenv(const char *var, char **env)
> {
>   char *ep;
> 
>   while ((ep = *env)) {
>     const char *vp = var;
> 
>     while (*vp && *vp == *ep) {
>       vp++;
>       ep++;
>     }
>     if (*vp == '\0' && *ep++ == '=') {
>       char **P;
> 
>       for (P = env;; ++P)
>       if (!(*P = *(P + 1)))
>         break;
>     } else
>       env++;
>   }
>   return ;

Hope it helps. Thx in advance.
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list