Skip to content

Commit ec1af7c

Browse files
committed
Platform (OpenBSD): improves executable path retrieval method
Fixes #2195
1 parent a1e2027 commit ec1af7c

File tree

1 file changed

+80
-1
lines changed

1 file changed

+80
-1
lines changed

src/common/impl/FFPlatform_unix.c

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "FFPlatform_private.h"
22
#include "common/FFstrbuf.h"
3+
#include "common/arrayUtils.h"
34
#include "common/stringUtils.h"
45
#include "common/io.h"
56
#include "fastfetch_config.h"
@@ -13,8 +14,12 @@
1314
#ifdef __APPLE__
1415
#include <libproc.h>
1516
#include <sys/sysctl.h>
16-
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
17+
#elif defined(__FreeBSD__) || defined(__NetBSD__)
1718
#include <sys/sysctl.h>
19+
#elif defined(__OpenBSD__)
20+
#include <sys/sysctl.h>
21+
#include <kvm.h>
22+
#include "common/path.h"
1823
#elif defined(__HAIKU__)
1924
#include <image.h>
2025
#include <OS.h>
@@ -46,7 +51,81 @@ static void getExePath(FFPlatform* platform)
4651
else
4752
exePathLen--; // remove terminating NUL
4853
#elif defined(__OpenBSD__)
54+
// OpenBSD doesn't have a reliable way to get the executable path.
55+
// Current implementation uses argv[0], which can be easily spoofed.
56+
// See #2195
4957
size_t exePathLen = 0;
58+
kvm_t* kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
59+
if (kd)
60+
{
61+
int kpCount;
62+
struct kinfo_proc* kp = kvm_getprocs(kd, KERN_PROC_PID, (pid_t) platform->pid, sizeof(*kp), &kpCount);
63+
if (kp && kpCount == 1)
64+
{
65+
char** argv = kvm_getargv(kd, kp, 0);
66+
if (argv && argv[0])
67+
{
68+
char* arg0 = argv[0];
69+
if (arg0[0])
70+
{
71+
if (strchr(arg0, '/') != NULL) // likely a path (absolute or relative)
72+
{
73+
exePathLen = strlen(arg0);
74+
if (exePathLen < ARRAY_SIZE(exePath))
75+
{
76+
memcpy(exePath, arg0, exePathLen);
77+
exePath[exePathLen] = '\0';
78+
}
79+
else
80+
exePathLen = 0;
81+
}
82+
else
83+
{
84+
FF_STRBUF_AUTO_DESTROY tmpPath = ffStrbufCreate();
85+
if (ffFindExecutableInPath(arg0, &tmpPath) == NULL && tmpPath.length < ARRAY_SIZE(exePath))
86+
{
87+
memcpy(exePath, tmpPath.chars, tmpPath.length + 1);
88+
exePathLen = tmpPath.length;
89+
}
90+
}
91+
92+
if (exePathLen > 0)
93+
{
94+
struct stat st;
95+
if (stat(exePath, &st) == 0 && S_ISREG(st.st_mode))
96+
{
97+
int cntp;
98+
struct kinfo_file* kf = kvm_getfiles(kd, KERN_FILE_BYPID, platform->pid, sizeof(*kf), &cntp);
99+
if (kf)
100+
{
101+
int i;
102+
for (i = 0; i < cntp; i++)
103+
{
104+
if (kf[i].fd_fd == KERN_FILE_TEXT)
105+
{
106+
// KERN_FILE_TEXT is the executable file, not a shared library, and should be unique in the list.
107+
if (st.st_dev != (dev_t)kf[i].va_fsid || st.st_ino != (ino_t)kf[i].va_fileid)
108+
i = -1;
109+
break;
110+
}
111+
}
112+
if (i < 0)
113+
exePathLen = 0;
114+
}
115+
else
116+
{
117+
// If we can't get the list of open files, we can't verify that the file is actually the executable
118+
// Assume it is
119+
}
120+
}
121+
else
122+
exePathLen = 0;
123+
}
124+
}
125+
}
126+
}
127+
kvm_close(kd);
128+
}
50129
#elif defined(__sun)
51130
ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1);
52131
if (exePathLen >= 0)

0 commit comments

Comments
 (0)