2011/12/2 Alexander Kabaev <kab...@gmail.com>: > On Fri, 2 Dec 2011 18:22:57 +0100 > joris dedieu <joris.ded...@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. Joris > > -- > Alexander Kabaev _______________________________________________ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"