@@ -1914,10 +1914,52 @@ update_script_environment(void)
19141914 * reap_kids) iff the return value is > 0.
19151915 */
19161916pid_t
1917- run_program (char * prog , char * const * args , int must_exist , void (* done )(void * ), void * arg , int wait )
1917+ run_program (char * _prog , char * const * args , int must_exist , void (* done )(void * ), void * arg , int wait )
19181918{
19191919 int pid , status , ret ;
19201920 struct stat sbuf ;
1921+ char prog [PATH_MAX ];
1922+ char * slash ;
1923+
1924+ /*
1925+ * Resolve symlinks such that we eliminate a few potential ToCToU
1926+ * attack avenues (eg, changing symlinks).
1927+ */
1928+ if (!realpath (_prog , prog )) {
1929+ if (must_exist || errno != ENOENT )
1930+ warn ("Can't execute %s: %m" , prog );
1931+ return 0 ;
1932+ }
1933+
1934+ /*
1935+ * full check the entire path, must be root: owned, and NOT be writable
1936+ * to group/other (which incorporates FACL bits somehow, so we can ignore
1937+ * explicit FACL checks).
1938+ */
1939+ do {
1940+ bool ok = false;
1941+ if (fstatat (AT_FDCWD , slash ? prog : "/" , & sbuf , AT_SYMLINK_NOFOLLOW ) != 0 ) {
1942+ warn ("Script path check failure: %s: %m" , slash ? prog : "/" );
1943+ } else if (sbuf .st_uid != 0 /* getuid() ? */ ) {
1944+ warn ("Script path %s is not root owned." , slash ? prog : "/" );
1945+ } else if (0 != (sbuf .st_mode & (S_IWGRP | S_IWOTH ))) {
1946+ warn ("Script path %s is group or other writable." , slash ? prog : "/" );
1947+ } else {
1948+ ok = true;
1949+ }
1950+
1951+ if (slash )
1952+ * slash = '/' ;
1953+
1954+ if (!ok ) {
1955+ warn ("Can't execute %s: error checking path as per above" );
1956+ return 0 ;
1957+ }
1958+
1959+ slash = strchr ((slash ? slash : prog ) + 1 , '/' );
1960+ if (slash )
1961+ * slash = 0 ;
1962+ } while (slash );
19211963
19221964 /*
19231965 * First check if the file exists and is executable.
@@ -1926,13 +1968,27 @@ run_program(char *prog, char * const *args, int must_exist, void (*done)(void *)
19261968 * might be accessible only to root.
19271969 */
19281970 errno = EINVAL ;
1929- if (stat (prog , & sbuf ) < 0 || !S_ISREG (sbuf .st_mode )
1930- || (sbuf .st_mode & (S_IXUSR |S_IXGRP |S_IXOTH )) == 0 ) {
1971+ if (stat (AT_FDCWD , prog , & sbuf , AT_SYMLINK_NOFOLLOW ) != 0 ) {
19311972 if (must_exist || errno != ENOENT )
19321973 warn ("Can't execute %s: %m" , prog );
19331974 return 0 ;
19341975 }
19351976
1977+ if (sbuf .st_uid != 0 /* getuid() ? */ ) {
1978+ warn ("Can't execute %s: Not root owned." , prog );
1979+ return 0 ;
1980+ }
1981+
1982+ if (0 != (sbuf .st_mode & (S_IWGRP | S_IWOTH ))) {
1983+ warn ("Can't execute %s: Writable by group or other." , prog );
1984+ return 0 ;
1985+ }
1986+
1987+ if (!S_ISREG (sbuf .st_mode ) || (sbuf .st_mode & (S_IXUSR )) == 0 ) {
1988+ warn ("Can't execute %s: Not a regular executable (for root) file." );
1989+ return 0 ;
1990+ }
1991+
19361992 pid = ppp_safe_fork (fd_devnull , fd_devnull , fd_devnull );
19371993 if (pid == -1 ) {
19381994 error ("Failed to create child process for %s: %m" , prog );
0 commit comments