@@ -866,40 +866,93 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
866866 cgroup_context_dump (& s -> cgroup_context , f , prefix );
867867}
868868
869+ static int service_is_suitable_main_pid (Service * s , pid_t pid , int prio ) {
870+ Unit * owner ;
871+
872+ assert (s );
873+ assert (pid_is_valid (pid ));
874+
875+ /* Checks whether the specified PID is suitable as main PID for this service. returns negative if not, 0 if the
876+ * PID is questionnable but should be accepted if the source of configuration is trusted. > 0 if the PID is
877+ * good */
878+
879+ if (pid == getpid_cached () || pid == 1 ) {
880+ log_unit_full (UNIT (s ), prio , 0 , "New main PID " PID_FMT " is the manager, refusing." , pid );
881+ return - EPERM ;
882+ }
883+
884+ if (pid == s -> control_pid ) {
885+ log_unit_full (UNIT (s ), prio , 0 , "New main PID " PID_FMT " is the control process, refusing." , pid );
886+ return - EPERM ;
887+ }
888+
889+ if (!pid_is_alive (pid )) {
890+ log_unit_full (UNIT (s ), prio , 0 , "New main PID " PID_FMT " does not exist or is a zombie." , pid );
891+ return - ESRCH ;
892+ }
893+
894+ owner = manager_get_unit_by_pid (UNIT (s )-> manager , pid );
895+ if (owner == UNIT (s )) {
896+ log_unit_debug (UNIT (s ), "New main PID " PID_FMT " belongs to service, we are happy." , pid );
897+ return 1 ; /* Yay, it's definitely a good PID */
898+ }
899+
900+ return 0 ; /* Hmm it's a suspicious PID, let's accept it if configuration source is trusted */
901+ }
902+
869903static int service_load_pid_file (Service * s , bool may_warn ) {
904+ char procfs [STRLEN ("/proc/self/fd/" ) + DECIMAL_STR_MAX (int )];
870905 _cleanup_free_ char * k = NULL ;
871- int r ;
906+ _cleanup_close_ int fd = -1 ;
907+ int r , prio ;
872908 pid_t pid ;
873909
874910 assert (s );
875911
876912 if (!s -> pid_file )
877913 return - ENOENT ;
878914
879- r = read_one_line_file (s -> pid_file , & k );
880- if (r < 0 ) {
881- if (may_warn )
882- log_unit_info_errno (UNIT (s ), r , "PID file %s not readable (yet?) after %s: %m" , s -> pid_file , service_state_to_string (s -> state ));
883- return r ;
884- }
915+ prio = may_warn ? LOG_INFO : LOG_DEBUG ;
916+
917+ fd = chase_symlinks (s -> pid_file , NULL , CHASE_OPEN |CHASE_SAFE , NULL );
918+ if (fd == - EPERM )
919+ return log_unit_full (UNIT (s ), prio , fd , "Permission denied while opening PID file or unsafe symlink chain: %s" , s -> pid_file );
920+ if (fd < 0 )
921+ return log_unit_full (UNIT (s ), prio , fd , "Can't open PID file %s (yet?) after %s: %m" , s -> pid_file , service_state_to_string (s -> state ));
922+
923+ /* Let's read the PID file now that we chased it down. But we need to convert the O_PATH fd chase_symlinks() returned us into a proper fd first. */
924+ xsprintf (procfs , "/proc/self/fd/%i" , fd );
925+ r = read_one_line_file (procfs , & k );
926+ if (r < 0 )
927+ return log_unit_error_errno (UNIT (s ), r , "Can't convert PID files %s O_PATH file descriptor to proper file descriptor: %m" , s -> pid_file );
885928
886929 r = parse_pid (k , & pid );
887- if (r < 0 ) {
888- if (may_warn )
889- log_unit_info_errno (UNIT (s ), r , "Failed to read PID from file %s: %m" , s -> pid_file );
930+ if (r < 0 )
931+ return log_unit_full (UNIT (s ), prio , r , "Failed to parse PID from file %s: %m" , s -> pid_file );
932+
933+ if (s -> main_pid_known && pid == s -> main_pid )
934+ return 0 ;
935+
936+ r = service_is_suitable_main_pid (s , pid , prio );
937+ if (r < 0 )
890938 return r ;
891- }
939+ if (r == 0 ) {
940+ struct stat st ;
892941
893- if (!pid_is_alive (pid )) {
894- if (may_warn )
895- log_unit_info (UNIT (s ), "PID " PID_FMT " read from file %s does not exist or is a zombie." , pid , s -> pid_file );
896- return - ESRCH ;
942+ /* Hmm, it's not clear if the new main PID is safe. Let's allow this if the PID file is owned by root */
943+
944+ if (fstat (fd , & st ) < 0 )
945+ return log_unit_error_errno (UNIT (s ), errno , "Failed to fstat() PID file O_PATH fd: %m" );
946+
947+ if (st .st_uid != 0 ) {
948+ log_unit_error (UNIT (s ), "New main PID " PID_FMT " does not belong to service, and PID file is not owned by root. Refusing." , pid );
949+ return - EPERM ;
950+ }
951+
952+ log_unit_debug (UNIT (s ), "New main PID " PID_FMT " does not belong to service, but we'll accept it since PID file is owned by root." , pid );
897953 }
898954
899955 if (s -> main_pid_known ) {
900- if (pid == s -> main_pid )
901- return 0 ;
902-
903956 log_unit_debug (UNIT (s ), "Main PID changing: " PID_FMT " -> " PID_FMT , s -> main_pid , pid );
904957
905958 service_unwatch_main_pid (s );
@@ -915,7 +968,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
915968 if (r < 0 ) /* FIXME: we need to do something here */
916969 return log_unit_warning_errno (UNIT (s ), r , "Failed to watch PID " PID_FMT " for service: %m" , pid );
917970
918- return 0 ;
971+ return 1 ;
919972}
920973
921974static void service_search_main_pid (Service * s ) {
@@ -2981,7 +3034,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
29813034 /* Forking services may occasionally move to a new PID.
29823035 * As long as they update the PID file before exiting the old
29833036 * PID, they're fine. */
2984- if (service_load_pid_file (s , false) == 0 )
3037+ if (service_load_pid_file (s , false) > 0 )
29853038 return ;
29863039
29873040 s -> main_pid = 0 ;
@@ -3406,37 +3459,55 @@ static bool service_notify_message_authorized(Service *s, pid_t pid, char **tags
34063459 return true;
34073460}
34083461
3409- static void service_notify_message (Unit * u , pid_t pid , char * * tags , FDSet * fds ) {
3462+ static void service_notify_message (
3463+ Unit * u ,
3464+ const struct ucred * ucred ,
3465+ char * * tags ,
3466+ FDSet * fds ) {
3467+
34103468 Service * s = SERVICE (u );
34113469 bool notify_dbus = false;
34123470 const char * e ;
34133471 char * * i ;
3472+ int r ;
34143473
34153474 assert (u );
3475+ assert (ucred );
34163476
3417- if (!service_notify_message_authorized (SERVICE (u ), pid , tags , fds ))
3477+ if (!service_notify_message_authorized (SERVICE (u ), ucred -> pid , tags , fds ))
34183478 return ;
34193479
34203480 if (DEBUG_LOGGING ) {
34213481 _cleanup_free_ char * cc = NULL ;
34223482
34233483 cc = strv_join (tags , ", " );
3424- log_unit_debug (u , "Got notification message from PID " PID_FMT " (%s)" , pid , isempty (cc ) ? "n/a" : cc );
3484+ log_unit_debug (u , "Got notification message from PID " PID_FMT " (%s)" , ucred -> pid , isempty (cc ) ? "n/a" : cc );
34253485 }
34263486
34273487 /* Interpret MAINPID= */
34283488 e = strv_find_startswith (tags , "MAINPID=" );
34293489 if (e && IN_SET (s -> state , SERVICE_START , SERVICE_START_POST , SERVICE_RUNNING , SERVICE_RELOAD )) {
3430- if (parse_pid (e , & pid ) < 0 )
3431- log_unit_warning (u , "Failed to parse MAINPID= field in notification message: %s" , e );
3432- else if (pid == s -> control_pid )
3433- log_unit_warning (u , "A control process cannot also be the main process" );
3434- else if (pid == getpid_cached () || pid == 1 )
3435- log_unit_warning (u , "Service manager can't be main process, ignoring sd_notify() MAINPID= field" );
3436- else if (pid != s -> main_pid ) {
3437- service_set_main_pid (s , pid );
3438- unit_watch_pid (UNIT (s ), pid );
3439- notify_dbus = true;
3490+ pid_t new_main_pid ;
3491+
3492+ if (parse_pid (e , & new_main_pid ) < 0 )
3493+ log_unit_warning (u , "Failed to parse MAINPID= field in notification message, ignoring: %s" , e );
3494+ else if (!s -> main_pid_known || new_main_pid != s -> main_pid ) {
3495+
3496+ r = service_is_suitable_main_pid (s , new_main_pid , LOG_WARNING );
3497+ if (r == 0 ) {
3498+ /* The new main PID is a bit suspicous, which is OK if the sender is privileged. */
3499+
3500+ if (ucred -> uid == 0 ) {
3501+ log_unit_debug (u , "New main PID " PID_FMT " does not belong to service, but we'll accept it as the request to change it came from a privileged process." , new_main_pid );
3502+ r = 1 ;
3503+ } else
3504+ log_unit_debug (u , "New main PID " PID_FMT " does not belong to service, refusing." , new_main_pid );
3505+ }
3506+ if (r > 0 ) {
3507+ service_set_main_pid (s , new_main_pid );
3508+ unit_watch_pid (UNIT (s ), new_main_pid );
3509+ notify_dbus = true;
3510+ }
34403511 }
34413512 }
34423513
0 commit comments