Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 62 additions & 3 deletions Settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,67 @@ int Settings_write(const Settings* this, bool onCrash) {
return r;
}

static void Settings_resolveSymlink(char** resolvedPath, const char* path) {
int fd = -1;
int openFlags = O_NOCTTY | O_NOFOLLOW | O_NONBLOCK;
#ifdef O_EXEC
openFlags |= O_EXEC;
#else
// O_EXEC is not supported in Linux.
openFlags |= O_RDONLY;
#endif
#ifdef O_PATH
// O_PATH is specific to Linux and FreeBSD.
openFlags |= O_PATH;
#endif
do {
fd = open(path, openFlags);
} while (fd < 0 && errno == EINTR);

if (fd < 0)
goto noPath;

struct stat sb;
int err = fstat(fd, &sb);
if (err)
goto fileBroken;

if (!S_ISLNK(sb.st_mode) || (sb.st_uid != 0 && sb.st_uid != geteuid())) {
// Not a symbolic link or the symbolic link is not trusted.
// Return the path to the link itself. This allows the link
// target to be opened read-only when desirable.
close(fd);
*resolvedPath = xStrdup(path);
return;
}

if (sb.st_size < 0 || sb.st_size >= PATH_MAX)
goto fileBroken;

char buf[PATH_MAX];
ssize_t len = readlinkat(fd, "", buf, PATH_MAX);
close(fd);

if (len < 0 || len > sb.st_size)
goto noPath;

buf[len] = '\0';
char* intermediatePath = xStrdup(buf);
char* ptr = realpath(intermediatePath, buf);
free(intermediatePath);
if (!ptr)
goto noPath;

*resolvedPath = xStrdup(buf);
return;

fileBroken:
close(fd);
noPath:
*resolvedPath = xStrdup("");
return;
}

Settings* Settings_new(const Machine* host, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* dynamicScreens) {
Settings* this = xCalloc(1, sizeof(Settings));

Expand Down Expand Up @@ -868,9 +929,7 @@ Settings* Settings_new(const Machine* host, Hashtable* dynamicMeters, Hashtable*
legacyDotfile = String_cat(home, "/.htoprc");
}

this->filename = xMalloc(PATH_MAX);
if (!realpath(this->initialFilename, this->filename))
free_and_xStrdup(&this->filename, this->initialFilename);
Settings_resolveSymlink(&this->filename, this->initialFilename);

this->colorScheme = 0;
#ifdef HAVE_GETMOUSE
Expand Down
Loading