--- ../safeugid.diff 2019-10-02 13:37:13.191868203 +0200 +++ P 2019-10-02 13:36:09.036002978 +0200 @@ -0,0 +1,211 @@ +--- ./lib/rpmchroot.c.orig 2019-06-26 14:17:31.411985696 +0000 ++++ ./lib/rpmchroot.c 2019-10-02 11:35:58.788024507 +0000 +@@ -126,6 +126,7 @@ int rpmChrootIn(void) + + if (chdir("/") == 0 && chroot(rootState.rootDir) == 0) { + rootState.chrootDone = 1; ++ rpmugChroot(1); + } else { + rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n")); + rc = -1; +@@ -151,6 +152,7 @@ int rpmChrootOut(void) + } else if (rootState.chrootDone == 1) { + if (chroot(".") == 0 && fchdir(rootState.cwd) == 0) { + rootState.chrootDone = 0; ++ rpmugChroot(0); + } else { + rpmlog(RPMLOG_ERR, _("Unable to restore root directory: %m\n")); + rc = -1; +--- ./lib/rpmug.c.orig 2019-06-26 14:17:31.418985685 +0000 ++++ ./lib/rpmug.c 2019-10-02 11:35:58.788024507 +0000 +@@ -11,6 +11,47 @@ + #include "lib/rpmug.h" + #include "debug.h" + ++#if defined(__GLIBC__) ++ ++static int inchroot; ++ ++/* ++ * Unfortunatelly glibc caches nss/nscd data and there is no ++ * good way to flush those caches when we did a chroot(). Thus ++ * we need to parse /etc/passwd and /etc/group ourselfs. ++ */ ++static int safe_lookup(const char * file, const char * name) ++{ ++ FILE *fp; ++ int l; ++ char buf[4096], *p; ++ ++ if (!name || !*name) ++ return -1; ++ l = strlen(name); ++ if ((fp = fopen(file, "r")) == 0) ++ return -1; ++ while ((p = fgets(buf, sizeof(buf), fp)) != 0) { ++ if (*p == '#') ++ continue; ++ while (*p && (*p == ' ' || *p == '\t')) ++ p++; ++ if (strncmp(p, name, l) != 0 || p[l] != ':') ++ continue; ++ p = strchr(p + l + 1, ':'); ++ if (!p) ++ continue; ++ fclose(fp); ++ p++; ++ while (*p && (*p == ' ' || *p == '\t')) ++ p++; ++ return atoi(p); ++ } ++ fclose(fp); ++ return -1; ++} ++#endif ++ + /* + * These really ought to use hash tables. I just made the + * guess that most files would be owned by root or the same person/group +@@ -44,17 +85,28 @@ int rpmugUid(const char * thisUname, uid + lastUnameAlloced = thisUnameLen + 10; + lastUname = xrealloc(lastUname, lastUnameAlloced); /* XXX memory leak */ + } +- strcpy(lastUname, thisUname); + +- pwent = getpwnam(thisUname); +- if (pwent == NULL) { +- /* FIX: shrug */ +- endpwent(); ++#if defined(__GLIBC__) ++ if (inchroot) { ++ int uid = safe_lookup("/etc/passwd", thisUname); ++ if (uid < 0) ++ return -1; ++ lastUid = uid; ++ } else ++#endif ++ { + pwent = getpwnam(thisUname); +- if (pwent == NULL) return -1; ++ if (pwent == NULL) { ++ /* FIX: shrug */ ++ endpwent(); ++ pwent = getpwnam(thisUname); ++ if (pwent == NULL) return -1; ++ } ++ lastUid = pwent->pw_uid; + } + +- lastUid = pwent->pw_uid; ++ strcpy(lastUname, thisUname); ++ lastUnameLen = thisUnameLen; + } + + *uid = lastUid; +@@ -87,18 +139,29 @@ int rpmugGid(const char * thisGname, gid + lastGnameAlloced = thisGnameLen + 10; + lastGname = xrealloc(lastGname, lastGnameAlloced); /* XXX memory leak */ + } +- strcpy(lastGname, thisGname); + +- grent = getgrnam(thisGname); +- if (grent == NULL) { +- /* FIX: shrug */ +- endgrent(); ++#if defined(__GLIBC__) ++ if (inchroot) { ++ int gid = safe_lookup("/etc/group", thisGname); ++ if (gid < 0) ++ return -1; ++ lastGid = gid; ++ } else ++#endif ++ { + grent = getgrnam(thisGname); + if (grent == NULL) { +- return -1; ++ /* FIX: shrug */ ++ endgrent(); ++ grent = getgrnam(thisGname); ++ if (grent == NULL) { ++ return -1; ++ } + } ++ lastGid = grent->gr_gid; + } +- lastGid = grent->gr_gid; ++ strcpy(lastGname, thisGname); ++ lastGnameLen = thisGnameLen; + } + + *gid = lastGid; +@@ -110,7 +173,7 @@ const char * rpmugUname(uid_t uid) + { + static uid_t lastUid = (uid_t) -1; + static char * lastUname = NULL; +- static size_t lastUnameLen = 0; ++ static size_t lastUnameAlloced = 0; + + if (uid == (uid_t) -1) { + lastUid = (uid_t) -1; +@@ -127,9 +190,9 @@ const char * rpmugUname(uid_t uid) + + lastUid = uid; + len = strlen(pwent->pw_name); +- if (lastUnameLen < len + 1) { +- lastUnameLen = len + 20; +- lastUname = xrealloc(lastUname, lastUnameLen); ++ if (lastUnameAlloced < len + 1) { ++ lastUnameAlloced = len + 20; ++ lastUname = xrealloc(lastUname, lastUnameAlloced); + } + strcpy(lastUname, pwent->pw_name); + +@@ -141,7 +204,7 @@ const char * rpmugGname(gid_t gid) + { + static gid_t lastGid = (gid_t) -1; + static char * lastGname = NULL; +- static size_t lastGnameLen = 0; ++ static size_t lastGnameAlloced = 0; + + if (gid == (gid_t) -1) { + lastGid = (gid_t) -1; +@@ -158,9 +221,9 @@ const char * rpmugGname(gid_t gid) + + lastGid = gid; + len = strlen(grent->gr_name); +- if (lastGnameLen < len + 1) { +- lastGnameLen = len + 20; +- lastGname = xrealloc(lastGname, lastGnameLen); ++ if (lastGnameAlloced < len + 1) { ++ lastGnameAlloced = len + 20; ++ lastGname = xrealloc(lastGname, lastGnameAlloced); + } + strcpy(lastGname, grent->gr_name); + +@@ -192,3 +255,16 @@ void rpmugFree(void) + rpmugUname(-1); + rpmugGname(-1); + } ++ ++void rpmugChroot(int in) ++{ ++ /* tell libc to drop caches / file descriptors */ ++ endpwent(); ++ endgrent(); ++ /* drop our own caches */ ++ rpmugUid(NULL, NULL); ++ rpmugGid(NULL, NULL); ++#if defined(__GLIBC__) ++ inchroot = in; ++#endif ++} +--- ./lib/rpmug.h.orig 2019-06-26 14:17:31.418985685 +0000 ++++ ./lib/rpmug.h 2019-10-02 11:35:58.788024507 +0000 +@@ -15,4 +15,6 @@ int rpmugInit(void); + + void rpmugFree(void); + ++void rpmugChroot(int in); ++ + #endif /* _RPMUG_H */