mirror of https://github.com/xzeldon/htop.git
Security review: make privilege dropping-restoring optional.
This is/was necessary only on macOS, because you needed root in order to read the process list. This was never necessary on Linux, and it also raises security concerns, so now it needs to be enabled explicitly at build time.
This commit is contained in:
parent
f205f7004c
commit
543d65c6ab
47
CRT.c
47
CRT.c
|
@ -5,6 +5,7 @@ Released under the GNU GPL, see the COPYING file
|
||||||
in the source distribution for its full text.
|
in the source distribution for its full text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "CRT.h"
|
#include "CRT.h"
|
||||||
|
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
@ -17,6 +18,10 @@ in the source distribution for its full text.
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <langinfo.h>
|
#include <langinfo.h>
|
||||||
|
#if HAVE_SETUID_ENABLED
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ColorIndex(i,j) ((7-i)*8+j)
|
#define ColorIndex(i,j) ((7-i)*8+j)
|
||||||
|
|
||||||
|
@ -545,6 +550,48 @@ static void CRT_handleSIGTERM(int sgn) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_SETUID_ENABLED
|
||||||
|
|
||||||
|
static int CRT_euid = -1;
|
||||||
|
|
||||||
|
static int CRT_egid = -1;
|
||||||
|
|
||||||
|
#define DIE(msg) do { CRT_done(); fprintf(stderr, msg); exit(1); } while(0)
|
||||||
|
|
||||||
|
void CRT_dropPrivileges() {
|
||||||
|
CRT_egid = getegid();
|
||||||
|
CRT_euid = geteuid();
|
||||||
|
if (setegid(getgid()) == -1) {
|
||||||
|
DIE("Fatal error: failed dropping group privileges.\n");
|
||||||
|
}
|
||||||
|
if (seteuid(getuid()) == -1) {
|
||||||
|
DIE("Fatal error: failed dropping user privileges.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRT_restorePrivileges() {
|
||||||
|
if (CRT_egid == -1 || CRT_euid == -1) {
|
||||||
|
DIE("Fatal error: internal inconsistency.\n");
|
||||||
|
}
|
||||||
|
if (setegid(CRT_egid) == -1) {
|
||||||
|
DIE("Fatal error: failed restoring group privileges.\n");
|
||||||
|
}
|
||||||
|
if (seteuid(CRT_euid) == -1) {
|
||||||
|
DIE("Fatal error: failed restoring user privileges.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Turn setuid operations into NOPs */
|
||||||
|
|
||||||
|
#ifndef CRT_dropPrivileges
|
||||||
|
#define CRT_dropPrivileges()
|
||||||
|
#define CRT_restorePrivileges()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO: pass an instance of Settings instead.
|
// TODO: pass an instance of Settings instead.
|
||||||
|
|
||||||
void CRT_init(int delay, int colorScheme) {
|
void CRT_init(int delay, int colorScheme) {
|
||||||
|
|
22
CRT.h
22
CRT.h
|
@ -9,6 +9,9 @@ Released under the GNU GPL, see the COPYING file
|
||||||
in the source distribution for its full text.
|
in the source distribution for its full text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if HAVE_SETUID_ENABLED
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ColorIndex(i,j) ((7-i)*8+j)
|
#define ColorIndex(i,j) ((7-i)*8+j)
|
||||||
|
|
||||||
#define ColorPair(i,j) COLOR_PAIR(ColorIndex(i,j))
|
#define ColorPair(i,j) COLOR_PAIR(ColorIndex(i,j))
|
||||||
|
@ -154,6 +157,25 @@ extern int CRT_colorScheme;
|
||||||
|
|
||||||
void *backtraceArray[128];
|
void *backtraceArray[128];
|
||||||
|
|
||||||
|
#if HAVE_SETUID_ENABLED
|
||||||
|
|
||||||
|
#define DIE(msg) do { CRT_done(); fprintf(stderr, msg); exit(1); } while(0)
|
||||||
|
|
||||||
|
void CRT_dropPrivileges();
|
||||||
|
|
||||||
|
void CRT_restorePrivileges();
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Turn setuid operations into NOPs */
|
||||||
|
|
||||||
|
#ifndef CRT_dropPrivileges
|
||||||
|
#define CRT_dropPrivileges()
|
||||||
|
#define CRT_restorePrivileges()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO: pass an instance of Settings instead.
|
// TODO: pass an instance of Settings instead.
|
||||||
|
|
||||||
void CRT_init(int delay, int colorScheme);
|
void CRT_init(int delay, int colorScheme);
|
||||||
|
|
|
@ -48,10 +48,9 @@ void EnvScreen_scan(InfoScreen* this) {
|
||||||
|
|
||||||
Panel_prune(panel);
|
Panel_prune(panel);
|
||||||
|
|
||||||
uid_t euid = geteuid();
|
CRT_dropPrivileges();
|
||||||
(void) seteuid(getuid());
|
char* env = Platform_getProcessEnv(this->process->pid);
|
||||||
char *env = Platform_getProcessEnv(this->process->pid);
|
CRT_restorePrivileges();
|
||||||
(void) seteuid(euid);
|
|
||||||
if (env) {
|
if (env) {
|
||||||
for (char *p = env; *p; p = strrchr(p, 0)+1)
|
for (char *p = env; *p; p = strrchr(p, 0)+1)
|
||||||
InfoScreen_addLine(this, p);
|
InfoScreen_addLine(this, p);
|
||||||
|
|
10
Process.c
10
Process.c
|
@ -522,11 +522,10 @@ void Process_toggleTag(Process* this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Process_setPriority(Process* this, int priority) {
|
bool Process_setPriority(Process* this, int priority) {
|
||||||
uid_t euid = geteuid();
|
CRT_dropPrivileges();
|
||||||
(void) seteuid(getuid());
|
|
||||||
int old_prio = getpriority(PRIO_PROCESS, this->pid);
|
int old_prio = getpriority(PRIO_PROCESS, this->pid);
|
||||||
int err = setpriority(PRIO_PROCESS, this->pid, priority);
|
int err = setpriority(PRIO_PROCESS, this->pid, priority);
|
||||||
(void) seteuid(euid);
|
CRT_restorePrivileges();
|
||||||
if (err == 0 && old_prio != getpriority(PRIO_PROCESS, this->pid)) {
|
if (err == 0 && old_prio != getpriority(PRIO_PROCESS, this->pid)) {
|
||||||
this->nice = priority;
|
this->nice = priority;
|
||||||
}
|
}
|
||||||
|
@ -538,10 +537,9 @@ bool Process_changePriorityBy(Process* this, size_t delta) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process_sendSignal(Process* this, size_t sgn) {
|
void Process_sendSignal(Process* this, size_t sgn) {
|
||||||
uid_t euid = geteuid();
|
CRT_dropPrivileges();
|
||||||
(void) seteuid(getuid());
|
|
||||||
kill(this->pid, (int) sgn);
|
kill(this->pid, (int) sgn);
|
||||||
(void) seteuid(euid);
|
CRT_restorePrivileges();
|
||||||
}
|
}
|
||||||
|
|
||||||
long Process_pidCompare(const void* v1, const void* v2) {
|
long Process_pidCompare(const void* v1, const void* v2) {
|
||||||
|
|
17
Settings.c
17
Settings.c
|
@ -165,11 +165,10 @@ static void readFields(ProcessField* fields, int* flags, const char* line) {
|
||||||
|
|
||||||
static bool Settings_read(Settings* this, const char* fileName) {
|
static bool Settings_read(Settings* this, const char* fileName) {
|
||||||
FILE* fd;
|
FILE* fd;
|
||||||
uid_t euid = geteuid();
|
|
||||||
|
|
||||||
(void) seteuid(getuid());
|
CRT_dropPrivileges();
|
||||||
fd = fopen(fileName, "r");
|
fd = fopen(fileName, "r");
|
||||||
(void) seteuid(euid);
|
CRT_restorePrivileges();
|
||||||
if (!fd)
|
if (!fd)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -278,11 +277,11 @@ static void writeMeterModes(Settings* this, FILE* fd, int column) {
|
||||||
|
|
||||||
bool Settings_write(Settings* this) {
|
bool Settings_write(Settings* this) {
|
||||||
FILE* fd;
|
FILE* fd;
|
||||||
uid_t euid = geteuid();
|
|
||||||
|
|
||||||
(void) seteuid(getuid());
|
CRT_dropPrivileges();
|
||||||
fd = fopen(this->filename, "w");
|
fd = fopen(this->filename, "w");
|
||||||
(void) seteuid(euid);
|
CRT_restorePrivileges();
|
||||||
|
|
||||||
if (fd == NULL) {
|
if (fd == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -368,8 +367,8 @@ Settings* Settings_new(int cpuCount) {
|
||||||
htopDir = String_cat(home, "/.config/htop");
|
htopDir = String_cat(home, "/.config/htop");
|
||||||
}
|
}
|
||||||
legacyDotfile = String_cat(home, "/.htoprc");
|
legacyDotfile = String_cat(home, "/.htoprc");
|
||||||
uid_t euid = geteuid();
|
|
||||||
(void) seteuid(getuid());
|
CRT_dropPrivileges();
|
||||||
(void) mkdir(configDir, 0700);
|
(void) mkdir(configDir, 0700);
|
||||||
(void) mkdir(htopDir, 0700);
|
(void) mkdir(htopDir, 0700);
|
||||||
free(htopDir);
|
free(htopDir);
|
||||||
|
@ -382,7 +381,7 @@ Settings* Settings_new(int cpuCount) {
|
||||||
free(legacyDotfile);
|
free(legacyDotfile);
|
||||||
legacyDotfile = NULL;
|
legacyDotfile = NULL;
|
||||||
}
|
}
|
||||||
(void) seteuid(euid);
|
CRT_restorePrivileges();
|
||||||
}
|
}
|
||||||
this->colorScheme = 0;
|
this->colorScheme = 0;
|
||||||
this->changed = false;
|
this->changed = false;
|
||||||
|
|
|
@ -96,7 +96,7 @@ bool TraceScreen_forkTracer(TraceScreen* this) {
|
||||||
this->child = fork();
|
this->child = fork();
|
||||||
if (this->child == -1) return false;
|
if (this->child == -1) return false;
|
||||||
if (this->child == 0) {
|
if (this->child == 0) {
|
||||||
(void) seteuid(getuid());
|
CRT_dropPrivileges();
|
||||||
dup2(this->fdpair[1], STDERR_FILENO);
|
dup2(this->fdpair[1], STDERR_FILENO);
|
||||||
int ok = fcntl(this->fdpair[1], F_SETFL, O_NONBLOCK);
|
int ok = fcntl(this->fdpair[1], F_SETFL, O_NONBLOCK);
|
||||||
if (ok != -1) {
|
if (ok != -1) {
|
||||||
|
|
|
@ -253,6 +253,12 @@ then
|
||||||
AC_CHECK_HEADERS([hwloc.h],[:], [missing_headers="$missing_headers $ac_header"])
|
AC_CHECK_HEADERS([hwloc.h],[:], [missing_headers="$missing_headers $ac_header"])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(setuid, [AS_HELP_STRING([--enable-setuid], [enable setuid support for platforms that need it])],, enable_setuid="no")
|
||||||
|
if test "x$enable_setuid" = xyes
|
||||||
|
then
|
||||||
|
AC_DEFINE(HAVE_SETUID_ENABLED, 1, [Define if setuid support should be enabled.])
|
||||||
|
fi
|
||||||
|
|
||||||
# Bail out on errors.
|
# Bail out on errors.
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
if test ! -z "$missing_libraries"; then
|
if test ! -z "$missing_libraries"; then
|
||||||
|
|
Loading…
Reference in New Issue