mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-10 03:40:29 +00:00
Pathname security in GetProgramExecutableName
- Tries `KERN_PROC_PATHNAME` first on NetBSD/FreeBSD. - Tries procfs first, but now only on Linux. (You can have /proc on FreeBSD, but then again, /proc could be anything on non-Linux. An option here is to put non-Linux /proc after the issetugid check.) - If `issetugid()` and none of the secure methods have worked, sets the empty string and returns.
This commit is contained in:
parent
3fd424bf0d
commit
860bf7ec17
1 changed files with 37 additions and 35 deletions
|
@ -52,13 +52,14 @@ static inline int IsAlpha(int c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void InitProgramExecutableNameImpl(void) {
|
static inline void InitProgramExecutableNameImpl(void) {
|
||||||
|
size_t n;
|
||||||
|
ssize_t got;
|
||||||
|
char c, *q, *b;
|
||||||
|
|
||||||
if (__program_executable_name) {
|
if (__program_executable_name) {
|
||||||
/* already set by the loader */
|
/* already set by the loader */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
npassert(!issetugid()); // TODO(mrdomino): pathname security
|
|
||||||
// https://github.com/jart/cosmopolitan/issues/991
|
|
||||||
|
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
int n = GetModuleFileName(0, g_prog.u.buf16, ARRAYLEN(g_prog.u.buf16));
|
int n = GetModuleFileName(0, g_prog.u.buf16, ARRAYLEN(g_prog.u.buf16));
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
|
@ -78,18 +79,44 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||||
tprecode16to8(g_prog.u.buf, sizeof(g_prog.u.buf), g_prog.u.buf16);
|
tprecode16to8(g_prog.u.buf, sizeof(g_prog.u.buf), g_prog.u.buf16);
|
||||||
goto UseBuf;
|
goto UseBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
char c, *q;
|
|
||||||
if (IsMetal()) {
|
if (IsMetal()) {
|
||||||
__program_executable_name = APE_COM_NAME;
|
__program_executable_name = APE_COM_NAME;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b = g_prog.u.buf;
|
||||||
|
n = sizeof(g_prog.u.buf) - 1;
|
||||||
|
if (IsFreebsd() || IsNetbsd()) {
|
||||||
|
int cmd[4];
|
||||||
|
cmd[0] = CTL_KERN;
|
||||||
|
cmd[1] = KERN_PROC;
|
||||||
|
if (IsFreebsd()) {
|
||||||
|
cmd[2] = KERN_PROC_PATHNAME_FREEBSD;
|
||||||
|
} else {
|
||||||
|
cmd[2] = KERN_PROC_PATHNAME_NETBSD;
|
||||||
|
}
|
||||||
|
cmd[3] = -1; // current process
|
||||||
|
if (sys_sysctl(cmd, ARRAYLEN(cmd), b, &n, 0, 0) != -1) {
|
||||||
|
goto UseBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (IsLinux()) {
|
||||||
|
if ((got = sys_readlinkat(AT_FDCWD, "/proc/self/exe", b, n)) > 0 ||
|
||||||
|
(got = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", b, n)) > 0) {
|
||||||
|
b[got] = 0;
|
||||||
|
goto UseBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issetugid()) {
|
||||||
|
/* give up prior to using less secure methods */
|
||||||
|
goto UseEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
/* the previous loader supplied the full program path as the first
|
/* the previous loader supplied the full program path as the first
|
||||||
environment variable. */
|
environment variable. */
|
||||||
if ((q = __getenv(__envp, "COSMOPOLITAN_PROGRAM_EXECUTABLE").s)) {
|
if ((q = __getenv(__envp, "COSMOPOLITAN_PROGRAM_EXECUTABLE").s)) {
|
||||||
strlcpy(g_prog.u.buf, q, sizeof(g_prog.u.buf));
|
goto CopyString;
|
||||||
goto UseBuf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if argv[0] exists then turn it into an absolute path. we also try
|
// if argv[0] exists then turn it into an absolute path. we also try
|
||||||
|
@ -120,34 +147,8 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if getenv("_") exists then use that
|
// if getenv("_") exists then use that
|
||||||
for (char **ep = __envp; (q = *ep); ++ep) {
|
if ((q = __getenv(__envp, "_").s)) {
|
||||||
if (*q++ == '_' && *q++ == '=') {
|
goto CopyString;
|
||||||
goto CopyString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if argv[0] doesn't exist, then fallback to interpreter name
|
|
||||||
ssize_t got;
|
|
||||||
char *b = g_prog.u.buf;
|
|
||||||
size_t n = sizeof(g_prog.u.buf) - 1;
|
|
||||||
if ((got = sys_readlinkat(AT_FDCWD, "/proc/self/exe", b, n)) > 0 ||
|
|
||||||
(got = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", b, n)) > 0) {
|
|
||||||
b[got] = 0;
|
|
||||||
goto UseBuf;
|
|
||||||
}
|
|
||||||
if (IsFreebsd() || IsNetbsd()) {
|
|
||||||
int cmd[4];
|
|
||||||
cmd[0] = CTL_KERN;
|
|
||||||
cmd[1] = KERN_PROC;
|
|
||||||
if (IsFreebsd()) {
|
|
||||||
cmd[2] = KERN_PROC_PATHNAME_FREEBSD;
|
|
||||||
} else {
|
|
||||||
cmd[2] = KERN_PROC_PATHNAME_NETBSD;
|
|
||||||
}
|
|
||||||
cmd[3] = -1; // current process
|
|
||||||
if (sys_sysctl(cmd, ARRAYLEN(cmd), b, &n, 0, 0) != -1) {
|
|
||||||
goto UseBuf;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// give up and just copy argv[0] into it
|
// give up and just copy argv[0] into it
|
||||||
|
@ -165,6 +166,7 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we don't even have that then empty the string
|
// if we don't even have that then empty the string
|
||||||
|
UseEmpty:
|
||||||
g_prog.u.buf[0] = 0;
|
g_prog.u.buf[0] = 0;
|
||||||
|
|
||||||
UseBuf:
|
UseBuf:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue