Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:maxrd2:deps:toolkit
AppImageKit
preload.c
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File preload.c of Package AppImageKit
/* -*- Mode: C; indent-tabs-mode: nil; tab-width: 4 -*- * * Copyright (C) 2015 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define _GNU_SOURCE #define __USE_GNU #include <dirent.h> #include <dlfcn.h> #include <errno.h> #include <fcntl.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/inotify.h> #include <sys/socket.h> #include <sys/statvfs.h> #include <sys/un.h> #include <sys/vfs.h> #include <unistd.h> #define LD_PRELOAD "LD_PRELOAD" #define SNAPPY_PRELOAD "SNAPPY_PRELOAD" static char **saved_ld_preloads = NULL; static size_t num_saved_ld_preloads = 0; static char *saved_snappy_preload = NULL; static char *saved_tmpdir = NULL; static char *saved_varlib = NULL; static void constructor() __attribute__((constructor)); static char * getenvdup (const char *varname) { char *envvar = secure_getenv (varname); if (envvar == NULL || envvar[0] == 0) // identical for our purposes return NULL; else return strdup (envvar); } void constructor() { char *ld_preload_copy, *p, *savedptr = NULL; size_t libnamelen; // We need to save LD_PRELOAD and SNAPPY_PRELOAD in case we need to // propagate the values to an exec'd program. ld_preload_copy = getenvdup (LD_PRELOAD); if (ld_preload_copy == NULL) { return; } saved_snappy_preload = getenvdup (SNAPPY_PRELOAD); if (saved_snappy_preload == NULL) { free (ld_preload_copy); return; } saved_tmpdir = getenvdup ("SNAP_APP_TMPDIR"); if (!saved_tmpdir) { saved_tmpdir = getenvdup ("TMPDIR"); } saved_varlib = getenvdup ("SNAP_APP_DATA_PATH"); if (!saved_varlib) { saved_varlib = getenvdup ("SNAPP_APP_DATA_PATH"); } // Pull out each absolute-pathed libsnappypreload.so we find. Better to // accidentally include some other libsnappypreload than not propagate // ourselves. libnamelen = strlen (SNAPPY_LIBNAME); for (p = strtok_r (ld_preload_copy, " :", &savedptr); p; p = strtok_r (NULL, " :", &savedptr)) { size_t plen = strlen (p); if (plen > libnamelen && p[0] == '/' && strcmp (p + strlen (p) - strlen (SNAPPY_LIBNAME) - 1, "/" SNAPPY_LIBNAME) == 0) { num_saved_ld_preloads++; saved_ld_preloads = realloc (saved_ld_preloads, (num_saved_ld_preloads + 1) * sizeof (char *)); saved_ld_preloads[num_saved_ld_preloads - 1] = strdup (p); saved_ld_preloads[num_saved_ld_preloads] = NULL; } } free (ld_preload_copy); } static char * redirect_writable_path (const char *pathname, const char *basepath) { char *redirected_pathname; int chop = 0; if (pathname[0] == 0) { return strdup (basepath); } redirected_pathname = malloc (PATH_MAX); if (basepath[strlen (basepath) - 1] == '/') { chop = 1; } strncpy (redirected_pathname, basepath, PATH_MAX - 1 - chop); strncat (redirected_pathname, pathname, PATH_MAX - 1 - strlen (redirected_pathname)); // No need to see if it already exists -- app can only be in TMPDIR, not /tmp return redirected_pathname; } static char * redirect_path_full (const char *pathname, int check_parent, int only_if_absolute) { int (*_access) (const char *pathname, int mode); char *redirected_pathname; char *preload_dir; int ret; int chop = 0; char *slash = 0; if (pathname == NULL) { return NULL; } preload_dir = saved_snappy_preload; if (preload_dir == NULL) { return strdup (pathname); } // Do not redirect when accessing /dev if (strcmp (pathname, "/dev") == 0 || strncmp (pathname, "/dev/", 5) == 0) { return strdup (pathname); } if (only_if_absolute && pathname[0] != '/') { return strdup (pathname); } // Sometimes programs will hardcode /tmp (like Xorg does for its lock file). // In that case, let's redirect to TMPDIR. if (strcmp (pathname, "/tmp") == 0 || strncmp (pathname, "/tmp/", 5) == 0) { if (saved_tmpdir && strncmp (pathname, saved_tmpdir, strlen (saved_tmpdir)) != 0) { return redirect_writable_path (pathname + 4, saved_tmpdir); } else { return strdup (pathname); } } _access = (int (*)(const char *pathname, int mode)) dlsym (RTLD_NEXT, "access"); // And each app should have its own /var/lib writable tree. Here, we want // to support reading the base system's files if they exist, else let the app // play in /var/lib themselves. So we reverse the normal check: first see if // it exists in root, else do our redirection. if (strcmp (pathname, "/var/lib") == 0 || strncmp (pathname, "/var/lib/", 9) == 0) { if (saved_varlib && strncmp (pathname, saved_varlib, strlen (saved_varlib)) != 0 && _access (pathname, F_OK) != 0) { return redirect_writable_path (pathname + 8, saved_varlib); } else { return strdup (pathname); } } redirected_pathname = malloc (PATH_MAX); if (preload_dir[strlen (preload_dir) - 1] == '/') { chop = 1; } strncpy (redirected_pathname, preload_dir, PATH_MAX - 1 - chop); if (pathname[0] != '/') { size_t cursize = strlen (redirected_pathname); if (getcwd (redirected_pathname + cursize, PATH_MAX - cursize) == NULL) { free (redirected_pathname); return strdup (pathname); } strncat (redirected_pathname, "/", PATH_MAX - 1 - strlen (redirected_pathname)); } strncat (redirected_pathname, pathname, PATH_MAX - 1 - strlen (redirected_pathname)); if (check_parent) { slash = strrchr (redirected_pathname, '/'); if (slash) { // should always be true *slash = 0; } } ret = _access (redirected_pathname, F_OK); if (check_parent && slash) { *slash = '/'; } if (ret == 0 || errno == ENOTDIR) { // ENOTDIR is OK because it exists at least return redirected_pathname; } else { free (redirected_pathname); return strdup (pathname); } } static char * redirect_path (const char *pathname) { return redirect_path_full (pathname, 0, 0); } static char * redirect_path_target (const char *pathname) { return redirect_path_full (pathname, 1, 0); } static char * redirect_path_if_absolute (const char *pathname) { return redirect_path_full (pathname, 0, 1); } #define REDIRECT_1_1(RET, NAME) \ RET \ NAME (const char *path) \ { \ RET (*_NAME) (const char *path); \ char *new_path = NULL; \ RET result; \ _NAME = (RET (*)(const char *path)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path (path); \ result = _NAME (new_path); \ free (new_path); \ return result; \ } #define REDIRECT_1_2(RET, NAME, T2) \ RET \ NAME (const char *path, T2 A2) \ { \ RET (*_NAME) (const char *path, T2 A2); \ char *new_path = NULL; \ RET result; \ _NAME = (RET (*)(const char *path, T2 A2)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path (path); \ result = _NAME (new_path, A2); \ free (new_path); \ return result; \ } #define REDIRECT_1_3(RET, NAME, T2, T3) \ RET \ NAME (const char *path, T2 A2, T3 A3) \ { \ RET (*_NAME) (const char *path, T2 A2, T3 A3); \ char *new_path = NULL; \ RET result; \ _NAME = (RET (*)(const char *path, T2 A2, T3 A3)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path (path); \ result = _NAME (new_path, A2, A3); \ free (new_path); \ return result; \ } #define REDIRECT_2_2(RET, NAME, T1) \ RET \ NAME (T1 A1, const char *path) \ { \ RET (*_NAME) (T1 A1, const char *path); \ char *new_path = NULL; \ RET result; \ _NAME = (RET (*)(T1 A1, const char *path)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path (path); \ result = _NAME (A1, new_path); \ free (new_path); \ return result; \ } #define REDIRECT_2_3(RET, NAME, T1, T3) \ RET \ NAME (T1 A1, const char *path, T3 A3) \ { \ RET (*_NAME) (T1 A1, const char *path, T3 A3); \ char *new_path = NULL; \ RET result; \ _NAME = (RET (*)(T1 A1, const char *path, T3 A3)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path (path); \ result = _NAME (A1, new_path, A3); \ free (new_path); \ return result; \ } #define REDIRECT_2_3_AT(RET, NAME, T1, T3) \ RET \ NAME (T1 A1, const char *path, T3 A3) \ { \ RET (*_NAME) (T1 A1, const char *path, T3 A3); \ char *new_path = NULL; \ RET result; \ _NAME = (RET (*)(T1 A1, const char *path, T3 A3)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path_if_absolute (path); \ result = _NAME (A1, new_path, A3); \ free (new_path); \ return result; \ } #define REDIRECT_2_4_AT(RET, NAME, T1, T3, T4) \ RET \ NAME (T1 A1, const char *path, T3 A3, T4 A4) \ { \ RET (*_NAME) (T1 A1, const char *path, T3 A3, T4 A4); \ char *new_path = NULL; \ RET result; \ _NAME = (RET (*)(T1 A1, const char *path, T3 A3, T4 A4)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path_if_absolute (path); \ result = _NAME (A1, new_path, A3, A4); \ free (new_path); \ return result; \ } #define REDIRECT_3_5(RET, NAME, T1, T2, T4, T5) \ RET \ NAME (T1 A1, T2 A2, const char *path, T4 A4, T5 A5) \ { \ RET (*_NAME) (T1 A1, T2 A2, const char *path, T4 A4, T5 A5); \ char *new_path = NULL; \ RET result; \ _NAME = (RET (*)(T1 A1, T2 A2, const char *path, T4 A4, T5 A5)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path (path); \ result = _NAME (A1, A2, new_path, A4, A5); \ free (new_path); \ return result; \ } #define REDIRECT_TARGET(RET, NAME) \ RET \ NAME (const char *path, const char *target) \ { \ RET (*_NAME) (const char *path, const char *target); \ char *new_path = NULL; \ char *new_target = NULL; \ RET result; \ _NAME = (RET (*)(const char *path, const char *target)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path (path); \ new_target = redirect_path_target (target); \ result = _NAME (new_path, new_target); \ free (new_path); \ free (new_target); \ return result; \ } #define REDIRECT_OPEN(NAME) \ int \ NAME (const char *path, int flags, ...) \ { \ int mode = 0; \ int (*_NAME) (const char *path, int flags, mode_t mode); \ char *new_path = NULL; \ int result; \ if (flags & (O_CREAT|O_TMPFILE)) \ { \ va_list ap; \ va_start (ap, flags); \ mode = va_arg (ap, mode_t); \ va_end (ap); \ } \ _NAME = (int (*)(const char *path, int flags, mode_t mode)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path (path); \ result = _NAME (new_path, flags, mode); \ free (new_path); \ return result; \ } #define REDIRECT_OPEN_AT(NAME) \ int \ NAME (int dirfp, const char *path, int flags, ...) \ { \ int mode = 0; \ int (*_NAME) (int dirfp, const char *path, int flags, mode_t mode); \ char *new_path = NULL; \ int result; \ if (flags & (O_CREAT|O_TMPFILE)) \ { \ va_list ap; \ va_start (ap, flags); \ mode = va_arg (ap, mode_t); \ va_end (ap); \ } \ _NAME = (int (*)(int dirfp, const char *path, int flags, mode_t mode)) dlsym (RTLD_NEXT, #NAME); \ new_path = redirect_path_if_absolute (path); \ result = _NAME (dirfp, new_path, flags, mode); \ free (new_path); \ return result; \ } REDIRECT_1_2(FILE *, fopen, const char *) REDIRECT_1_2(FILE *, fopen64, const char *) REDIRECT_1_1(int, unlink) REDIRECT_2_3_AT(int, unlinkat, int, int) REDIRECT_1_2(int, access, int) REDIRECT_1_2(int, eaccess, int) REDIRECT_1_2(int, euidaccess, int) REDIRECT_2_4_AT(int, faccessat, int, int, int) REDIRECT_1_2(int, stat, struct stat *) REDIRECT_1_2(int, stat64, struct stat64 *) REDIRECT_1_2(int, lstat, struct stat *) REDIRECT_1_2(int, lstat64, struct stat64 *) REDIRECT_1_2(int, creat, mode_t) REDIRECT_1_2(int, creat64, mode_t) REDIRECT_1_2(int, truncate, off_t) REDIRECT_2_2(char *, bindtextdomain, const char *) REDIRECT_2_3(int, __xstat, int, struct stat *) REDIRECT_2_3(int, __xstat64, int, struct stat64 *) REDIRECT_2_3(int, __lxstat, int, struct stat *) REDIRECT_2_3(int, __lxstat64, int, struct stat64 *) REDIRECT_3_5(int, __fxstatat, int, int, struct stat *, int) REDIRECT_3_5(int, __fxstatat64, int, int, struct stat64 *, int) REDIRECT_1_2(int, statfs, struct statfs *) REDIRECT_1_2(int, statfs64, struct statfs64 *) REDIRECT_1_2(int, statvfs, struct statvfs *) REDIRECT_1_2(int, statvfs64, struct statvfs64 *) REDIRECT_1_2(long, pathconf, int) REDIRECT_1_1(DIR *, opendir) REDIRECT_1_2(int, mkdir, mode_t) REDIRECT_1_1(int, rmdir) REDIRECT_1_3(int, chown, uid_t, gid_t) REDIRECT_1_3(int, lchown, uid_t, gid_t) REDIRECT_1_2(int, chmod, mode_t) REDIRECT_1_2(int, lchmod, mode_t) REDIRECT_1_1(int, chdir) REDIRECT_1_3(ssize_t, readlink, char *, size_t) REDIRECT_1_2(char *, realpath, char *) REDIRECT_TARGET(int, link) REDIRECT_TARGET(int, rename) REDIRECT_OPEN(open) REDIRECT_OPEN(open64) REDIRECT_OPEN_AT(openat) REDIRECT_OPEN_AT(openat64) REDIRECT_2_3(int, inotify_add_watch, int, uint32_t) int scandir (const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)) { int (*_scandir) (const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)); char *new_path = NULL; int ret; _scandir = (int (*)(const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **))) dlsym (RTLD_NEXT, "scandir"); new_path = redirect_path (dirp); ret = _scandir (new_path, namelist, filter, compar); free (new_path); return ret; } int scandir64 (const char *dirp, struct dirent64 ***namelist, int (*filter)(const struct dirent64 *), int (*compar)(const struct dirent64 **, const struct dirent64 **)) { int (*_scandir64) (const char *dirp, struct dirent64 ***namelist, int (*filter)(const struct dirent64 *), int (*compar)(const struct dirent64 **, const struct dirent64 **)); char *new_path = NULL; int ret; _scandir64 = (int (*)(const char *dirp, struct dirent64 ***namelist, int (*filter)(const struct dirent64 *), int (*compar)(const struct dirent64 **, const struct dirent64 **))) dlsym (RTLD_NEXT, "scandir64"); new_path = redirect_path (dirp); ret = _scandir64 (new_path, namelist, filter, compar); free (new_path); return ret; } int scandirat (int dirfd, const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)) { int (*_scandirat) (int dirfd, const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)); char *new_path = NULL; int ret; _scandirat = (int (*)(int dirfd, const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **))) dlsym (RTLD_NEXT, "scandirat"); new_path = redirect_path_if_absolute (dirp); ret = _scandirat (dirfd, new_path, namelist, filter, compar); free (new_path); return ret; } int scandirat64 (int dirfd, const char *dirp, struct dirent64 ***namelist, int (*filter)(const struct dirent64 *), int (*compar)(const struct dirent64 **, const struct dirent64 **)) { int (*_scandirat64) (int dirfd, const char *dirp, struct dirent64 ***namelist, int (*filter)(const struct dirent64 *), int (*compar)(const struct dirent64 **, const struct dirent64 **)); char *new_path = NULL; int ret; _scandirat64 = (int (*)(int dirfd, const char *dirp, struct dirent64 ***namelist, int (*filter)(const struct dirent64 *), int (*compar)(const struct dirent64 **, const struct dirent64 **))) dlsym (RTLD_NEXT, "scandirat64"); new_path = redirect_path_if_absolute (dirp); ret = _scandirat64 (dirfd, new_path, namelist, filter, compar); free (new_path); return ret; } int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int (*_bind) (int sockfd, const struct sockaddr *addr, socklen_t addrlen); int result; _bind = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "bind"); if (addr->sa_family == AF_UNIX && ((const struct sockaddr_un *)addr)->sun_path[0] != 0) { // could be abstract socket char *new_path = NULL; struct sockaddr_un new_addr; new_path = redirect_path (((const struct sockaddr_un *)addr)->sun_path); new_addr.sun_family = AF_UNIX; strcpy (new_addr.sun_path, new_path); free (new_path); result = _bind (sockfd, (const struct sockaddr *)&new_addr, sizeof(new_addr)); } else { result = _bind (sockfd, addr, addrlen); } return result; } int connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int (*_connect) (int sockfd, const struct sockaddr *addr, socklen_t addrlen); _connect = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "connect"); /* addrlen == sizeof(sa_family_t) is the case of unnamed sockets, * and first byte of sun_path is 0 for abstract sockets. */ if (addr->sa_family == AF_UNIX && addrlen > sizeof(sa_family_t) && ((const struct sockaddr_un *) addr)->sun_path[0] != '\0') { const struct sockaddr_un *un_addr = (const struct sockaddr_un *) addr; char *new_path = NULL; struct sockaddr_un new_addr; new_path = redirect_path (un_addr->sun_path); new_addr.sun_family = AF_UNIX; strcpy (new_addr.sun_path, new_path); free (new_path); return _connect (sockfd, (const struct sockaddr *)&new_addr, sizeof(new_addr)); } return _connect (sockfd, addr, addrlen); } void * dlopen (const char *path, int mode) { void *(*_dlopen) (const char *path, int mode); char *new_path = NULL; void *result; _dlopen = (void *(*)(const char *path, int mode)) dlsym (RTLD_NEXT, "dlopen"); if (path && path[0] == '/') { new_path = redirect_path (path); result = _dlopen (new_path, mode); free (new_path); } else { // non-absolute library paths aren't simply relative paths, they need // a whole lookup algorithm result = _dlopen (path, mode); } return result; } static char * ensure_in_ld_preload (char *ld_preload, const char *to_be_added) { if (ld_preload && ld_preload[0] != 0) { char *ld_preload_copy; char *p, *savedptr = NULL; int found = 0; // Check if we are already in LD_PRELOAD and thus can bail ld_preload_copy = strdup (ld_preload); for (p = strtok_r (ld_preload_copy + strlen (LD_PRELOAD) + 1, " :", &savedptr); p; p = strtok_r (NULL, " :", &savedptr)) { if (strcmp (p, to_be_added) == 0) { found = 1; break; } } free (ld_preload_copy); if (!found) { ld_preload = realloc (ld_preload, strlen (to_be_added) + strlen (ld_preload) + 2); strcat (ld_preload, ":"); strcat (ld_preload, to_be_added); } } else { ld_preload = realloc (ld_preload, strlen (to_be_added) + strlen (LD_PRELOAD) + 2); strcpy (ld_preload, LD_PRELOAD "="); strcat (ld_preload, to_be_added); } return ld_preload; } static char ** execve_copy_envp (char *const envp[]) { int i, num_elements; char **new_envp = NULL; char *ld_preload = NULL; char *snappy_preload = NULL; for (num_elements = 0; envp && envp[num_elements]; num_elements++) { // this space intentionally left blank } new_envp = malloc (sizeof (char *) * (num_elements + 3)); for (i = 0; i < num_elements; i++) { new_envp[i] = strdup (envp[i]); if (strncmp (envp[i], LD_PRELOAD "=", strlen (LD_PRELOAD) + 1) == 0) { ld_preload = new_envp[i]; // point at last defined LD_PRELOAD } } if (saved_ld_preloads) { size_t j; char *ld_preload_copy; ld_preload_copy = ld_preload ? strdup (ld_preload) : NULL; for (j = 0; j < num_saved_ld_preloads; j++) { ld_preload_copy = ensure_in_ld_preload(ld_preload_copy, saved_ld_preloads[j]); } new_envp[i++] = ld_preload_copy; } if (saved_snappy_preload) { snappy_preload = malloc (strlen (saved_snappy_preload) + strlen (SNAPPY_PRELOAD) + 2); strcpy (snappy_preload, SNAPPY_PRELOAD "="); strcat (snappy_preload, saved_snappy_preload); new_envp[i++] = snappy_preload; } new_envp[i++] = NULL; return new_envp; } static int execve32_wrapper (int (*_execve) (const char *path, char *const argv[], char *const envp[]), char *path, char *const argv[], char *const envp[]) { char *custom_loader = NULL; char **new_argv; int i, num_elements, result; custom_loader = redirect_path ("/lib/ld-linux.so.2"); if (strcmp (custom_loader, "/lib/ld-linux.so.2") == 0) { free (custom_loader); return 0; } // envp is already adjusted for our needs. But we need to shift argv for (num_elements = 0; argv && argv[num_elements]; num_elements++) { // this space intentionally left blank } new_argv = malloc (sizeof (char *) * (num_elements + 2)); new_argv[0] = path; for (i = 0; i < num_elements; i++) { new_argv[i + 1] = argv[i]; } new_argv[num_elements + 1] = 0; // Now actually run execve with our loader and adjusted argv result = _execve (custom_loader, new_argv, envp); // Cleanup on error free (new_argv); free (custom_loader); return result; } static int execve_wrapper (const char *func, const char *path, char *const argv[], char *const envp[]) { int (*_execve) (const char *path, char *const argv[], char *const envp[]); char *new_path = NULL; char **new_envp = NULL; int i, result; _execve = (int (*)(const char *path, char *const argv[], char *const envp[])) dlsym (RTLD_NEXT, func); new_path = redirect_path (path); // Make sure we inject our original preload values, can't trust this // program to pass them along in envp for us. new_envp = execve_copy_envp (envp); result = _execve (new_path, argv, new_envp); if (result == -1 && errno == ENOENT) { // OK, get prepared for gross hacks here. In order to run 32-bit ELF // executables -- which will hardcode /lib/ld-linux.so.2 as their ld.so // loader, we must redirect that check to our own version of ld-linux.so.2. // But that lookup is done behind the scenes by execve, so we can't // intercept it like normal. Instead, we'll prefix the command by the // ld.so loader which will only work if the architecture matches. So if // we failed to run it normally above because the loader couldn't find // something, try with our own 32-bit loader. int (*_access) (const char *pathname, int mode); _access = (int (*)(const char *pathname, int mode)) dlsym (RTLD_NEXT, "access"); if (_access (new_path, F_OK) == 0) { // Only actually try this if the path actually did exist. That // means the ENOENT must have been a missing linked library or the // wrong ld.so loader. Lets assume the latter and try to run as // a 32-bit executable. result = execve32_wrapper (_execve, new_path, argv, new_envp); } } free (new_path); for (i = 0; new_envp[i]; i++) { free (new_envp[i]); } free (new_envp); return result; } int execv (const char *path, char *const argv[]) { return execve (path, argv, environ); } int execve (const char *path, char *const argv[], char *const envp[]) { return execve_wrapper ("execve", path, argv, envp); } int __execve (const char *path, char *const argv[], char *const envp[]) { return execve_wrapper ("__execve", path, argv, envp); }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor