summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog2
-rw-r--r--src/archives.c23
-rw-r--r--src/errors.c8
-rw-r--r--src/main.h1
-rw-r--r--src/script.c9
-rw-r--r--t/cppcheck/cppcheck.supp2
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