diff --git a/lib/fsm.c b/lib/fsm.c index f8767706f..ceb38d463 100644 --- a/lib/fsm.c +++ b/lib/fsm.c @@ -650,7 +650,7 @@ static int fsmUtime(const char *path, mode_t mode, time_t mtime) return rc; } -static int fsmVerify(const char *path, rpmfi fi) +static int fsmVerify(const char *path, rpmfi fi, const struct stat *fsb) { int rc; int saveerrno = errno; @@ -675,11 +675,14 @@ static int fsmVerify(const char *path, rpmfi fi) } else if (S_ISDIR(mode)) { if (S_ISDIR(dsb.st_mode)) return 0; if (S_ISLNK(dsb.st_mode)) { + uid_t luid = dsb.st_uid; rc = fsmStat(path, 0, &dsb); if (rc == RPMERR_ENOENT) rc = 0; if (rc) return rc; errno = saveerrno; - if (S_ISDIR(dsb.st_mode)) return 0; + /* Only permit directory symlinks by target owner and root */ + if (S_ISDIR(dsb.st_mode) && (luid == 0 || luid == fsb->st_uid)) + return 0; } } else if (S_ISLNK(mode)) { if (S_ISLNK(dsb.st_mode)) { @@ -921,7 +924,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, } /* Assume file does't exist when tmp suffix is in use */ if (!suffix) { - rc = fsmVerify(fpath, fi); + rc = fsmVerify(fpath, fi, &sb); } else { rc = (action == FA_TOUCH) ? 0 : RPMERR_ENOENT; } diff --git a/tests/data/SPECS/replacetest.spec b/tests/data/SPECS/replacetest.spec index e8a64e803..c764adc27 100644 --- a/tests/data/SPECS/replacetest.spec +++ b/tests/data/SPECS/replacetest.spec @@ -1,5 +1,6 @@ %{!?filetype: %global filetype file} %{?fixit: %global havepretrans 1} +%{!?user: %global user root} Name: replacetest%{?sub:-%{sub}} Version: %{ver} @@ -43,5 +44,5 @@ rm -rf $RPM_BUILD_ROOT %endif %files -%defattr(-,root,root,-) +%defattr(-,%{user},%{user},-) /opt/* diff --git a/tests/rpmreplace.at b/tests/rpmreplace.at index 90a85bfb8..11e6221d7 100644 --- a/tests/rpmreplace.at +++ b/tests/rpmreplace.at @@ -398,6 +398,40 @@ tf="${RPMTEST}"/opt/foo rm -rf "${RPMTEST}"/opt/* rm -rf "${TOPDIR}" +runroot rpmbuild --quiet -bb \ + --define "ver 1.0" \ + --define "filetype datadir" \ + --define "filedata README1" \ + --define "user $(id -u -n)" \ + /data/SPECS/replacetest.spec + +runroot rpmbuild --quiet -bb \ + --define "ver 2.0" \ + --define "filetype datadir" \ + --define "filedata README2" \ + --define "user $(id -u -n)" \ + /data/SPECS/replacetest.spec + +mkdir "${RPMTEST}"/opt/f00f +ln -s f00f "${RPMTEST}"/opt/foo +runroot rpm -U /build/RPMS/noarch/replacetest-1.0-1.noarch.rpm +test -L "${tf}" && test -d "${tf}" && runroot rpm -U /build/RPMS/noarch/replacetest-2.0-1.noarch.rpm +test -L "${tf}" && test -d "${tf}" +], +[0], +[], +[]) +AT_CLEANUP + +AT_SETUP([upgrade invalid locally symlinked directory]) +AT_KEYWORDS([install]) +AT_CHECK([ +RPMDB_CLEAR +RPMDB_INIT +tf="${RPMTEST}"/opt/foo +rm -rf "${RPMTEST}"/opt/* +rm -rf "${TOPDIR}" + runroot rpmbuild --quiet -bb \ --define "ver 1.0" \ --define "filetype datadir" \ @@ -414,7 +448,7 @@ mkdir "${RPMTEST}"/opt/f00f ln -s f00f "${RPMTEST}"/opt/foo runroot rpm -U /build/RPMS/noarch/replacetest-1.0-1.noarch.rpm test -L "${tf}" && test -d "${tf}" && runroot rpm -U /build/RPMS/noarch/replacetest-2.0-1.noarch.rpm -test -L "${tf}" && test -d "${tf}" +test -d "${tf}" ], [0], [],