sys_macosx: drop root privileges

Run chronyd as a non-privileged user, using the privops helper to
perform adjtime(), settimeofday() and bind() functions on its behalf.
This commit is contained in:
Bryan Christianson 2015-11-24 21:01:59 +13:00 committed by Miroslav Lichvar
parent 139fc667aa
commit 750d82f1d1
7 changed files with 61 additions and 9 deletions

View file

@ -978,7 +978,13 @@ This option sets the name of the system user to which @code{chronyd} will
switch after start in order to drop root privileges. It overrides the switch after start in order to drop root privileges. It overrides the
@code{user} directive (default @code{@DEFAULT_USER@}). It may be set to a @code{user} directive (default @code{@DEFAULT_USER@}). It may be set to a
non-root user only when @code{chronyd} is compiled with support for Linux non-root user only when @code{chronyd} is compiled with support for Linux
capabilities (libcap) or on NetBSD with the @code{/dev/clockctl} device. capabilities (libcap), on NetBSD with the @code{/dev/clockctl} device or on
Mac OS X.
In the Mac OS X implementation @code{chronyd} forks into two processes. The
child process retains root privileges but can only perform a very limited range
of privileged system calls on behalf of the parent. The parent process drops
root privileges to run as the specified system user.
@item -F <level> @item -F <level>
This option configures a system call filter when @code{chronyd} is compiled with This option configures a system call filter when @code{chronyd} is compiled with
support for the Linux secure computing (seccomp) facility. In level 1 the support for the Linux secure computing (seccomp) facility. In level 1 the
@ -3169,8 +3175,13 @@ Valid measurements with corresponding compensations are logged to the
The @code{user} directive sets the name of the system user to which The @code{user} directive sets the name of the system user to which
@code{chronyd} will switch after start in order to drop root privileges. @code{chronyd} will switch after start in order to drop root privileges.
It may be set to a non-root user only when @code{chronyd} is compiled with It may be set to a non-root user only when @code{chronyd} is compiled with
support for Linux capabilities (libcap) or on NetBSD with the support for Linux capabilities (libcap), on NetBSD with the
@code{/dev/clockctl} device. @code{/dev/clockctl} device or on Mac OS X.
In the Mac OS X implementation @code{chronyd} forks into two processes. The
child process retains root privileges but can only perform a very limited range
of privileged system calls on behalf of the parent. The parent process drops
root privileges to run as the specified system user.
The default value is @code{@DEFAULT_USER@}. The default value is @code{@DEFAULT_USER@}.
@c }}} @c }}}

View file

@ -103,7 +103,12 @@ This option sets the name of the system user to which \fBchronyd\fR will switch
after start in order to drop root privileges. It overrides the \fBuser\fR after start in order to drop root privileges. It overrides the \fBuser\fR
directive (default \fB@DEFAULT_USER@\fR). It may be set to a non-root user directive (default \fB@DEFAULT_USER@\fR). It may be set to a non-root user
only when \fBchronyd\fR is compiled with support for Linux capabilities only when \fBchronyd\fR is compiled with support for Linux capabilities
(libcap) or on NetBSD with the \fB/dev/clockctl\fR device. (libcap), on NetBSD with the \fB/dev/clockctl\fR device or on Mac OS X.
In the Mac OS X implementation \fBchronyd\fR forks into two processes. The
child process retains root privileges but can only perform a very limited range
of privileged system calls on behalf of the parent. The parent process drops
root privileges to run as the specified system user.
.TP .TP
\fB\-F\fR \fIlevel\fR \fB\-F\fR \fIlevel\fR
This option configures a system call filter when \fBchronyd\fR is compiled with This option configures a system call filter when \fBchronyd\fR is compiled with

8
configure vendored
View file

@ -392,6 +392,14 @@ case $OPERATINGSYSTEM in
EXTRA_LIBS="-lresolv" EXTRA_LIBS="-lresolv"
EXTRA_CLI_LIBS="-lresolv" EXTRA_CLI_LIBS="-lresolv"
add_def MACOSX add_def MACOSX
if [ $feat_droproot = "1" ]; then
EXTRA_OBJECTS="$EXTRA_OBJECTS privops.o"
add_def PRIVOPS_ADJUSTTIME
add_def PRIVOPS_SETTIME
add_def PRIVOPS_BINDSOCKET
add_def PRIVOPS_HELPER
add_def FEAT_PRIVDROP
fi
echo "Configuring for MacOS X (" $SYSTEM "MacOS X version" $VERSION ")" echo "Configuring for MacOS X (" $SYSTEM "MacOS X version" $VERSION ")"
;; ;;
SunOS) SunOS)

View file

@ -37,6 +37,7 @@
#include "local.h" #include "local.h"
#include "logging.h" #include "logging.h"
#include "conf.h" #include "conf.h"
#include "privops.h"
#include "util.h" #include "util.h"
#define INVALID_SOCK_FD -1 #define INVALID_SOCK_FD -1
@ -221,7 +222,7 @@ prepare_socket(int family, int port_number, int client_only)
#endif #endif
/* Bind the socket if a port or address was specified */ /* Bind the socket if a port or address was specified */
if (my_addr_len > 0 && bind(sock_fd, &my_addr.u, my_addr_len) < 0) { if (my_addr_len > 0 && PRV_BindSocket(sock_fd, &my_addr.u, my_addr_len) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not bind %s NTP socket : %s", LOG(LOGS_ERR, LOGF_NtpIO, "Could not bind %s NTP socket : %s",
UTI_SockaddrFamilyToString(family), strerror(errno)); UTI_SockaddrFamilyToString(family), strerror(errno));
close(sock_fd); close(sock_fd);

2
sys.c
View file

@ -92,6 +92,8 @@ void SYS_DropRoot(uid_t uid, gid_t gid)
SYS_Linux_DropRoot(uid, gid); SYS_Linux_DropRoot(uid, gid);
#elif defined(NETBSD) && defined(FEAT_PRIVDROP) #elif defined(NETBSD) && defined(FEAT_PRIVDROP)
SYS_NetBSD_DropRoot(uid, gid); SYS_NetBSD_DropRoot(uid, gid);
#elif defined(MACOSX) && defined(FEAT_PRIVDROP)
SYS_MacOSX_DropRoot(uid, gid);
#else #else
LOG_FATAL(LOGF_Sys, "dropping root privileges not supported"); LOG_FATAL(LOGF_Sys, "dropping root privileges not supported");
#endif #endif

View file

@ -50,6 +50,7 @@
#include "localp.h" #include "localp.h"
#include "sched.h" #include "sched.h"
#include "logging.h" #include "logging.h"
#include "privops.h"
#include "util.h" #include "util.h"
/* ================================================== */ /* ================================================== */
@ -117,7 +118,7 @@ clock_initialise(void)
newadj.tv_sec = 0; newadj.tv_sec = 0;
newadj.tv_usec = 0; newadj.tv_usec = 0;
if (adjtime(&newadj, &oldadj) < 0) { if (PRV_AdjustTime(&newadj, &oldadj) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed"); LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
} }
} }
@ -169,7 +170,7 @@ start_adjust(void)
UTI_TimevalToDouble(&newadj, &adjustment_requested); UTI_TimevalToDouble(&newadj, &adjustment_requested);
rounding_error = adjust_required - adjustment_requested; rounding_error = adjust_required - adjustment_requested;
if (adjtime(&newadj, &oldadj) < 0) { if (PRV_AdjustTime(&newadj, &oldadj) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed"); LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
} }
@ -193,7 +194,7 @@ stop_adjust(void)
zeroadj.tv_sec = 0; zeroadj.tv_sec = 0;
zeroadj.tv_usec = 0; zeroadj.tv_usec = 0;
if (adjtime(&zeroadj, &remadj) < 0) { if (PRV_AdjustTime(&zeroadj, &remadj) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed"); LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
} }
@ -244,7 +245,7 @@ apply_step_offset(double offset)
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time); UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) { if (PRV_SetTime(&new_time, NULL) < 0) {
DEBUG_LOG(LOGF_SysMacOSX, "settimeofday() failed"); DEBUG_LOG(LOGF_SysMacOSX, "settimeofday() failed");
return 0; return 0;
} }
@ -400,6 +401,26 @@ SYS_MacOSX_SetScheduler(int SchedPriority)
/* ================================================== */ /* ================================================== */
#ifdef FEAT_PRIVDROP
void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid)
{
PRV_Initialise();
if (setgroups(0, NULL))
LOG_FATAL(LOGF_SysMacOSX, "setgroups() failed : %s", strerror(errno));
if (setgid(gid))
LOG_FATAL(LOGF_SysMacOSX, "setgid(%d) failed : %s", gid, strerror(errno));
if (setuid(uid))
LOG_FATAL(LOGF_SysMacOSX, "setuid(%d) failed : %s", uid, strerror(errno));
DEBUG_LOG(LOGF_SysMacOSX, "Root dropped to uid %d gid %d", uid, gid);
}
#endif
/* ================================================== */
void void
SYS_MacOSX_Initialise(void) SYS_MacOSX_Initialise(void)
{ {
@ -423,6 +444,9 @@ SYS_MacOSX_Finalise(void)
SCH_RemoveTimeout(drift_removal_id); SCH_RemoveTimeout(drift_removal_id);
clock_finalise(); clock_finalise();
#ifdef FEAT_PRIVDROP
PRV_Finalise();
#endif
} }
/* ================================================== */ /* ================================================== */

View file

@ -31,6 +31,7 @@
#define GOT_SYS_MACOSX_H #define GOT_SYS_MACOSX_H
void SYS_MacOSX_SetScheduler(int SchedPriority); void SYS_MacOSX_SetScheduler(int SchedPriority);
void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid);
void SYS_MacOSX_Initialise(void); void SYS_MacOSX_Initialise(void);
void SYS_MacOSX_Finalise(void); void SYS_MacOSX_Finalise(void);