MillaFleurs left a comment (rpm-software-management/rpm#4200)

Here's the patch.  Currently testing and once I've confirmed it works I'll 
create a PR.
```
--- a/lib/fsm.cc
+++ b/lib/fsm.cc
@@ -469,22 +469,33 @@ static int fsmMknod(int dirfd, const char *path, mode_t 
mode, dev_t dev)
     return rc;
 }

-static int removeSBITS(int dirfd, const char *path)
+/*
+ * Strip setuid/setgid (and file caps when WITH_CAP) from a regular file
+ * before we unlink/rename it.  *nlinkp is set to st_nlink so callers can
+ * decide how to react to a failure: when nlink > 1 the bits live on via
+ * the surviving hardlink and the failure is fatal; when nlink == 1 the
+ * unlink itself removes the inode so a stripping failure is harmless.
+ */
+static int removeSBITS(int dirfd, const char *path, nlink_t *nlinkp)
 {
     struct stat stb;
     int flags = AT_SYMLINK_NOFOLLOW;
     int rc = 0;
+    if (nlinkp)
+       *nlinkp = 0;
     if (fstatat(dirfd, path, &stb, flags) == 0 && S_ISREG(stb.st_mode)) {
-       /* XXX TODO: actually check for the rc, but what to do there? */
-       /* We now know it's not a link so no need to worry about following */
+       if (nlinkp)
+           *nlinkp = stb.st_nlink;
        if ((stb.st_mode & 06000) != 0) {
-           rc += fchmodat(dirfd, path, stb.st_mode & 0777, 0);
+           if (fchmodat(dirfd, path, stb.st_mode & 0777, 0) != 0)
+               rc = -1;
        }
 #ifdef WITH_CAP
        if (stb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) {
-           rc += cap_set_fileat(dirfd, path, NULL);
+           if (cap_set_fileat(dirfd, path, NULL) != 0)
+               rc = -1;
        }
 #endif
     }
     return rc;
 }
@@ -515,8 +526,17 @@ static int fsmSymlink(const char *opath, int dirfd, const 
char *path)

 static int fsmUnlink(int dirfd, const char *path)
 {
     int rc = 0;
-    removeSBITS(dirfd, path);
+    nlink_t nlink = 0;
+    if (removeSBITS(dirfd, path, &nlink) != 0 && nlink > 1) {
+       /* Surviving hardlinks would inherit the suid bits; refuse to
+        * remove the directory entry so the operator sees the failure. */
+       rpmlog(RPMLOG_ERR,
+              _("failed to strip suid/caps from %s with %u links; "
+                "refusing to unlink: %m\n"),
+              path, (unsigned)nlink);
+       return RPMERR_CHMOD_FAILED;
+    }
     rc = unlinkat(dirfd, path, 0);
     if (_fsm_debug)
        rpmlog(RPMLOG_DEBUG, " %8s (%d %s) %s\n", __func__,
@@ -528,7 +546,14 @@ static int fsmUnlink(int dirfd, const char *path)

 static int fsmRename(int odirfd, const char *opath, int dirfd, const char 
*path)
 {
-    removeSBITS(dirfd, path);
+    nlink_t nlink = 0;
+    if (removeSBITS(dirfd, path, &nlink) != 0 && nlink > 1) {
+       rpmlog(RPMLOG_ERR,
+              _("failed to strip suid/caps from %s with %u links; "
+                "refusing to rename: %m\n"),
+              path, (unsigned)nlink);
+       return RPMERR_CHMOD_FAILED;
+    }
     int rc = renameat(odirfd, opath, dirfd, path);
 #if defined(ETXTBSY) && defined(__HPUX__)
     /* XXX HP-UX (and other os'es) don't permit rename to busy files. */
```

-- 
Reply to this email directly or view it on GitHub:
https://github.com/rpm-software-management/rpm/issues/4200#issuecomment-4378581310
You are receiving this because you are subscribed to this thread.

Message ID: <rpm-software-management/rpm/issues/4200/[email protected]>
_______________________________________________
Rpm-maint mailing list
[email protected]
https://lists.rpm.org/mailman/listinfo/rpm-maint

Reply via email to