Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 4 Dec 2011 19:18:25 +0200
From:      Kostik Belousov <kostikbel@gmail.com>
To:        joris dedieu <joris.dedieu@gmail.com>
Cc:        freebsd-hackers <freebsd-hackers@freebsd.org>
Subject:   Re: rtld and noexec
Message-ID:  <20111204171825.GE50300@deviant.kiev.zoral.com.ua>
In-Reply-To: <CAPd55qD%2B7PQ6vkc27%2BxQeeehJwCMG8x%2BqBxZ7sTit4i1M_yotQ@mail.gmail.com>
References:  <CAPd55qAoCttEbV8fkALDaFBc60jigfbu9=Uwa_%2BaECYaHFJpSw@mail.gmail.com> <20111202164157.3058d91d@kan.dyndns.org> <CAPd55qD%2B7PQ6vkc27%2BxQeeehJwCMG8x%2BqBxZ7sTit4i1M_yotQ@mail.gmail.com>

index | next in thread | previous in thread | raw e-mail

[-- Attachment #1 --]
On Sun, Dec 04, 2011 at 02:17:43PM +0100, joris dedieu wrote:
> 2011/12/2 Alexander Kabaev <kabaev@gmail.com>:
> > On Fri, 2 Dec 2011 18:22:57 +0100
> > joris dedieu <joris.dedieu@gmail.com> wrote:
> >
> >> Hi,
> >>
> >> Here is a patch I use to prevent loading a shared object from a noexec
> >> mountpoint. šIt's an easy way, I found, after the last root exploit
> >> ((http://seclists.org/fulldisclosure/2011/Nov/452), što enhance šthe
> >> security of my web servers (with /home, /tmp and /var/tmp mounted with
> >> noexec).
> >>
> >> - the last ftpd/porftpd š(libc ?) exploit does not work (indirect use
> >> of rtld via nsswitch)
> >> - the previous rtld security issue should have been more difficult to
> >> use in a noexec context.
> >> - It may help to prevent some miscellaneous usage of common softwares
> >> using dlopen like apache or php.
> >>
> >> I think it also makes sens because loading a shared object sounds like
> >> a kind of "execution".
> >>
> >> What do you think about this patch and the opportunity to open a PR on
> >> this subject?
> >>
> >> Cheers
> >> Joris
> >>
> >>
> >> --- libexec/rtld-elf/rtld.c.orig š š š š2011-12-02 12:09:40.000000000
> >> +0100 +++ libexec/rtld-elf/rtld.c š š 2011-12-02 13:45:18.000000000
> >> +0100 @@ -1123,32 +1123,50 @@
> >> š{
> >> š š šchar *pathname;
> >> š š šchar *name;
> >> + š šstruct statfs mnt;
> >>
> >> š š šif (strchr(xname, '/') != NULL) { š/* Hard coded pathname */
> >> + š š šname = NULL;
> >> š š š š if (xname[0] != '/' && !trust) {
> >> š š š š š š _rtld_error("Absolute pathname required for shared object
> >> \"%s\"", xname);
> >> š š š š š š return NULL;
> >> š š š š }
> >> š š š š if (refobj != NULL && refobj->z_origin)
> >> - š š š š š return origin_subst(xname, refobj->origin_path);
> >> + š š š š š pathname = origin_subst(xname, refobj->origin_path);
> >> š š š š else
> >> - š š š š š return xstrdup(xname);
> >> + š š š š š pathname = xstrdup(xname);
> >> + š š}
> >> + š šelse { /* xname is not a path */
> >> + š š š if (libmap_disable || (refobj == NULL) ||
> >> + š š š š š (name = lm_find(refobj->path, xname)) == NULL)
> >> + š š š š š name = (char *)xname;
> >> +
> >> + š š š dbg(" Searching for \"%s\"", name);
> >> +
> >> + š š š pathname = search_library_path(name, ld_library_path);
> >> + š š š if (pathname == NULL && refobj != NULL)
> >> + š š š š š špathname = search_library_path(name, refobj->rpath);
> >> + š š š if (pathname == NULL)
> >> + š š š š š špathname = search_library_path(name, gethints());
> >> + š š š if (pathname == NULL)
> >> + š š š š š špathname = search_library_path(name,
> >> STANDARD_LIBRARY_PATH);
> >> + š š}
> >> +
> >> + š šif (pathname != NULL) { /* noexec mountpoint in pathname */
> >> + š š š if (statfs(pathname, &mnt) != 0)
> >> + š š š š š šfree(pathname);
> >> + š š š else {
> >> + š š š š š šif (mnt.f_flags & MNT_NOEXEC) {
> >> + š š š š š š š_rtld_error("noexec violation for shared object
> >> \"%s\"", pathname);
> >> + š š š š š š šfree(pathname);
> >> + š š š š š š šreturn NULL;
> >> + š š š š š š}
> >> + š š š š š šelse
> >> + š š š š š š šreturn pathname;
> >> + š š š }
> >> š š š}
> >>
> >> - š šif (libmap_disable || (refobj == NULL) ||
> >> - š š š (name = lm_find(refobj->path, xname)) == NULL)
> >> - š š š name = (char *)xname;
> >> -
> >> - š šdbg(" Searching for \"%s\"", name);
> >> -
> >> - š šif ((pathname = search_library_path(name, ld_library_path)) !=
> >> NULL ||
> >> - š š š(refobj != NULL &&
> >> - š š š(pathname = search_library_path(name, refobj->rpath)) != NULL)
> >> ||
> >> - š š š(pathname = search_library_path(name, gethints())) != NULL ||
> >> - š š š(pathname = search_library_path(name,
> >> STANDARD_LIBRARY_PATH)) != NULL)
> >> - š š š return pathname;
> >> -
> >> š š šif(refobj != NULL && refobj->path != NULL) {
> >> š š š š _rtld_error("Shared object \"%s\" not found, required by
> >> \"%s\"", name, basename(refobj->path));
> >> _______________________________________________
> >
> >
> > 1. There is a race using statfs and then loading the file.
> I will look at this point. Maybe statfs on the dirname ?
> 
> > 2. We already have the check in  do_load_object
> It doesn't work with dlopen.
> 
> mount  |grep tank/t
> tank/t on /tank/t (zfs, local, noexec, nfsv4acls)
> 
> so /tank/t is noexec
> 
> Here the powerful libmoo source code :
> 
> void say_moo() {
>        printf("mooooooooooooooooo\n");
> }
> 
> it's in /tank/t so noexec
> 
> ls -l /tank/t/
> total 6
> -rwxr-xr-x  1 joris  joris  4632 Dec  4 13:52 libmoo.so
> 
> 1) First test with :
> 
> main() {
>        say_moo();
> }
> 
> LD_LIBRARY_PATH=/tank/t ./test_moo
> /libexec/ld-elf.so.1: Cannot execute objects on /tank/t
> 
> Ok cool work has expected.
> 
> Second test with :
> 
> main() {
>        void * handle = dlopen("/tank/t/libmoo.so", RTLD_LAZY);
>        if (! handle) {
>                fprintf(stderr, "%s\n", dlerror());
>                exit(1);
>        }
>        void (* moo) (void) = dlsym (handle, "say_moo");
>        (* moo)();
>        dlclose (handle);
> }
> 
> ./test_moo
> mooooooooooooooooo
> 
> Protection is not working when you use dlopen. This is what append
> with ftpd exploit . libc just load a shared object and the guy is
> root.

If you started to change rtld code, it pays to read it first.
The first example worked only because you used LD_LIBRARY_PATH.
See r144062. It has nothing to do with dlopen/static linking.

I do not think you patch is a right thing to do. noexec check
is a hack anyway, because noexec _mount_ option is only there to
globally disable execve(2) from the mount point, and not to disable
mapping with PROT_EXEC. rtld does not provide any magic from the
kernel POV, so purposive person can re-implement it at will in her
code.

[-- Attachment #2 --]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.18 (FreeBSD)

iEYEARECAAYFAk7bq2EACgkQC3+MBN1Mb4ibhACbBNS8aLZJZjDoxbCTLH+tgRnQ
4U4An3t/Owe0k5gK3w1hwZm1/mrWjEyF
=4WPM
-----END PGP SIGNATURE-----
home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20111204171825.GE50300>