From owner-freebsd-hackers@FreeBSD.ORG Sun Dec 4 13:17:44 2011 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 61ADF106566B for ; Sun, 4 Dec 2011 13:17:44 +0000 (UTC) (envelope-from joris.dedieu@gmail.com) Received: from mail-qw0-f47.google.com (mail-qw0-f47.google.com [209.85.216.47]) by mx1.freebsd.org (Postfix) with ESMTP id 24DFA8FC08 for ; Sun, 4 Dec 2011 13:17:43 +0000 (UTC) Received: by qadb17 with SMTP id b17so1126543qad.13 for ; Sun, 04 Dec 2011 05:17:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; bh=qBUhklPLqhOsZ6NrIVbHRF4p45Lg4W/Jfp3mLd2A5Do=; b=eOjmeS+hkg4Sz7dU/UKeaDAwVpokCBVtS0KmClnOZaeY3DS+m8JzSkusyhzNkSwAFx ByPGWBVWV2xOCZVg4gdlF9rIZ7eIPxV6/afDTzDEFuKVEMNi3Sk3FSsoWN8Nn8/HQtJ9 CvHXGVS2Eqn4jRuVGfT79TeSuCyz4WiNIO9c0= MIME-Version: 1.0 Received: by 10.224.116.144 with SMTP id m16mr4652349qaq.19.1323004663367; Sun, 04 Dec 2011 05:17:43 -0800 (PST) Received: by 10.229.93.211 with HTTP; Sun, 4 Dec 2011 05:17:43 -0800 (PST) In-Reply-To: <20111202164157.3058d91d@kan.dyndns.org> References: <20111202164157.3058d91d@kan.dyndns.org> Date: Sun, 4 Dec 2011 14:17:43 +0100 Message-ID: From: joris dedieu To: freebsd-hackers Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Subject: Re: rtld and noexec X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 04 Dec 2011 13:17:44 -0000 2011/12/2 Alexander Kabaev : > On Fri, 2 Dec 2011 18:22:57 +0100 > joris dedieu 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