This is an automated email from the git hooks/post-receive script.

guillem pushed a commit to branch master
in repository dpkg.

View the commit online:
https://git.dpkg.org/cgit/dpkg/dpkg.git/commit/?id=eebc650619521acffdd7acfd00f833d6face21d3

commit eebc650619521acffdd7acfd00f833d6face21d3
Author: Guillem Jover <[email protected]>
AuthorDate: Mon Oct 8 11:35:00 2018 +0200

    dpkg: Fix --force-not-root
    
    Ignore EPERM for chown and chmod based syscalls. And give a more
    meaningful error message on chroot().
    
    Closes: #614126
---
 debian/changelog         |  2 ++
 src/archives.c           | 23 +++++++++++++++++------
 src/errors.c             |  8 ++++++++
 src/main.h               |  1 +
 src/script.c             |  9 ++++++++-
 t/cppcheck/cppcheck.supp |  2 +-
 6 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 500111abe..eb68b75dc 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,8 @@
 dpkg (1.19.2) UNRELEASED; urgency=medium
 
   [ Guillem Jover ]
+  * dpkg: Fix --force-not-root for chown() and chmod() based syscalls, and
+    give a more meaningful error message on chroot(). Closes: #614126
   * Perl modules:
     - Dpkg::OpenPGP: Ignore Version field in enarmored output.
       Fixes CPAN#127217.
diff --git a/src/archives.c b/src/archives.c
index e802baaee..a1013d73a 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -353,6 +353,7 @@ tarobject_extract(struct tarcontext *tc, struct tar_entry 
*te,
   char fnamebuf[256];
   char fnamenewbuf[256];
   char *newhash;
+  int rc;
 
   switch (te->type) {
   case TAR_FILETYPE_FILE:
@@ -388,9 +389,11 @@ tarobject_extract(struct tarcontext *tc, struct tar_entry 
*te,
             namenode->statoverride->uid,
             namenode->statoverride->gid,
             namenode->statoverride->mode);
-    if (fchown(fd, st->uid, st->gid))
+    rc = fchown(fd, st->uid, st->gid);
+    if (forcible_nonroot_error(rc))
       ohshite(_("error setting ownership of '%.255s'"), te->name);
-    if (fchmod(fd, st->mode & ~S_IFMT))
+    rc = fchmod(fd, st->mode & ~S_IFMT);
+    if (forcible_nonroot_error(rc))
       ohshite(_("error setting permissions of '%.255s'"), te->name);
 
     /* Postpone the fsync, to try to avoid massive I/O degradation. */
@@ -497,16 +500,21 @@ tarobject_set_mtime(struct tar_entry *te, const char 
*path)
 static void
 tarobject_set_perms(struct tar_entry *te, const char *path, struct file_stat 
*st)
 {
+  int rc;
+
   if (te->type == TAR_FILETYPE_FILE)
     return; /* Already handled using the file descriptor. */
 
   if (te->type == TAR_FILETYPE_SYMLINK) {
-    if (lchown(path, st->uid, st->gid))
+    rc = lchown(path, st->uid, st->gid);
+    if (forcible_nonroot_error(rc))
       ohshite(_("error setting ownership of symlink '%.255s'"), path);
   } else {
-    if (chown(path, st->uid, st->gid))
+    rc = chown(path, st->uid, st->gid);
+    if (forcible_nonroot_error(rc))
       ohshite(_("error setting ownership of '%.255s'"), path);
-    if (chmod(path, st->mode & ~S_IFMT))
+    rc = chmod(path, st->mode & ~S_IFMT);
+    if (forcible_nonroot_error(rc))
       ohshite(_("error setting permissions of '%.255s'"), path);
   }
 }
@@ -1020,6 +1028,8 @@ tarobject(void *ctx, struct tar_entry *ti)
         ohshite(_("unable to move aside '%.255s' to install new version"),
                 ti->name);
     } else if (S_ISLNK(stab.st_mode)) {
+      int rc;
+
       /* We can't make a symlink with two hardlinks, so we'll have to
        * copy it. (Pretend that making a copy of a symlink is the same
        * as linking to it.) */
@@ -1038,7 +1048,8 @@ tarobject(void *ctx, struct tar_entry *ti)
       varbuf_end_str(&symlinkfn);
       if (symlink(symlinkfn.buf,fnametmpvb.buf))
         ohshite(_("unable to make backup symlink for '%.255s'"), ti->name);
-      if (lchown(fnametmpvb.buf,stab.st_uid,stab.st_gid))
+      rc = lchown(fnametmpvb.buf, stab.st_uid, stab.st_gid);
+      if (forcible_nonroot_error(rc))
         ohshite(_("unable to chown backup symlink for '%.255s'"), ti->name);
       tarobject_set_se_context(fnamevb.buf, fnametmpvb.buf, stab.st_mode);
     } else {
diff --git a/src/errors.c b/src/errors.c
index 3d2d71967..6fa940856 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -146,3 +146,11 @@ void forcibleerr(int forceflag, const char *fmt, ...) {
   }
   va_end(args);
 }
+
+int
+forcible_nonroot_error(int rc)
+{
+  if (fc_nonroot && errno == EPERM)
+    return 0;
+  return rc;
+}
diff --git a/src/main.h b/src/main.h
index 319d8afd0..d1b31b196 100644
--- a/src/main.h
+++ b/src/main.h
@@ -228,6 +228,7 @@ void cu_prermremove(int argc, void **argv);
 void print_error_perpackage(const char *emsg, const void *data);
 void print_error_perarchive(const char *emsg, const void *data);
 void forcibleerr(int forceflag, const char *format, ...) DPKG_ATTR_PRINTF(2);
+int forcible_nonroot_error(int rc);
 int reportbroken_retexitstatus(int ret);
 bool skip_due_to_hold(struct pkginfo *pkg);
 
diff --git a/src/script.c b/src/script.c
index 66792135b..0865b953f 100644
--- a/src/script.c
+++ b/src/script.c
@@ -106,6 +106,8 @@ maintscript_pre_exec(struct command *cmd)
                changedir = "/";
 
        if (instdirlen > 0 && !fc_script_chrootless) {
+               int rc;
+
                if (strncmp(admindir, instdir, instdirlen) != 0)
                        ohshit(_("admindir must be inside instdir for dpkg to 
work properly"));
                if (setenv("DPKG_ADMINDIR", admindir + instdirlen, 1) < 0)
@@ -113,7 +115,12 @@ maintscript_pre_exec(struct command *cmd)
                if (setenv("DPKG_ROOT", "", 1) < 0)
                        ohshite(_("unable to setenv for subprocesses"));
 
-               if (chroot(instdir))
+               rc = chroot(instdir);
+               if (rc && fc_nonroot && errno == EPERM)
+                       ohshit(_("not enough privileges to change root "
+                                "directory with --force-not-root, consider "
+                                "using --force-script-chrootless?"));
+               else if (rc)
                        ohshite(_("failed to chroot to '%.250s'"), instdir);
        }
        /* Switch to a known good directory to give the maintainer script
diff --git a/t/cppcheck/cppcheck.supp b/t/cppcheck/cppcheck.supp
index e7888e513..7f11afac0 100644
--- a/t/cppcheck/cppcheck.supp
+++ b/t/cppcheck/cppcheck.supp
@@ -13,7 +13,7 @@ unusedStructMember:lib/compat/obstack.c
 nullPointerArithmetic:lib/compat/obstack.c
 
 // Ignore, we use this construct to ease portability.
-knownConditionTrueFalse:src/script.c:162
+knownConditionTrueFalse:src/script.c:169
 
 // Ignore, We use our own test assertions macros.
 literalWithCharPtrCompare:lib/dpkg/t/t-test.c

-- 
Dpkg.Org's dpkg

Reply via email to