Fix a crash in rdistd triggered by the recent getpw{ent,nam,uid}
authormillert <millert@openbsd.org>
Sun, 9 Sep 2018 13:53:11 +0000 (13:53 +0000)
committermillert <millert@openbsd.org>
Sun, 9 Sep 2018 13:53:11 +0000 (13:53 +0000)
changes.  This stems from rdist stashing a pointer to the static
area used by getpw{ent,nam,uid} and using it to avoid repeating
passwd lookups when pw->pw_name matches the user to be looked up.

This relied on undefined behavior, and with the recent passwd
changes, is no longer possible as the old pointer will be invalidated.
A better approach is to use the upcoming uid_from_user(3) functions.
Found by and fix OK tim@

usr.bin/rdist/common.c
usr.bin/rdist/defs.h
usr.bin/rdist/expand.c
usr.bin/rdistd/server.c

index 1927e2f..62efc88 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: common.c,v 1.37 2015/12/22 08:48:39 mmcc Exp $        */
+/*     $OpenBSD: common.c,v 1.38 2018/09/09 13:53:11 millert Exp $     */
 
 /*
  * Copyright (c) 1983 Regents of the University of California.
@@ -65,7 +65,6 @@ char                 *currenthost = NULL;     /* Current client hostname */
 char                  *progname = NULL;        /* Name of this program */
 int                    rem_r = -1;             /* Client file descriptor */
 int                    rem_w = -1;             /* Client file descriptor */
-struct passwd         *pw = NULL;              /* Local user's pwd entry */
 volatile sig_atomic_t  contimedout = FALSE;    /* Connection timed out */
 int                    rtimeout = RTIMEOUT;    /* Response time out */
 jmp_buf                        finish_jmpbuf;          /* Finish() jmp buffer */
@@ -107,6 +106,7 @@ xwrite(int fd, void *buf, size_t len)
 int
 init(int argc, char **argv, char **envp)
 {
+       struct passwd *pw;
        int i;
 
        /*
@@ -572,6 +572,7 @@ response(void)
 char *
 exptilde(char *ebuf, char *file, size_t ebufsize)
 {
+       struct passwd *pw;
        char *pw_dir, *rest;
        size_t len;
 
@@ -580,11 +581,10 @@ notilde:
                (void) strlcpy(ebuf, file, ebufsize);
                return(ebuf);
        }
+       pw_dir = homedir;
        if (*++file == CNULL) {
-               pw_dir = homedir;
                rest = NULL;
        } else if (*file == '/') {
-               pw_dir = homedir;
                rest = file;
        } else {
                rest = file;
@@ -594,17 +594,17 @@ notilde:
                        *rest = CNULL;
                else
                        rest = NULL;
-               if (pw == NULL || strcmp(pw->pw_name, file) != 0) {
+               if (strcmp(locuser, file) != 0) {
                        if ((pw = getpwnam(file)) == NULL) {
                                error("%s: unknown user name", file);
                                if (rest != NULL)
                                        *rest = '/';
                                return(NULL);
                        }
+                       pw_dir = pw->pw_dir;
                }
                if (rest != NULL)
                        *rest = '/';
-               pw_dir = pw->pw_dir;
        }
        if ((len = strlcpy(ebuf, pw_dir, ebufsize)) >= ebufsize)
                goto notilde;
index 80bfe48..88ae077 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: defs.h,v 1.36 2015/01/21 03:05:03 guenther Exp $      */
+/*     $OpenBSD: defs.h,v 1.37 2018/09/09 13:53:11 millert Exp $       */
 
 #ifndef __DEFS_H__
 #define __DEFS_H__
@@ -166,8 +166,8 @@ extern int          rem_r;          /* Remote file descriptor, reading */
 extern int             rem_w;          /* Remote file descriptor, writing */
 extern int             rtimeout;       /* Response time out in seconds */
 extern uid_t           userid;         /* User ID of rdist user */
+extern gid_t           groupid;        /* Group ID of rdist user */
 extern jmp_buf         finish_jmpbuf;  /* Setjmp buffer for finish() */
-extern struct passwd   *pw;    /* pointer to static area used by getpwent */
 extern char defowner[64];              /* Default owner */
 extern char defgroup[64];              /* Default group */
 extern volatile sig_atomic_t contimedout; /* Connection timed out */
index 8a1e5e3..bdc1582 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: expand.c,v 1.15 2015/01/20 09:00:16 guenther Exp $    */
+/*     $OpenBSD: expand.c,v 1.16 2018/09/09 13:53:11 millert Exp $     */
 
 /*
  * Copyright (c) 1983 Regents of the University of California.
@@ -260,6 +260,8 @@ expstr(u_char *s)
                return;
        }
        if (*s == '~') {
+               struct passwd *pw;
+
                cp = ++s;
                if (*cp == CNULL || *cp == '/') {
                        tilde = "~";
@@ -271,8 +273,7 @@ expstr(u_char *s)
                                *cp1++ = *cp++;
                        while (*cp && *cp != '/');
                        *cp1 = CNULL;
-                       if (pw == NULL || strcmp(pw->pw_name, 
-                                                (char *)ebuf+1) != 0) {
+                       if (strcmp(locuser, (char *)ebuf+1) != 0) {
                                if ((pw = getpwnam((char *)ebuf+1)) == NULL) {
                                        strlcat((char *)ebuf, 
                                                ": unknown user name",
@@ -280,8 +281,10 @@ expstr(u_char *s)
                                        yyerror((char *)ebuf+1);
                                        return;
                                }
+                               cp1 = (u_char *)pw->pw_dir;
+                       } else {
+                               cp1 = (u_char *)homedir;
                        }
-                       cp1 = (u_char *)pw->pw_dir;
                        s = cp;
                }
                for (cp = (u_char *)path; (*cp++ = *cp1++) != '\0'; )
index e86f764..21f1d41 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server.c,v 1.43 2017/08/30 07:43:52 otto Exp $        */
+/*     $OpenBSD: server.c,v 1.44 2018/09/09 13:53:11 millert Exp $     */
 
 /*
  * Copyright (c) 1983 Regents of the University of California.
@@ -188,7 +188,9 @@ fchog(int fd, char *file, char *owner, char *group, int mode)
        if (userid == 0) {      /* running as root; take anything */
                if (*owner == ':') {
                        uid = (uid_t) atoi(owner + 1);
-               } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) {
+               } else if (strcmp(owner, locuser) != 0) {
+                       struct passwd *pw;
+
                        if ((pw = getpwnam(owner)) == NULL) {
                                if (mode != -1 && IS_ON(mode, S_ISUID)) {
                                        message(MT_NOTICE,
@@ -203,8 +205,8 @@ fchog(int fd, char *file, char *owner, char *group, int mode)
                        } else
                                uid = pw->pw_uid;
                } else {
-                       uid = pw->pw_uid;
-                       primegid = pw->pw_gid;
+                       uid = userid;
+                       primegid = groupid;
                }
                if (*group == ':') {
                        gid = (gid_t)atoi(group + 1);