For b/4074041, add EXEC_ORIGIN support. Forward-ported from cl/56955623 and http://cl/59961863.

This commit is contained in:
Paul Pluzhnikov 2014-03-08 15:12:52 -08:00
parent 21c2ca10b1
commit 502932b7f5
5 changed files with 110 additions and 3 deletions

View File

@ -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); \
} \

View File

@ -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)
{

View File

@ -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;

View File

@ -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

View File

@ -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). */