When deleting files, drop any s-bit first, so that a malicious user does not have access to old programs if he hard links them to some other directory. [#50376] rh#125517 Already in rpm-4.4.7. Index: lib/cpio.h =================================================================== --- lib/cpio.h.orig +++ lib/cpio.h @@ -64,7 +64,8 @@ typedef enum cpioMapFlags_e { CPIO_MAP_ABSOLUTE = (1 << 5), CPIO_MAP_ADDDOT = (1 << 6), CPIO_ALL_HARDLINKS = (1 << 7), /*!< fail if hardlinks are missing. */ - CPIO_MAP_TYPE = (1 << 8) /*!< only for building. */ + CPIO_MAP_TYPE = (1 << 8), /*!< only for building. */ + CPIO_SBIT_CHECK = (1 << 9) } cpioMapFlags; #define CPIO_NEWC_MAGIC "070701" Index: lib/fsm.c =================================================================== --- lib/fsm.c.orig +++ lib/fsm.c @@ -2127,6 +2127,11 @@ if (!(fsm->mapFlags & CPIO_ALL_HARDLINKS /*@notreached@*/ break; case FSM_UNLINK: + if (fsm->mapFlags & CPIO_SBIT_CHECK) { + struct stat stb; + if (Lstat(fsm->path, &stb) == 0 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) + chmod(fsm->path, stb.st_mode & 0777); + } rc = Unlink(fsm->path); if (_fsm_debug && (stage & FSM_SYSCALL)) rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur, Index: lib/psm.c =================================================================== --- lib/psm.c.orig +++ lib/psm.c @@ -1472,7 +1472,7 @@ assert(psm->mi == NULL); fi->striplen = (xx ? strlen(p) + 1 : 1); } fi->mapflags = - CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID; + CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID | (fi->mapflags & CPIO_SBIT_CHECK); if (headerIsEntry(fi->h, RPMTAG_ORIGBASENAMES)) rpmfiBuildFNames(fi->h, RPMTAG_ORIGBASENAMES, &fi->apath, NULL); Index: lib/transaction.c =================================================================== --- lib/transaction.c.orig +++ lib/transaction.c @@ -187,6 +187,13 @@ static int handleInstInstalledFiles(cons if (XFA_SKIPPING(fi->actions[fileNum])) continue; + if (!(fi->mapflags & CPIO_SBIT_CHECK)) { + int_16 omode = rpmfiFMode(otherFi); + if (S_ISREG(omode) && (omode & 06000) != 0) { + fi->mapflags |= CPIO_SBIT_CHECK; + } + } + if (rpmfiCompare(otherFi, fi)) { int rConflicts; @@ -1843,6 +1850,20 @@ rpmMessage(RPMMESS_DEBUG, _("computing f case TR_REMOVED: /*@switchbreak@*/ break; } + /* check for s-bit files to be removed */ + if (rpmteType(p) == TR_REMOVED) { + fi = rpmfiInit(fi, 0); + while ((i = rpmfiNext(fi)) >= 0) { + int_16 mode; + if (XFA_SKIPPING(fi->actions[i])) + continue; + (void) rpmfiSetFX(fi, i); + mode = rpmfiFMode(fi); + if (S_ISREG(mode) && (mode & 06000) != 0) { + fi->mapflags |= CPIO_SBIT_CHECK; + } + } + } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc); } pi = rpmtsiFree(pi); @@ -2088,6 +2109,7 @@ assert(psm != NULL); { char * fstates = fi->fstates; fileAction * actions = fi->actions; + int mapflags = fi->mapflags; rpmte savep; fi->fstates = NULL; @@ -2106,6 +2128,8 @@ assert(psm != NULL); fi->fstates = fstates; fi->actions = _free(fi->actions); fi->actions = actions; + if (mapflags & CPIO_SBIT_CHECK) + fi->mapflags |= CPIO_SBIT_CHECK; p->fi = fi; } }