From patchwork Tue Nov 10 00:20:43 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roland McGrath X-Patchwork-Id: 9622 Received: (qmail 84893 invoked by alias); 10 Nov 2015 00:20:49 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 84877 invoked by uid 89); 10 Nov 2015 00:20:48 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.7 required=5.0 tests=AWL, BAYES_00, KAM_LAZY_DOMAIN_SECURITY autolearn=no version=3.3.2 X-HELO: topped-with-meat.com MIME-Version: 1.0 From: Roland McGrath To: "GNU C. Library" Subject: [PATCH roland/nacl-open-resource] NaCl: Use open_resource API for shared objects Message-Id: <20151110002043.CB3782C3B1E@topped-with-meat.com> Date: Mon, 9 Nov 2015 16:20:43 -0800 (PST) X-CMAE-Score: 0 X-CMAE-Analysis: v=2.1 cv=RZ8DVTdv c=1 sm=1 tr=0 a=WkljmVdYkabdwxfqvArNOQ==:117 a=14OXPxybAAAA:8 a=hOe2yjtxAAAA:8 a=kj9zAlcOel0A:10 a=mDV3o1hIAAAA:8 a=nZScxM_h1d7f-ItsW_sA:9 a=CjuIK1q_8ugA:10 This is necessary for arm-nacl applications to load their libraries in the normal NaCl deployment model in the web browser. It's user-visible in the sense that this didn't work before, but there is no bugzilla item because no NaCl users actually encountered the problem yet (nobody really tried using arm-nacl glibc in the browser before now). I've verified on x86_64-linux-gnu that this does not change the compiled code meaningfully. (In fact, the code itself is wholly unchanged, though the local symbols are substantially different because the compiler did a lot of fancy optimization to turn this change back into a no-op.) If there are no objections, I'll put this on both trunk and 2.22 on Tuesday. Thanks, Roland 2015-11-09 Roland McGrath * elf/dl-load.c (open_verify): Take new argument FD. Skip __open call if passed FD is not -1. (_dl_map_object, open_path): Update callers. * elf/dl-sysdep-open.h: New file. * elf/dl-load.c: Include it. (_dl_map_object): Try _dl_sysdep_open_object before ldconfig cache. * sysdeps/nacl/dl-sysdep.c (_dl_sysdep_open_object): New function. * sysdeps/nacl/dl-sysdep-open.h: New file. * sysdeps/nacl/nacl-interface-list.h: Move nacl_irt_resource_open from libc to rtld. diff --git a/elf/dl-load.c b/elf/dl-load.c index c5e948e..6fb615e 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -1483,9 +1484,13 @@ print_search_path (struct r_search_path_elem **list, ignore only ELF files for other architectures. Non-ELF files and ELF files with different header information cause fatal errors since this could mean there is something wrong in the installation and the - user might want to know about this. */ + user might want to know about this. + + If FD is not -1, then the file is already open and FD refers to it. + In that case, FD is consumed for both successful and error returns. */ static int -open_verify (const char *name, struct filebuf *fbp, struct link_map *loader, +open_verify (const char *name, int fd, + struct filebuf *fbp, struct link_map *loader, int whatcode, int mode, bool *found_other_class, bool free_name) { /* This is the expected ELF header. */ @@ -1526,6 +1531,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader, if (__glibc_unlikely (GLRO(dl_naudit) > 0) && whatcode != 0 && loader->l_auditing == 0) { + const char *original_name = name; struct audit_ifaces *afct = GLRO(dl_audit); for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) { @@ -1540,11 +1546,21 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader, afct = afct->next; } + + if (fd != -1 && name != original_name && strcmp (name, original_name)) + { + /* An audit library changed what we're supposed to open, + so FD no longer matches it. */ + __close (fd); + fd = -1; + } } #endif - /* Open the file. We always open files read-only. */ - int fd = __open (name, O_RDONLY | O_CLOEXEC); + if (fd == -1) + /* Open the file. We always open files read-only. */ + fd = __open (name, O_RDONLY | O_CLOEXEC); + if (fd != -1) { ElfW(Ehdr) *ehdr; @@ -1813,7 +1829,7 @@ open_path (const char *name, size_t namelen, int mode, if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) _dl_debug_printf (" trying file=%s\n", buf); - fd = open_verify (buf, fbp, loader, whatcode, mode, + fd = open_verify (buf, -1, fbp, loader, whatcode, mode, found_other_class, false); if (this_dir->status[cnt] == unknown) { @@ -2064,6 +2080,20 @@ _dl_map_object (struct link_map *loader, const char *name, &loader->l_runpath_dirs, &realname, &fb, loader, LA_SER_RUNPATH, &found_other_class); + if (fd == -1) + { + realname = _dl_sysdep_open_object (name, namelen, &fd); + if (realname != NULL) + { + fd = open_verify (realname, fd, + &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, + LA_SER_CONFIG, mode, &found_other_class, + false); + if (fd == -1) + free (realname); + } + } + #ifdef USE_LDCONFIG if (fd == -1 && (__glibc_likely ((mode & __RTLD_SECURE) == 0) @@ -2109,7 +2139,7 @@ _dl_map_object (struct link_map *loader, const char *name, if (cached != NULL) { - fd = open_verify (cached, + fd = open_verify (cached, -1, &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, LA_SER_CONFIG, mode, &found_other_class, false); @@ -2144,7 +2174,7 @@ _dl_map_object (struct link_map *loader, const char *name, fd = -1; else { - fd = open_verify (realname, &fb, + fd = open_verify (realname, -1, &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode, &found_other_class, true); if (__glibc_unlikely (fd == -1)) diff --git a/elf/dl-sysdep-open.h b/elf/dl-sysdep-open.h new file mode 100644 index 0000000..a63d9f5 --- /dev/null +++ b/elf/dl-sysdep-open.h @@ -0,0 +1,45 @@ +/* System-specific call to open a shared object by name. Stub version. + Copyright (C) 2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _DL_SYSDEP_OPEN_H +#define _DL_SYSDEP_OPEN_H 1 + +#include +#include + +/* NAME is a name without slashes, as it appears in a DT_NEEDED entry + or a dlopen call's argument or suchlike. NAMELEN is (strlen (NAME) + 1). + + Find NAME in an OS-dependent fashion, and return its "real" name. + Optionally fill in *FD with a file descriptor open on that file (or + else leave its initial value of -1). The return value is a new + malloc'd string, which will be free'd by the caller. If NAME is + resolved to an actual file that can be opened, then the return + value should name that file (and if *FD was not set, then a normal + __open call on that string will be made). If *FD was set by some + other means than a normal open and there is no "real" name to use, + then __strdup (NAME) is fine (modulo error checking). */ + +static inline char * +_dl_sysdep_open_object (const char *name, size_t namelen, int *fd) +{ + assert (*fd == -1); + return NULL; +} + +#endif /* dl-sysdep-open.h */ diff --git a/sysdeps/nacl/dl-sysdep-open.h b/sysdeps/nacl/dl-sysdep-open.h new file mode 100644 index 0000000..38b0f9e --- /dev/null +++ b/sysdeps/nacl/dl-sysdep-open.h @@ -0,0 +1,40 @@ +/* System-specific call to open a shared object by name. NaCl version. + Copyright (C) 2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _DL_SYSDEP_OPEN_H +#define _DL_SYSDEP_OPEN_H 1 + +#include + +/* NAME is a name without slashes, as it appears in a DT_NEEDED entry + or a dlopen call's argument or suchlike. NAMELEN is (strlen (NAME) + 1). + + Find NAME in an OS-dependent fashion, and return its "real" name. + Optionally fill in *FD with a file descriptor open on that file (or + else leave its initial value of -1). The return value is a new + malloc'd string, which will be free'd by the caller. If NAME is + resolved to an actual file that can be opened, then the return + value should name that file (and if *FD was not set, then a normal + __open call on that string will be made). If *FD was set by some + other means than a normal open and there is no "real" name to use, + then __strdup (NAME) is fine (modulo error checking). */ + +extern char *_dl_sysdep_open_object (const char *name, size_t namelen, int *fd) + internal_function attribute_hidden; + +#endif /* dl-sysdep-open.h */ diff --git a/sysdeps/nacl/dl-sysdep.c b/sysdeps/nacl/dl-sysdep.c index 3e902c2..3a04aa1 100644 --- a/sysdeps/nacl/dl-sysdep.c +++ b/sysdeps/nacl/dl-sysdep.c @@ -87,3 +87,26 @@ _dl_start_user (void (*user_entry) (uint32_t info[]), uint32_t info[]) #endif /* SHARED */ #include + +#include +#include +#include +#include +#include + +char * +internal_function +_dl_sysdep_open_object (const char *name, size_t namelen, int *fd) +{ + int error = __nacl_irt_resource_open.open_resource (name, fd); + if (error) + return NULL; + assert (*fd != -1); + char *realname = __strdup (name); + if (__glibc_unlikely (realname == NULL)) + { + __close (*fd); + *fd = -1; + } + return realname; +} diff --git a/sysdeps/nacl/nacl-interface-list.h b/sysdeps/nacl/nacl-interface-list.h index cb33751..c68faed 100644 --- a/sysdeps/nacl/nacl-interface-list.h +++ b/sysdeps/nacl/nacl-interface-list.h @@ -28,7 +28,7 @@ NACL_MANDATORY_INTERFACE (rtld, NACL_IRT_FUTEX_v0_1, nacl_irt_futex) NACL_MANDATORY_INTERFACE (rtld, NACL_IRT_TLS_v0_1, nacl_irt_tls) -NACL_MANDATORY_INTERFACE (libc, +NACL_MANDATORY_INTERFACE (rtld, NACL_IRT_RESOURCE_OPEN_v0_1, nacl_irt_resource_open) NACL_MANDATORY_INTERFACE (rtld, NACL_IRT_CODE_DATA_ALLOC_v0_1,