summaryrefslogtreecommitdiff
path: root/libgcompat
diff options
context:
space:
mode:
authorA. Wilcox <AWilcox@Wilcox-Tech.com>2020-07-06 08:02:28 -0500
committerA. Wilcox <AWilcox@Wilcox-Tech.com>2020-07-06 08:09:19 -0500
commit18a847c22a04de22cc9c431e87b63a0cfd5f1286 (patch)
tree58726c702031f848e12cd207cc7623d78f496a29 /libgcompat
parent581bddc0c02dbbde4dd130bf48b0f4e1887a0abf (diff)
downloadgcompat-18a847c22a04de22cc9c431e87b63a0cfd5f1286.tar.gz
gcompat-18a847c22a04de22cc9c431e87b63a0cfd5f1286.tar.bz2
gcompat-18a847c22a04de22cc9c431e87b63a0cfd5f1286.tar.xz
gcompat-18a847c22a04de22cc9c431e87b63a0cfd5f1286.zip
unistd: Interpose execv* functions for LOADER
Newer releases of Chromium directly execv /proc/self/exe, missing our readlink(3) interposing. We go ahead and interpose all three execv* functions just to ensure wider compatibility.
Diffstat (limited to 'libgcompat')
-rw-r--r--libgcompat/unistd.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/libgcompat/unistd.c b/libgcompat/unistd.c
index d2f3097..d632eee 100644
--- a/libgcompat/unistd.c
+++ b/libgcompat/unistd.c
@@ -3,6 +3,10 @@
#include <limits.h> /* NGROUPS_MAX */
#include <stddef.h> /* NULL, size_t */
#include <unistd.h> /* confstr, getcwd, getgroups, ... */
+#include <errno.h> /* ENOSYS, ENOMEM */
+#include <stdlib.h> /* calloc */
+#include <dlfcn.h> /* dlsym */
+#include <string.h> /* strcmp */
#include "alias.h" /* alias */
@@ -179,3 +183,53 @@ int group_member(gid_t gid)
return 0;
}
+
+#ifndef LOADER
+#error LOADER must be defined
+#endif
+
+static int (*real_execve)(const char *pathname, char *const argv[], char *const envp[]);
+int execve(const char *pathname, char *const argv[], char *const envp[]) {
+ if(real_execve == NULL) {
+ real_execve = dlsym(RTLD_NEXT, "execve");
+ if(real_execve == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+ }
+
+ if(!strcmp(pathname, "/proc/self/exe")) {
+ char **new_argv;
+ char target[PATH_MAX] = "";
+ int argc = 0, i = 0;
+ while(argv[i++] != 0) argc++;
+
+ i = readlink("/proc/self/exe", target, sizeof(target));
+ if(i < 0 || i == sizeof(target)) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ new_argv = calloc(argc + 6, sizeof(char *));
+ new_argv[0] = LOADER;
+ new_argv[1] = "--argv0";
+ new_argv[2] = argv[0];
+ new_argv[3] = "--preload";
+ new_argv[4] = "/lib/libgcompat.so.0";
+ new_argv[5] = target;
+ for(int j = 1, i = 6; j < argc; ++i, ++j) {
+ new_argv[i] = argv[j];
+ }
+ return execve(LINKER, new_argv, envp);
+ }
+ return real_execve(pathname, argv, envp);
+}
+
+extern char **environ;
+int execv(const char *pathname, char *const argv[]) {
+ return execve(pathname, argv, environ);
+}
+
+int execvp(const char *file, char *const argv[]) {
+ return execv(file, argv);
+}