mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-04 19:00:09 +00:00
For b/4074041, add EXEC_ORIGIN support. Forward-ported from cl/56955623 and http://cl/59961863.
This commit is contained in:
parent
21c2ca10b1
commit
502932b7f5
@ -65,8 +65,13 @@
|
||||
else \
|
||||
dst_len = (l)->l_origin == (char *) -1 \
|
||||
? 0 : strlen ((l)->l_origin); \
|
||||
dst_len = MAX (MAX (dst_len, GLRO(dl_platformlen)), \
|
||||
strlen (DL_DST_LIB)); \
|
||||
\
|
||||
char *exec_origin = GLRO(google_exec_origin_dir); \
|
||||
size_t exec_origin_len = \
|
||||
(exec_origin == NULL) ? 0 : strlen (exec_origin); \
|
||||
\
|
||||
dst_len = MAX (MAX (MAX (dst_len, GLRO(dl_platformlen)), \
|
||||
strlen (DL_DST_LIB)), exec_origin_len); \
|
||||
if (dst_len > 4) \
|
||||
__len += __cnt * (dst_len - 4); \
|
||||
} \
|
||||
|
@ -232,7 +232,8 @@ _dl_dst_count (const char *name)
|
||||
++name;
|
||||
if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0
|
||||
|| (len = is_dst (start, name, "PLATFORM", 0)) != 0
|
||||
|| (len = is_dst (start, name, "LIB", 0)) != 0)
|
||||
|| (len = is_dst (start, name, "LIB", 0)) != 0
|
||||
|| (len = is_dst (start, name, "EXEC_ORIGIN", 0)) != 0)
|
||||
++cnt;
|
||||
|
||||
name = strchr (name + len, '$');
|
||||
@ -274,6 +275,13 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result)
|
||||
repl = GLRO(dl_platform);
|
||||
else if ((len = is_dst (start, name, "LIB", 0)) != 0)
|
||||
repl = DL_DST_LIB;
|
||||
else if ((len = is_dst (start, name, "EXEC_ORIGIN", is_path, 0)) != 0)
|
||||
{
|
||||
if (INTUSE(__libc_enable_secure) != 0)
|
||||
_dl_fatal_printf ("$EXEC_ORIGIN rpath entry not allowed in setuid/setgid executables.\n");
|
||||
|
||||
repl = GLRO(google_exec_origin_dir);
|
||||
}
|
||||
|
||||
if (repl != NULL && repl != (const char *) -1)
|
||||
{
|
||||
|
@ -67,6 +67,9 @@ void *__libc_stack_end;
|
||||
/* Path where the binary is found. */
|
||||
const char *_dl_origin_path;
|
||||
|
||||
/* Directory where the AT_EXECFN is found. */
|
||||
const char *_google_exec_origin_dir;
|
||||
|
||||
/* Nonzero if runtime lookup should not update the .got/.plt. */
|
||||
int _dl_bind_not;
|
||||
|
||||
|
88
elf/rtld.c
88
elf/rtld.c
@ -51,6 +51,12 @@ extern __typeof (__mempcpy) __mempcpy attribute_hidden;
|
||||
extern __typeof (_exit) exit_internal asm ("_exit") attribute_hidden;
|
||||
#define _exit exit_internal
|
||||
|
||||
/* Iterate over auxv, find AT_EXECFN if any. */
|
||||
static char * get_at_execfn(ElfW(auxv_t) *auxv);
|
||||
|
||||
/* Given file path, return fully resolved directory path. */
|
||||
static char * get_directory (const char *file_path);
|
||||
|
||||
/* Helper function to handle errors while resolving symbols. */
|
||||
static void print_unresolved (int errcode, const char *objname,
|
||||
const char *errsting);
|
||||
@ -73,6 +79,9 @@ enum mode { normal, list, verify, trace };
|
||||
all the entries. */
|
||||
static void process_envvars (enum mode *modep);
|
||||
|
||||
/* Set GLRO(google_exec_origin_dir). */
|
||||
static void set_exec_origin_dir(const char *exe_path);
|
||||
|
||||
#ifdef DL_ARGV_NOT_RELRO
|
||||
int _dl_argc attribute_hidden;
|
||||
char **_dl_argv = NULL;
|
||||
@ -1032,6 +1041,8 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
in LIST\n\
|
||||
--audit LIST use objects named in LIST as auditors\n");
|
||||
|
||||
set_exec_origin_dir (INTUSE(_dl_argv)[1]);
|
||||
|
||||
++_dl_skip_args;
|
||||
--_dl_argc;
|
||||
++_dl_argv;
|
||||
@ -1126,6 +1137,8 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
}
|
||||
else
|
||||
{
|
||||
set_exec_origin_dir (get_at_execfn (auxv));
|
||||
|
||||
/* Create a link_map for the executable itself.
|
||||
This will be what dlopen on "" returns. */
|
||||
main_map = _dl_new_object ((char *) "", "", lt_executable, NULL,
|
||||
@ -2811,6 +2824,81 @@ print_statistics (hp_timing_t *rtld_total_timep)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Given file path, return an absolute directory path.
|
||||
Examples: in: "/foo/bar/a.out", out: "/foo/bar/";
|
||||
in: "./a.out", out: "/dot/resolved/to/full/path/./". */
|
||||
static char *
|
||||
get_directory (const char *file_path)
|
||||
{
|
||||
assert (file_path != NULL);
|
||||
|
||||
/* Find the end of the directory substring in file_path. */
|
||||
size_t path_len = strlen (file_path);
|
||||
while (path_len > 0 && file_path[path_len - 1] != '/')
|
||||
--path_len;
|
||||
|
||||
/* Allocate space and set the path prefix according to whether or not
|
||||
this is an absolute path. */
|
||||
char *dest;
|
||||
char *full_dir_path;
|
||||
if (file_path[0] == '/')
|
||||
{
|
||||
full_dir_path = malloc (path_len + 1);
|
||||
assert (full_dir_path != NULL);
|
||||
dest = full_dir_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For a relative path, we need to include space for the largest
|
||||
possible current path, a joining '/', the relevant part of
|
||||
file_path, and a trailing '\0'. */
|
||||
full_dir_path = malloc (PATH_MAX + path_len + 2);
|
||||
assert (full_dir_path != NULL);
|
||||
|
||||
char *status = __getcwd (full_dir_path, PATH_MAX);
|
||||
assert (status != NULL);
|
||||
|
||||
dest = __rawmemchr (full_dir_path, '\0');
|
||||
if (dest[-1] != '/')
|
||||
*dest++ = '/';
|
||||
}
|
||||
|
||||
if (path_len > 0)
|
||||
dest = __mempcpy (dest, file_path, path_len);
|
||||
*dest = '\0';
|
||||
|
||||
/* Confirm that the constructed path is valid. */
|
||||
struct stat64 st;
|
||||
assert (__xstat64 (_STAT_VER, full_dir_path, &st) == 0);
|
||||
|
||||
return full_dir_path;
|
||||
}
|
||||
|
||||
/* Set GLRO(google_exec_origin_dir). */
|
||||
static void
|
||||
set_exec_origin_dir (const char *exe_path)
|
||||
{
|
||||
assert (GLRO(google_exec_origin_dir) == NULL);
|
||||
|
||||
if (GLRO(dl_origin_path) != NULL)
|
||||
GLRO(google_exec_origin_dir) = strdup (GLRO(dl_origin_path));
|
||||
else if (exe_path != NULL)
|
||||
GLRO(google_exec_origin_dir) = get_directory (exe_path);
|
||||
}
|
||||
|
||||
/* Iterate over auxv, find AT_EXECFN if any. */
|
||||
static char *
|
||||
get_at_execfn (ElfW(auxv_t) *auxv)
|
||||
{
|
||||
assert (auxv != NULL);
|
||||
|
||||
for (; auxv->a_type != AT_NULL; ++auxv)
|
||||
if (auxv->a_type == AT_EXECFN)
|
||||
return (char *) auxv->a_un.a_val;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef NESTING
|
||||
char *dummy1 = (char *)elf_get_dynamic_info;
|
||||
# if ! ELF_MACHINE_NO_REL
|
||||
|
@ -544,6 +544,9 @@ struct rtld_global_ro
|
||||
/* Location of the binary. */
|
||||
EXTERN const char *_dl_origin_path;
|
||||
|
||||
/* Directory where the AT_EXECFN is found. */
|
||||
EXTERN const char *_google_exec_origin_dir;
|
||||
|
||||
/* -1 if the dynamic linker should honor library load bias,
|
||||
0 if not, -2 use the default (honor biases for normal
|
||||
binaries, don't honor for PIEs). */
|
||||
|
Loading…
Reference in New Issue
Block a user