summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--INSTALL2
-rw-r--r--configure.ac3
-rw-r--r--lib/fsm.c144
3 files changed, 142 insertions, 7 deletions
diff --git a/INSTALL b/INSTALL
index 677ef88c4..961a160e0 100644
--- a/INSTALL
+++ b/INSTALL
@@ -103,6 +103,8 @@ option to configure). For GCC, OpenMP 4.5 is fully supported since GCC 6.1,
which is available from
http://www.gnu.org/
+Rpm requires a POSIX.1-2008 level operating system.
+
To compile RPM:
--------------
diff --git a/configure.ac b/configure.ac
index 3ee340726..0099e5f34 100644
--- a/configure.ac
+++ b/configure.ac
@@ -580,7 +580,8 @@ AC_CHECK_FUNCS([secure_getenv __secure_getenv])
AC_CHECK_FUNCS(
[mkstemp getcwd basename dirname realpath setenv unsetenv regcomp lchown \
- utimes getline localtime_r statvfs getaddrinfo ],
+ utimes getline localtime_r statvfs getaddrinfo \
+ openat mkdirat fstatat ],
[], [AC_MSG_ERROR([function required by rpm])])
AC_LIBOBJ(fnmatch)
diff --git a/lib/fsm.c b/lib/fsm.c
index 911898347..b6b152ab1 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -8,6 +8,7 @@
#include <inttypes.h>
#include <utime.h>
#include <errno.h>
+#include <fcntl.h>
#if WITH_CAP
#include <sys/capability.h>
#endif
@@ -20,6 +21,7 @@
#include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */
#include "lib/fsm.h"
#include "lib/rpmte_internal.h" /* XXX rpmfs */
+#include "lib/rpmfi_internal.h" /* rpmfiSetOnChdir */
#include "lib/rpmplugins.h" /* rpm plugins hooks */
#include "lib/rpmug.h"
@@ -406,17 +408,118 @@ static int fsmRmdir(const char *path)
return rc;
}
-static int fsmMkdir(const char *path, mode_t mode)
+static int fsmMkdir(int dirfd, const char *path, mode_t mode)
{
- int rc = mkdir(path, (mode & 07777));
+ int rc = mkdirat(dirfd, path, (mode & 07777));
if (_fsm_debug)
- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__,
- path, (unsigned)(mode & 07777),
+ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%04o) %s\n", __func__,
+ dirfd, path, (unsigned)(mode & 07777),
(rc < 0 ? strerror(errno) : ""));
if (rc < 0) rc = RPMERR_MKDIR_FAILED;
return rc;
}
+static int fsmOpenat(int dirfd, const char *path, int flags)
+{
+ struct stat lsb, sb;
+ int sflags = flags | O_NOFOLLOW;
+ int fd = openat(dirfd, path, sflags);
+
+ /*
+ * Only ever follow symlinks by root or target owner. Since we can't
+ * open the symlink itself, the order matters: we stat the link *after*
+ * opening the target, and if the link ownership changed between the calls
+ * it could've only been the link owner or root.
+ */
+ if (fd < 0 && errno == ELOOP && flags != sflags) {
+ int ffd = openat(dirfd, path, flags);
+ if (ffd >= 0 && fstatat(dirfd, path, &lsb, AT_SYMLINK_NOFOLLOW) == 0) {
+ if (fstat(ffd, &sb) == 0) {
+ if (lsb.st_uid == 0 || lsb.st_uid == sb.st_uid) {
+ fd = ffd;
+ } else {
+ close(ffd);
+ }
+ }
+ }
+ }
+ return fd;
+}
+
+static int fsmDoMkDir(rpmPlugins plugins, int dirfd, const char *dn,
+ int owned, mode_t mode)
+{
+ int rc;
+ rpmFsmOp op = (FA_CREATE);
+ if (!owned)
+ op |= FAF_UNOWNED;
+
+ /* Run fsm file pre hook for all plugins */
+ rc = rpmpluginsCallFsmFilePre(plugins, NULL, dn, mode, op);
+
+ if (!rc)
+ rc = fsmMkdir(dirfd, dn, mode);
+
+ if (!rc) {
+ rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, dn, dn, mode, op);
+ }
+
+ /* Run fsm file post hook for all plugins */
+ rpmpluginsCallFsmFilePost(plugins, NULL, dn, mode, op, rc);
+
+ if (!rc) {
+ rpmlog(RPMLOG_DEBUG,
+ "%s directory created with perms %04o\n",
+ dn, (unsigned)(mode & 07777));
+ }
+
+ return rc;
+}
+
+static int ensureDir(rpmPlugins plugins, const char *p, int owned, int create)
+{
+ char *path = xstrdup(p);
+ char *dp = path;
+ char *sp = NULL, *bn;
+ int oflags = O_RDONLY;
+
+ int dirfd = fsmOpenat(-1, "/", oflags);
+ int fd = dirfd; /* special case of "/" */
+
+ while ((bn = strtok_r(dp, "/", &sp)) != NULL) {
+ struct stat sb;
+ fd = fsmOpenat(dirfd, bn, oflags);
+
+ if (fd < 0 && errno == ENOENT && create) {
+ mode_t mode = S_IFDIR | (_dirPerms & 07777);
+ if (fsmDoMkDir(plugins, dirfd, bn, owned, mode) == 0) {
+ fd = fsmOpenat(dirfd, bn, oflags|O_NOFOLLOW);
+ }
+ }
+
+ if (fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
+ close(fd);
+ errno = ENOTDIR;
+ fd = -1;
+ }
+
+ close(dirfd);
+ if (fd >= 0) {
+ dirfd = fd;
+ } else {
+ dirfd = -1;
+ rpmlog(RPMLOG_ERR, _("failed to open dir %s of %s: %s\n"),
+ bn, p, strerror(errno));
+ break;
+ }
+
+ dp = NULL;
+ }
+
+ free(path);
+ return dirfd;
+}
+
static int fsmMkfifo(const char *path, mode_t mode)
{
int rc = mkfifo(path, (mode & 07777));
@@ -507,7 +610,7 @@ static int fsmMkdirs(rpmfiles files, rpmfs fs, rpmPlugins plugins)
rc = rpmpluginsCallFsmFilePre(plugins, NULL, dn, mode, op);
if (!rc)
- rc = fsmMkdir(dn, mode);
+ rc = fsmMkdir(-1, dn, mode);
if (!rc) {
rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, dn, dn,
@@ -874,6 +977,21 @@ static void setFileState(rpmfs fs, int i)
}
}
+struct diriter_s {
+ int dirfd;
+};
+
+static int onChdir(rpmfi fi, void *data)
+{
+ struct diriter_s *di = data;
+
+ if (di->dirfd >= 0) {
+ close(di->dirfd);
+ di->dirfd = -1;
+ }
+ return 0;
+}
+
int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rpmpsm psm, char ** failedFile)
{
@@ -890,6 +1008,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
char *tid = NULL;
struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
struct filedata_s *firstlink = NULL;
+ struct diriter_s di = { -1 };
/* transaction id used for temporary path suffix while installing */
rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
@@ -932,6 +1051,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rc = RPMERR_BAD_MAGIC;
goto exit;
}
+ rpmfiSetOnChdir(fi, onChdir, &di);
/* Detect and create directories not explicitly in package. */
if (!rc)
@@ -946,6 +1066,16 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (!fp->suffix) {
rc = fsmBackup(fi, fp->action);
}
+
+ if (di.dirfd == -1) {
+ di.dirfd = ensureDir(plugins, rpmfiDN(fi), 0,
+ (fp->action == FA_CREATE));
+ if (di.dirfd == -1) {
+ rc = RPMERR_OPEN_FAILED;
+ break;
+ }
+ }
+
/* Assume file does't exist when tmp suffix is in use */
if (!fp->suffix) {
if (fp->action == FA_TOUCH) {
@@ -980,7 +1110,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
mode_t mode = fp->sb.st_mode;
mode &= ~07777;
mode |= 00700;
- rc = fsmMkdir(fp->fpath, mode);
+ rc = fsmMkdir(di.dirfd, fp->fpath, mode);
}
} else if (S_ISLNK(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
@@ -1022,6 +1152,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
fp->stage = FILE_UNPACK;
}
fi = rpmfiFree(fi);
+ close(di.dirfd);
+ di.dirfd = -1;
if (!rc && fx < 0 && fx != RPMERR_ITER_END)
rc = fx;