File safesymlinks.diff of Package rpm
--- ./lib/fsm.c.orig 2018-05-24 14:35:41.136841262 +0000
+++ ./lib/fsm.c 2018-09-19 14:23:49.206077104 +0000
@@ -722,7 +722,7 @@ static int fsmMapAttrs(FSM_t fsm)
* @param archive payload archive
* @return 0 on success
*/
-static int expandRegular(FSM_t fsm, rpmpsm psm, rpmcpio_t archive, int nodigest)
+static int expandRegular(FSM_t fsm, rpmpsm psm, rpmcpio_t archive, int exclusive, int nodigest)
{
FD_t wfd = NULL;
const struct stat * st = &fsm->sb;
@@ -735,7 +735,7 @@ static int expandRegular(FSM_t fsm, rpmp
/* Create the file with 000 permissions. */
{
mode_t old_umask = umask(0777);
- wfd = Fopen(fsm->path, "w.ufdio");
+ wfd = Fopen(fsm->path, exclusive ? "wx.ufdio" : "w.ufdio");
umask(old_umask);
}
if (Ferror(wfd)) {
@@ -1472,11 +1472,14 @@ static int fsmVerify(FSM_t fsm)
} else if (S_ISDIR(st->st_mode)) {
if (S_ISDIR(ost->st_mode)) return 0;
if (S_ISLNK(ost->st_mode)) {
+ uid_t luid = ost->st_uid;
rc = fsmStat(fsm->path, 0, &fsm->osb);
if (rc == CPIOERR_ENOENT) rc = 0;
if (rc) return rc;
errno = saveerrno;
- if (S_ISDIR(ost->st_mode)) return 0;
+ /* Only permit directory symlinks by target owner and root */
+ if (S_ISDIR(ost->st_mode) && (luid == 0 || luid == ost->st_uid))
+ return 0;
}
} else if (S_ISLNK(st->st_mode)) {
if (S_ISLNK(ost->st_mode)) {
@@ -1699,7 +1702,7 @@ int rpmPackageFilesInstall(rpmts ts, rpm
if (S_ISREG(st->st_mode)) {
rc = fsmVerify(fsm);
if (!(rc == CPIOERR_ENOENT)) return rc;
- rc = expandRegular(fsm, psm, archive, nodigest);
+ rc = expandRegular(fsm, psm, archive, fsm->suffix ? 1 : 0, nodigest);
} else if (S_ISDIR(st->st_mode)) {
/* Directories replacing something need early backup */
rc = fsmBackup(fsm);
--- ./lib/verify.c.orig 2018-05-24 14:35:41.136841262 +0000
+++ ./lib/verify.c 2018-09-19 14:31:10.888882282 +0000
@@ -96,6 +96,18 @@ int rpmVerifyFile(const rpmts ts, const
return 1;
}
+ /* If we expected a directory but got a symlink to one, follow the link */
+ if (S_ISDIR(fmode) && S_ISLNK(sb.st_mode)) {
+ struct stat dsb;
+ /* ...if it actually points to a directory */
+ if (stat(fn, &dsb) == 0 && S_ISDIR(dsb.st_mode)) {
+ /* ...and is by a legit user, to match fsmVerify() behavior */
+ if (sb.st_uid == 0 || sb.st_uid == dsb.st_uid) {
+ sb = dsb; /* struct assignment */
+ }
+ }
+ }
+
/* Links have no mode, other types have no linkto */
if (S_ISLNK(sb.st_mode))
flags &= ~(RPMVERIFY_MODE);