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>
next in thread | previous in thread | raw e-mail | index | archive | help
--vTAnc/q0mOWkBj2n Content-Type: text/plain; charset=koi8-r Content-Disposition: inline Content-Transfer-Encoding: quoted-printable 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. =9AIt's an easy way, I found, after the last root exploit > >> ((http://seclists.org/fulldisclosure/2011/Nov/452), =9Ato enhance =9At= he > >> security of my web servers (with /home, /tmp and /var/tmp mounted with > >> noexec). > >> > >> - the last ftpd/porftpd =9A(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 =9A =9A =9A =9A2011-12-02 12:09:40.00= 0000000 > >> +0100 +++ libexec/rtld-elf/rtld.c =9A =9A 2011-12-02 13:45:18.000000000 > >> +0100 @@ -1123,32 +1123,50 @@ > >> =9A{ > >> =9A =9A =9Achar *pathname; > >> =9A =9A =9Achar *name; > >> + =9A =9Astruct statfs mnt; > >> > >> =9A =9A =9Aif (strchr(xname, '/') !=3D NULL) { =9A/* Hard coded pathna= me */ > >> + =9A =9A =9Aname =3D NULL; > >> =9A =9A =9A =9A if (xname[0] !=3D '/' && !trust) { > >> =9A =9A =9A =9A =9A =9A _rtld_error("Absolute pathname required for sh= ared object > >> \"%s\"", xname); > >> =9A =9A =9A =9A =9A =9A return NULL; > >> =9A =9A =9A =9A } > >> =9A =9A =9A =9A if (refobj !=3D NULL && refobj->z_origin) > >> - =9A =9A =9A =9A =9A return origin_subst(xname, refobj->origin_path); > >> + =9A =9A =9A =9A =9A pathname =3D origin_subst(xname, refobj->origin_= path); > >> =9A =9A =9A =9A else > >> - =9A =9A =9A =9A =9A return xstrdup(xname); > >> + =9A =9A =9A =9A =9A pathname =3D xstrdup(xname); > >> + =9A =9A} > >> + =9A =9Aelse { /* xname is not a path */ > >> + =9A =9A =9A if (libmap_disable || (refobj =3D=3D NULL) || > >> + =9A =9A =9A =9A =9A (name =3D lm_find(refobj->path, xname)) =3D=3D N= ULL) > >> + =9A =9A =9A =9A =9A name =3D (char *)xname; > >> + > >> + =9A =9A =9A dbg(" Searching for \"%s\"", name); > >> + > >> + =9A =9A =9A pathname =3D search_library_path(name, ld_library_path); > >> + =9A =9A =9A if (pathname =3D=3D NULL && refobj !=3D NULL) > >> + =9A =9A =9A =9A =9A =9Apathname =3D search_library_path(name, refobj= ->rpath); > >> + =9A =9A =9A if (pathname =3D=3D NULL) > >> + =9A =9A =9A =9A =9A =9Apathname =3D search_library_path(name, gethin= ts()); > >> + =9A =9A =9A if (pathname =3D=3D NULL) > >> + =9A =9A =9A =9A =9A =9Apathname =3D search_library_path(name, > >> STANDARD_LIBRARY_PATH); > >> + =9A =9A} > >> + > >> + =9A =9Aif (pathname !=3D NULL) { /* noexec mountpoint in pathname */ > >> + =9A =9A =9A if (statfs(pathname, &mnt) !=3D 0) > >> + =9A =9A =9A =9A =9A =9Afree(pathname); > >> + =9A =9A =9A else { > >> + =9A =9A =9A =9A =9A =9Aif (mnt.f_flags & MNT_NOEXEC) { > >> + =9A =9A =9A =9A =9A =9A =9A_rtld_error("noexec violation for shared = object > >> \"%s\"", pathname); > >> + =9A =9A =9A =9A =9A =9A =9Afree(pathname); > >> + =9A =9A =9A =9A =9A =9A =9Areturn NULL; > >> + =9A =9A =9A =9A =9A =9A} > >> + =9A =9A =9A =9A =9A =9Aelse > >> + =9A =9A =9A =9A =9A =9A =9Areturn pathname; > >> + =9A =9A =9A } > >> =9A =9A =9A} > >> > >> - =9A =9Aif (libmap_disable || (refobj =3D=3D NULL) || > >> - =9A =9A =9A (name =3D lm_find(refobj->path, xname)) =3D=3D NULL) > >> - =9A =9A =9A name =3D (char *)xname; > >> - > >> - =9A =9Adbg(" Searching for \"%s\"", name); > >> - > >> - =9A =9Aif ((pathname =3D search_library_path(name, ld_library_path))= !=3D > >> NULL || > >> - =9A =9A =9A(refobj !=3D NULL && > >> - =9A =9A =9A(pathname =3D search_library_path(name, refobj->rpath)) != =3D NULL) > >> || > >> - =9A =9A =9A(pathname =3D search_library_path(name, gethints())) !=3D= NULL || > >> - =9A =9A =9A(pathname =3D search_library_path(name, > >> STANDARD_LIBRARY_PATH)) !=3D NULL) > >> - =9A =9A =9A return pathname; > >> - > >> =9A =9A =9Aif(refobj !=3D NULL && refobj->path !=3D NULL) { > >> =9A =9A =9A =9A _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 ? >=20 > > 2. We already have the check in do_load_object > It doesn't work with dlopen. >=20 > mount |grep tank/t > tank/t on /tank/t (zfs, local, noexec, nfsv4acls) >=20 > so /tank/t is noexec >=20 > Here the powerful libmoo source code : >=20 > void say_moo() { > printf("mooooooooooooooooo\n"); > } >=20 > it's in /tank/t so noexec >=20 > ls -l /tank/t/ > total 6 > -rwxr-xr-x 1 joris joris 4632 Dec 4 13:52 libmoo.so >=20 > 1) First test with : >=20 > main() { > say_moo(); > } >=20 > LD_LIBRARY_PATH=3D/tank/t ./test_moo > /libexec/ld-elf.so.1: Cannot execute objects on /tank/t >=20 > Ok cool work has expected. >=20 > Second test with : >=20 > 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); > } >=20 > ./test_moo > mooooooooooooooooo >=20 > 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. --vTAnc/q0mOWkBj2n Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.18 (FreeBSD) iEYEARECAAYFAk7bq2EACgkQC3+MBN1Mb4ibhACbBNS8aLZJZjDoxbCTLH+tgRnQ 4U4An3t/Owe0k5gK3w1hwZm1/mrWjEyF =4WPM -----END PGP SIGNATURE----- --vTAnc/q0mOWkBj2n--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20111204171825.GE50300>