rtld and noexec
joris dedieu
joris.dedieu at gmail.com
Fri Dec 2 17:49:50 UTC 2011
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));
More information about the freebsd-hackers
mailing list