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

guillem pushed a commit to branch main
in repository dpkg.

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

commit ed6bbd445dd8800308c67236ba35d08004c98e82 (HEAD -> main)
Author: Guillem Jover <[email protected]>
AuthorDate: Sat Jun 7 14:17:07 2025 +0200

    dpkg-deb: Fix cleanup for control member with restricted directories
    
    When extracting a control member into a temporary directory, which is
    documented as being a safe operation even on untrusted data, the code
    in charge of the temporary directory cleanup does not sanitize the
    directory permissions, which is then unable to perform the «rm -rf»
    when running as a non-root user, leaving temporary files behind.
    
    Given automated and repeated execution of dpkg-deb commands on
    adversarial .deb packages or with well compressible files, placed
    inside a directory with permissions not allowing removal by a non-root
    user, this can end up with a DoS scenario due to causing disk quota
    exhaustion or disk full conditions.
    
    This is considered a minor issue, given the required conditions to
    trigger a problem with it, but an issue non the less given the
    documented security guarantees of the command. This has been an
    issue since the initial commit introducing dpkg-deb in C.
    
    We use an existing string for the error message to avoid new strings
    needing translation for stable branches, which make the error message
    less descriptive than what would be ideal. This will be improved in
    git HEAD.
    
    Reported-by: zhutyra on HackerOne
    Fixes: CVE-2025-6297
    Stable-Candidate: 1.20.x 1.21.x 1.22.x
---
 src/at/deb-content.at | 32 ++++++++++++++++++++++++++++++++
 src/deb/info.c        | 20 ++++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/src/at/deb-content.at b/src/at/deb-content.at
index a192c9493..2b1d8b0f4 100644
--- a/src/at/deb-content.at
+++ b/src/at/deb-content.at
@@ -127,3 +127,35 @@ newline'
 ])
 
 AT_CLEANUP
+
+AT_SETUP([dpkg-deb .deb extraction cleanup])
+AT_KEYWORDS([dpkg-deb deb extraction])
+
+DPKG_GEN_CONTROL([pkg-ctrl-dir-perms])
+AT_CHECK([
+dpkg-deb --root-owner-group -Znone -b pkg-ctrl-dir-perms
+DPKG_AR_EXTRACT([pkg-ctrl-dir-perms.deb])
+dpkg-deb -R pkg-ctrl-dir-perms.deb pkg-ctrl-dir-perms-bad
+mkdir -p pkg-ctrl-dir-perms-bad/DEBIAN/rx-subdir/inner
+touch pkg-ctrl-dir-perms-bad/DEBIAN/rx-subdir/inner/file
+chmod 0555 pkg-ctrl-dir-perms-bad/DEBIAN
+chmod 0555 pkg-ctrl-dir-perms-bad/DEBIAN/rx-subdir
+chmod 0555 pkg-ctrl-dir-perms-bad/DEBIAN/rx-subdir/inner
+$TAR cf control.tar --format=gnu --mtime @0 --clamp-mtime --owner root:0 
--group root:0 -C pkg-ctrl-dir-perms-bad/DEBIAN .
+DPKG_AR_GEN([pkg-ctrl-dir-perms.deb], [debian-binary control.tar data.tar])
+], [0], [dpkg-deb: building package 'pkg-ctrl-dir-perms' in 
'pkg-ctrl-dir-perms.deb'.
+])
+AT_CHECK([
+dpkg-deb --ctrl-tarfile pkg-ctrl-dir-perms.deb | $TAR tvf -
+], [0], [dr-xr-xr-x root/root         0 1970-01-01 00:00 ./
+dr-xr-xr-x root/root         0 1970-01-01 00:00 ./rx-subdir/
+dr-xr-xr-x root/root         0 1970-01-01 00:00 ./rx-subdir/inner/
+-rw-r--r-- root/root         0 1970-01-01 00:00 ./rx-subdir/inner/file
+-rw-r--r-- root/root       176 1970-01-01 00:00 ./control
+])
+# Check that we can cleanup the temporarily extracted control.tar member.
+AT_CHECK([
+dpkg-deb -I pkg-ctrl-dir-perms.deb
+], [0], [ignore])
+
+AT_CLEANUP
diff --git a/src/deb/info.c b/src/deb/info.c
index f3d57e2ce..396ea4d14 100644
--- a/src/deb/info.c
+++ b/src/deb/info.c
@@ -45,14 +45,34 @@
 #include <dpkg/pkg-format.h>
 #include <dpkg/buffer.h>
 #include <dpkg/path.h>
+#include <dpkg/treewalk.h>
 #include <dpkg/options.h>
 
 #include "dpkg-deb.h"
 
+static int
+cu_info_treewalk_fixup_dir(struct treenode *node)
+{
+  const char *nodename;
+
+  if (!S_ISDIR(treenode_get_mode(node)))
+    return 0;
+
+  nodename = treenode_get_pathname(node);
+  if (chmod(nodename, 0755) < 0)
+    ohshite(_("error setting permissions of '%.255s'"), nodename);
+
+  return 0;
+}
+
 static void cu_info_prepare(int argc, void **argv) {
   char *dir;
+  struct treewalk_funcs cu_info_treewalk_funcs = {
+    .visit = cu_info_treewalk_fixup_dir,
+  };
 
   dir = argv[0];
+  treewalk(dir, TREEWALK_NONE, &cu_info_treewalk_funcs);
   path_remove_tree(dir);
   free(dir);
 }

-- 
Dpkg.Org's dpkg

Reply via email to