RealPath in ape/loader.c

This commit is contained in:
Jōshin 2023-12-15 06:04:21 +00:00
parent 809f0f5019
commit 4673a6f186
No known key found for this signature in database

View file

@ -87,6 +87,8 @@
#define MIN(X, Y) ((Y) > (X) ? (X) : (Y))
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
#define PATH_MAX 1024 /* XXX verify */
#define SupportsLinux() (SUPPORT_VECTOR & LINUX)
#define SupportsXnu() (SUPPORT_VECTOR & XNU)
#define SupportsFreebsd() (SUPPORT_VECTOR & FREEBSD)
@ -212,13 +214,13 @@ struct PathSearcher {
const char *name;
const char *syspath;
unsigned long namelen;
char path[1024];
char path[PATH_MAX];
};
struct ApeLoader {
union ElfPhdrBuf phdr;
struct PathSearcher ps;
char path[1024];
char path[PATH_MAX];
};
EXTERN_C long SystemCall(long, long, long, long, long, long, long, int);
@ -239,6 +241,8 @@ static int StrCmp(const char *l, const char *r) {
return (l[i] & 255) - (r[i] & 255);
}
#if 0
static const char *StrRChr(const char *s, int c) {
const char *b = 0;
if (s) {
@ -256,6 +260,8 @@ static const char *BaseName(const char *s) {
return b ? b + 1 : s;
}
#endif
static void Bzero(void *a, unsigned long n) {
long z;
char *p, *e;
@ -347,7 +353,7 @@ static char *Utox(char p[19], unsigned long x) {
return p;
}
static char *Utoa(char p[21], unsigned long x) {
static char *Utoa(char p[20], unsigned long x) {
char t;
unsigned long i, a, b;
i = 0;
@ -538,6 +544,40 @@ __attribute__((__noreturn__)) static void Pexit(int os, const char *c, int rc,
Exit(127, os);
}
#define PSFD "/proc/self/fd/"
static int RealPath(int os, int fd, char *path, char **resolved) {
char buf[PATH_MAX];
int rc;
if (IsLinux()) {
char psfd[sizeof(PSFD) + 19];
MemMove(psfd, PSFD, sizeof(PSFD) - 1);
Utoa(psfd + sizeof(PSFD) - 1, fd);
rc = SystemCall(-100, (long)psfd, (long)buf, PATH_MAX, 0, 0, 0,
IsAarch64() ? 78 : 267);
if (rc >= 0) {
if (rc == PATH_MAX) {
rc = -36;
} else {
buf[rc] = 0;
}
}
} else if (IsXnu()) {
rc = SystemCall(fd, 50, (long)buf, 0, 0, 0, 0, 92 | 0x2000000);
} else if (IsOpenbsd()) {
rc = SystemCall((long)path, (long)buf, 0, 0, 0, 0, 0, 115);
} else {
*resolved = 0;
return 0;
}
if (rc >= 0) {
MemMove(path, buf, StrLen(buf) + 1);
*resolved = path;
rc = 0;
}
return rc;
}
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0;
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
@ -1039,6 +1079,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
Pexit(os, prog, 0, "not found (maybe chmod +x or ./ needed)");
} else if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) {
Pexit(os, exe, fd, "open");
} else if ((rc = RealPath(os, fd, exe, &prog)) < 0) {
Pexit(os, exe, rc, "realpath");
} else if ((rc = Pread(fd, ebuf->buf, sizeof(ebuf->buf), 0, os)) < 0) {
Pexit(os, exe, rc, "read");
} else if ((unsigned long)rc < sizeof(ebuf->ehdr)) {
@ -1046,10 +1088,9 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
}
pe = ebuf->buf + rc;
/* change argv[0] to resolved path if it's ambiguous */
if (argc > 0 && ((*prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) ||
!StrCmp(BaseName(prog), argv[0]))) {
argv[0] = exe;
/* change argv[0] to resolved path (TODO remove) */
if (argc > 0 && prog) {
argv[0] = prog;
}
/* ape intended behavior