Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 4 Dec 2011 14:17:43 +0100
From:      joris dedieu <joris.dedieu@gmail.com>
To:        freebsd-hackers <freebsd-hackers@freebsd.org>
Subject:   Re: rtld and noexec
Message-ID:  <CAPd55qD%2B7PQ6vkc27%2BxQeeehJwCMG8x%2BqBxZ7sTit4i1M_yotQ@mail.gmail.com>
In-Reply-To: <20111202164157.3058d91d@kan.dyndns.org>
References:  <CAPd55qAoCttEbV8fkALDaFBc60jigfbu9=Uwa_%2BaECYaHFJpSw@mail.gmail.com> <20111202164157.3058d91d@kan.dyndns.org>

next in thread | previous in thread | raw e-mail | index | archive | help
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. =A0It's an easy way, I found, after the last root exploit
>> ((http://seclists.org/fulldisclosure/2011/Nov/452), =A0to enhance =A0the
>> security of my web servers (with /home, /tmp and /var/tmp mounted with
>> noexec).
>>
>> - the last ftpd/porftpd =A0(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 =A0 =A0 =A0 =A02011-12-02 12:09:40.0000=
00000
>> +0100 +++ libexec/rtld-elf/rtld.c =A0 =A0 2011-12-02 13:45:18.000000000
>> +0100 @@ -1123,32 +1123,50 @@
>> =A0{
>> =A0 =A0 =A0char *pathname;
>> =A0 =A0 =A0char *name;
>> + =A0 =A0struct statfs mnt;
>>
>> =A0 =A0 =A0if (strchr(xname, '/') !=3D NULL) { =A0/* Hard coded pathname=
 */
>> + =A0 =A0 =A0name =3D NULL;
>> =A0 =A0 =A0 =A0 if (xname[0] !=3D '/' && !trust) {
>> =A0 =A0 =A0 =A0 =A0 =A0 _rtld_error("Absolute pathname required for shar=
ed object
>> \"%s\"", xname);
>> =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> =A0 =A0 =A0 =A0 }
>> =A0 =A0 =A0 =A0 if (refobj !=3D NULL && refobj->z_origin)
>> - =A0 =A0 =A0 =A0 =A0 return origin_subst(xname, refobj->origin_path);
>> + =A0 =A0 =A0 =A0 =A0 pathname =3D origin_subst(xname, refobj->origin_pa=
th);
>> =A0 =A0 =A0 =A0 else
>> - =A0 =A0 =A0 =A0 =A0 return xstrdup(xname);
>> + =A0 =A0 =A0 =A0 =A0 pathname =3D xstrdup(xname);
>> + =A0 =A0}
>> + =A0 =A0else { /* xname is not a path */
>> + =A0 =A0 =A0 if (libmap_disable || (refobj =3D=3D NULL) ||
>> + =A0 =A0 =A0 =A0 =A0 (name =3D lm_find(refobj->path, xname)) =3D=3D NUL=
L)
>> + =A0 =A0 =A0 =A0 =A0 name =3D (char *)xname;
>> +
>> + =A0 =A0 =A0 dbg(" Searching for \"%s\"", name);
>> +
>> + =A0 =A0 =A0 pathname =3D search_library_path(name, ld_library_path);
>> + =A0 =A0 =A0 if (pathname =3D=3D NULL && refobj !=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0pathname =3D search_library_path(name, refobj->=
rpath);
>> + =A0 =A0 =A0 if (pathname =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0pathname =3D search_library_path(name, gethints=
());
>> + =A0 =A0 =A0 if (pathname =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0pathname =3D search_library_path(name,
>> STANDARD_LIBRARY_PATH);
>> + =A0 =A0}
>> +
>> + =A0 =A0if (pathname !=3D NULL) { /* noexec mountpoint in pathname */
>> + =A0 =A0 =A0 if (statfs(pathname, &mnt) !=3D 0)
>> + =A0 =A0 =A0 =A0 =A0 =A0free(pathname);
>> + =A0 =A0 =A0 else {
>> + =A0 =A0 =A0 =A0 =A0 =A0if (mnt.f_flags & MNT_NOEXEC) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0_rtld_error("noexec violation for shared ob=
ject
>> \"%s\"", pathname);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0free(pathname);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0return NULL;
>> + =A0 =A0 =A0 =A0 =A0 =A0}
>> + =A0 =A0 =A0 =A0 =A0 =A0else
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0return pathname;
>> + =A0 =A0 =A0 }
>> =A0 =A0 =A0}
>>
>> - =A0 =A0if (libmap_disable || (refobj =3D=3D NULL) ||
>> - =A0 =A0 =A0 (name =3D lm_find(refobj->path, xname)) =3D=3D NULL)
>> - =A0 =A0 =A0 name =3D (char *)xname;
>> -
>> - =A0 =A0dbg(" Searching for \"%s\"", name);
>> -
>> - =A0 =A0if ((pathname =3D search_library_path(name, ld_library_path)) !=
=3D
>> NULL ||
>> - =A0 =A0 =A0(refobj !=3D NULL &&
>> - =A0 =A0 =A0(pathname =3D search_library_path(name, refobj->rpath)) !=
=3D NULL)
>> ||
>> - =A0 =A0 =A0(pathname =3D search_library_path(name, gethints())) !=3D N=
ULL ||
>> - =A0 =A0 =A0(pathname =3D search_library_path(name,
>> STANDARD_LIBRARY_PATH)) !=3D NULL)
>> - =A0 =A0 =A0 return pathname;
>> -
>> =A0 =A0 =A0if(refobj !=3D NULL && refobj->path !=3D NULL) {
>> =A0 =A0 =A0 =A0 _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=3D/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 =3D dlopen("/tank/t/libmoo.so", RTLD_LAZY);
       if (! handle) {
               fprintf(stderr, "%s\n", dlerror());
               exit(1);
       }
       void (* moo) (void) =3D 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.


Joris
>
> --
> Alexander Kabaev



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAPd55qD%2B7PQ6vkc27%2BxQeeehJwCMG8x%2BqBxZ7sTit4i1M_yotQ>