From 4a6ec615e0b892f1f397132beec4216815a805c8 Mon Sep 17 00:00:00 2001 From: millert Date: Sun, 9 Sep 2018 13:53:11 +0000 Subject: [PATCH] Fix a crash in rdistd triggered by the recent getpw{ent,nam,uid} 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 | 12 ++++++------ usr.bin/rdist/defs.h | 4 ++-- usr.bin/rdist/expand.c | 11 +++++++---- usr.bin/rdistd/server.c | 10 ++++++---- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/usr.bin/rdist/common.c b/usr.bin/rdist/common.c index 1927e2f1c4f..62efc8806a1 100644 --- a/usr.bin/rdist/common.c +++ b/usr.bin/rdist/common.c @@ -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; diff --git a/usr.bin/rdist/defs.h b/usr.bin/rdist/defs.h index 80bfe48785c..88ae0778649 100644 --- a/usr.bin/rdist/defs.h +++ b/usr.bin/rdist/defs.h @@ -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 */ diff --git a/usr.bin/rdist/expand.c b/usr.bin/rdist/expand.c index 8a1e5e36c61..bdc158281a1 100644 --- a/usr.bin/rdist/expand.c +++ b/usr.bin/rdist/expand.c @@ -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'; ) diff --git a/usr.bin/rdistd/server.c b/usr.bin/rdistd/server.c index e86f764dad8..21f1d4145fb 100644 --- a/usr.bin/rdistd/server.c +++ b/usr.bin/rdistd/server.c @@ -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); -- 2.20.1