Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package bubblewrap for openSUSE:Factory 
checked in at 2026-10-23 20:21:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/bubblewrap (Old)
 and      /work/SRC/openSUSE:Factory/.bubblewrap.new.2252680 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "bubblewrap"

Fri Oct 23 20:21:57 2026 rev:26 rq:1387012 version:0.13.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/bubblewrap/bubblewrap.changes    2026-09-08 
16:53:40.891868413 +0200
+++ /work/SRC/openSUSE:Factory/.bubblewrap.new.2252680/bubblewrap.changes       
2026-10-23 20:22:21.780667878 +0200
@@ -1,0 +2,42 @@
+Thu Oct 15 02:32:00 UTC 2026 - Kyle Scheuing <[email protected]>
+
+- update to 0.13.1:
+  * bwrap now accepts multiple --sync-fd arguments and will handle
+    all of the fds.
+  * O_PATH is used when opening parent directories in the new root,
+    fixing an error when read permission is missing.
+
+
+-------------------------------------------------------------------
+Tue Oct 13 22:24:12 UTC 2026 - Kyle Scheuing <[email protected]>
+
+- update to 0.13.0:
+  * Linux kernel headers with __NR_pivot_root (Linux 2.3.41+) are
+    required at build-time on all architectures
+  * If compiled with -Dassume_kernel=5.12.0 or newer, then a kernel with
+    the mount_setattr syscall is required at runtime, and kernel headers
+    with __NR_mount_setattr are required at build-time on most
+    architectures. On the x86_64, i386 and aarch64 architectures, a
+    fallback is provided to be able to compile with pre-5.12 kernel
+    headers.
+  * On kernels that support it (5.12+), use mount_setattr() to remount
+    filesystems with ro, nodev and/or nosuid.
+  * Arguments that expect a path argument (--bind, --overlay-src, etc.)
+    now reject empty strings. Previously they would sometimes be treated
+    as the root directory due to implementation details, but this was
+    unintended.
+  * A new build option -Ddebug_logging=true can be used to enable
+    verbose debug logging (not recommended for distro builds). These
+    debug messages don't appear unless environment variable
+    DEBUG_INVOCATION is set at runtime.
+  * Fix build failures with older gcc or older -std argument
+  * Fix build failure with musl
+  * Fix test failure on systems that lack hostname(1)
+  * Fix test failure on systems with a mount point containing a
+    backslash
+  * Fix test failure on systems with older xdg-desktop-portal
+  * Don't leave a temporary file behind after running the test suite
+  * CI improvements
+
+
+-------------------------------------------------------------------

Old:
----
  bubblewrap-0.12.0.tar.xz
  bubblewrap-0.12.0.tar.xz.sha256sum

New:
----
  bubblewrap-0.13.1.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ bubblewrap.spec ++++++
--- /var/tmp/diff_new_pack.ne9zx3/_old  2026-10-23 20:22:22.419694414 +0200
+++ /var/tmp/diff_new_pack.ne9zx3/_new  2026-10-23 20:22:22.420694456 +0200
@@ -18,14 +18,13 @@
 
 
 Name:           bubblewrap
-Version:        0.12.0
+Version:        0.13.1
 Release:        0
 Summary:        Core execution tool for unprivileged containers
 License:        LGPL-2.1-or-later
 Group:          Productivity/Security
 URL:            https://github.com/containers/bubblewrap
 Source0:        %{url}/releases/download/v%{version}/%{name}-%{version}.tar.xz
-Source1:        
%{url}/releases/download/v%{version}/%{name}-%{version}.tar.xz.sha256sum
 # https://www.pseudorandom.co.uk/2003/contact/
 # 0x4DE8FF2A63C7CC90, fingerprint: DA98 F25C 0871 C49A 59EA FF2C 4DE8 FF2A 
63C7 CC90
 BuildRequires:  docbook-xsl-stylesheets

++++++ bubblewrap-0.12.0.tar.xz -> bubblewrap-0.13.1.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/.editorconfig 
new/bubblewrap-0.13.1/.editorconfig
--- old/bubblewrap-0.12.0/.editorconfig 2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/.editorconfig 2026-10-14 14:13:57.000000000 +0200
@@ -1,5 +1,15 @@
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
 [*.[ch]]
 indent_style = space
 indent_size = 2
-trim_trailing_whitespace = true
 indent_brace_style = gnu
+
+[*.py]
+indent_style = space
+indent_size = 4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/.github/dependabot.yml 
new/bubblewrap-0.13.1/.github/dependabot.yml
--- old/bubblewrap-0.12.0/.github/dependabot.yml        1970-01-01 
01:00:00.000000000 +0100
+++ new/bubblewrap-0.13.1/.github/dependabot.yml        2026-10-14 
14:13:57.000000000 +0200
@@ -0,0 +1,10 @@
+version: 2
+updates:
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "monthly"
+    groups:
+      actions:
+        patterns:
+          - "*"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/.github/workflows/check.yml 
new/bubblewrap-0.13.1/.github/workflows/check.yml
--- old/bubblewrap-0.12.0/.github/workflows/check.yml   2026-08-26 
12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/.github/workflows/check.yml   2026-10-14 
14:13:57.000000000 +0200
@@ -8,13 +8,16 @@
     branches:
     - main
 
+permissions:
+  contents: read
+
 jobs:
   meson:
     name: Build with Meson and gcc, and test
     runs-on: ubuntu-latest
     steps:
     - name: Check out
-      uses: actions/checkout@v4
+      uses: actions/checkout@v7
     - name: Install build-dependencies
       run: sudo ./ci/builddeps.sh
     - name: Enable user namespaces
@@ -23,13 +26,10 @@
       run: mkdir test-logs
     - name: setup
       run: |
-        meson _build
+        meson setup _build -Db_sanitize=address,undefined -Ddebug_logging=true 
-Doptimization=2
       env:
         CFLAGS: >-
-          -O2
           -Wp,-D_FORTIFY_SOURCE=2
-          -fsanitize=address
-          -fsanitize=undefined
     - name: compile
       run: ninja -C _build -v
     - name: smoke-test
@@ -38,11 +38,13 @@
         ./_build/bwrap --bind / / --tmpfs /tmp true
       env:
         ASAN_OPTIONS: detect_leaks=0
+        DEBUG_INVOCATION: '1'
     - name: test
       run: |
         BWRAP_MUST_WORK=1 meson test -C _build
       env:
         ASAN_OPTIONS: detect_leaks=0
+        DEBUG_INVOCATION: '1'
     - name: Collect overall test logs on failure
       if: failure()
       run: mv _build/meson-logs/testlog.txt test-logs/ || true
@@ -71,7 +73,7 @@
         test ! -e DESTDIR-as-subproject/usr/local/libexec/bwrap
         tests/use-as-subproject/assert-correct-rpath.py 
DESTDIR-as-subproject/usr/local/libexec/not-flatpak-bwrap
     - name: Upload test logs
-      uses: actions/upload-artifact@v4
+      uses: actions/upload-artifact@v7
       if: failure() || cancelled()
       with:
         name: test logs
@@ -80,6 +82,8 @@
   clang:
     name: Build with clang and analyze
     runs-on: ubuntu-latest
+    permissions:
+      security-events: write
     strategy:
       fail-fast: false
       matrix:
@@ -87,19 +91,18 @@
           - cpp
     steps:
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v2
+      uses: github/codeql-action/init@v4
       with:
         languages: ${{ matrix.language }}
     - name: Check out
-      uses: actions/checkout@v4
+      uses: actions/checkout@v7
     - name: Install build-dependencies
       run: sudo ./ci/builddeps.sh --clang
-    - run: meson build -Dselinux=enabled
+    - run: meson setup build -Doptimization=2 -Dselinux=enabled
       env:
         CC: clang
         CFLAGS: >-
-          -O2
           -Werror=unused-variable
     - run: meson compile -C build
     - name: CodeQL analysis
-      uses: github/codeql-action/analyze@v2
+      uses: github/codeql-action/analyze@v4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/.gitignore 
new/bubblewrap-0.13.1/.gitignore
--- old/bubblewrap-0.12.0/.gitignore    1970-01-01 01:00:00.000000000 +0100
+++ new/bubblewrap-0.13.1/.gitignore    2026-10-14 14:13:57.000000000 +0200
@@ -0,0 +1 @@
+__pycache__/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/NEWS.md 
new/bubblewrap-0.13.1/NEWS.md
--- old/bubblewrap-0.12.0/NEWS.md       2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/NEWS.md       2026-10-14 14:13:57.000000000 +0200
@@ -1,8 +1,84 @@
+bubblewrap 0.13.1
+=================
+
+Released: 2026-10-14
+
+Enhancements:
+
+  * bwrap now accepts multiple --sync-fd arguments and will handle
+    all of the fds.
+
+Bug fixes:
+
+  * O_PATH is used when opening parent directories in the new root,
+    fixing an error when read permission is missing. (#806, #855).
+
+Thanks: smcv, swick
+
+bubblewrap 0.13.0
+=================
+
+Released: 2026-09-22
+
+Dependencies:
+
+  * Linux kernel headers with `__NR_pivot_root` (Linux 2.3.41+)
+    are required at build-time on all architectures (#789).
+
+  * If compiled with `-Dassume_kernel=5.12.0` or newer,
+    then a kernel with the `mount_setattr` syscall is required at runtime,
+    and kernel headers with `__NR_mount_setattr` are required at build-time
+    on most architectures.
+    On the `x86_64`, `i386` and `aarch64` architectures,
+    a fallback is provided to be able to compile with pre-5.12 kernel headers.
+    (#756, #785)
+
+Enhancements:
+
+  * On kernels that support it (5.12+), use `mount_setattr()` to remount
+    filesystems with `ro`, `nodev` and/or `nosuid`. (#756)
+
+  * Arguments that expect a path argument (`--bind`, `--overlay-src`, etc.)
+    now reject empty strings.
+    Previously they would sometimes be treated as the root directory
+    due to implementation details, but this was unintended.
+    (#771)
+
+  * A new build option `-Ddebug_logging=true` can be used to enable
+    verbose debug logging (not recommended for distro builds).
+    These debug messages don't appear unless environment variable
+    `DEBUG_INVOCATION` is set at runtime.
+
+Bug fixes:
+
+  * Fix build failures with older gcc or older `-std` argument (#773, #786)
+
+  * Fix build failure with musl (#782)
+
+  * Fix test failure on systems that lack hostname(1) (#775)
+
+  * Fix test failure on systems with a mount point containing a backslash
+    (#778)
+
+  * Fix test failure on systems with older xdg-desktop-portal (#794)
+
+  * Don't leave a temporary file behind after running the test suite (#775)
+
+  * CI improvements
+
+Thanks: abhinavmir, ao2, smcv, vaibhav8a, xxyzz
+
 bubblewrap 0.12.0
 =================
 
 Released: 2026-08-26
 
+Dependencies:
+
+  * If compiled with `-Dassume_kernel=5.6.0` or newer,
+    then a kernel with the `openat2` syscall is required at runtime,
+    and kernel headers with `__NR_openat2` are required at build-time.
+
 Enhancements:
 
  * The flag --not-a-security-boundary was added. If this is enabled
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/README.md 
new/bubblewrap-0.13.1/README.md
--- old/bubblewrap-0.12.0/README.md     2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/README.md     2026-10-14 14:13:57.000000000 +0200
@@ -86,7 +86,7 @@
 If you need to build bubblewrap from source, you can do this with meson:
 
 ```sh
-meson _builddir
+meson setup _builddir
 meson compile -C _builddir
 meson test -C _builddir
 meson install -C _builddir
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/bind-mount.c 
new/bubblewrap-0.13.1/bind-mount.c
--- old/bubblewrap-0.12.0/bind-mount.c  2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/bind-mount.c  2026-10-14 14:13:57.000000000 +0200
@@ -24,6 +24,23 @@
 #include "utils.h"
 #include "bind-mount.h"
 
+#if ASSUMED_KERNEL < BWRAP_KERNEL_VERSION (5, 12, 0)
+#  define USE_MOUNT_SETATTR_FALLBACK 1
+#else
+#  define USE_MOUNT_SETATTR_FALLBACK 0
+#endif
+
+static bind_mount_result mount_setattr_setup (const char *resolved_dest,
+                                              bind_option_t options,
+                                              char **failing_path);
+
+static bind_mount_result mount_setattr_fallback (const char *resolved_dest,
+                                                 bind_option_t options,
+                                                 char **failing_path);
+
+bool opt_force_mount_setattr_fallback = false;
+
+#if USE_MOUNT_SETATTR_FALLBACK
 static char *
 skip_token (char *line, bool eat_whitespace)
 {
@@ -372,6 +389,7 @@
 
   return steal_pointer (&mount_tab);
 }
+#endif /* USE_MOUNT_SETATTR_FALLBACK */
 
 bind_mount_result
 bind_mount (const char   *src,
@@ -408,14 +426,9 @@
                bind_option_t options,
                char        **failing_path)
 {
-  bool readonly = (options & BIND_READONLY) != 0;
-  bool devices = (options & BIND_DEVICES) != 0;
   bool recursive = (options & BIND_RECURSIVE) != 0;
-  unsigned long current_flags, new_flags;
-  cleanup_mount_tab MountTab mount_tab = NULL;
   cleanup_free char *resolved_dest = NULL;
   cleanup_free char *dest_proc = NULL;
-  int i;
 
   dest_proc = fd_to_proc_path (dest_fd);
 
@@ -451,11 +464,43 @@
         }
     }
 
+  return mount_setattr_setup (resolved_dest, options, failing_path);
+}
+
+static bind_mount_result
+mount_setattr_fallback (const char *resolved_dest,
+                        bind_option_t options,
+                        char **failing_path)
+{
+#if !USE_MOUNT_SETATTR_FALLBACK
+  debug ("No mount_setattr fallback");
+  (void) resolved_dest;
+  (void) options;
+
+  if (failing_path != NULL)
+    *failing_path = xstrdup (resolved_dest);
+
+  errno = ENOSYS;
+  return BIND_MOUNT_ERROR_MOUNT_SETATTR;
+#else
+  bool readonly = (options & BIND_READONLY) != 0;
+  bool devices = (options & BIND_DEVICES) != 0;
+  bool recursive = (options & BIND_RECURSIVE) != 0;
+  unsigned long current_flags, new_flags;
+  cleanup_mount_tab MountTab mount_tab = NULL;
+  int i;
+
+  debug ("Remounting mount table entries (%s %s) on  \"%s\" %s",
+         readonly ? "ro" : "rw",
+         devices ? "dev" : "nodev",
+         resolved_dest,
+         recursive ? "recursively" : "only");
+
   mount_tab = parse_mountinfo (resolved_dest);
   if (mount_tab[0].mountpoint == NULL)
     {
       if (failing_path != NULL)
-        *failing_path = steal_pointer (&resolved_dest);
+        *failing_path = xstrdup (resolved_dest);
 
       errno = EINVAL;
       return BIND_MOUNT_ERROR_FIND_DEST_MOUNT;
@@ -469,7 +514,7 @@
              NULL, MS_SILENT | MS_BIND | MS_REMOUNT | new_flags, NULL) != 0)
     {
       if (failing_path != NULL)
-        *failing_path = steal_pointer (&resolved_dest);
+        *failing_path = xstrdup (resolved_dest);
 
       return BIND_MOUNT_ERROR_REMOUNT_DEST;
     }
@@ -482,6 +527,7 @@
     {
       for (i = 1; mount_tab[i].mountpoint != NULL; i++)
         {
+          debug ("Acting on submount %s", mount_tab[i].mountpoint);
           current_flags = mount_tab[i].options;
           new_flags = current_flags | (devices ? 0 : MS_NODEV) | MS_NOSUID | 
(readonly ? MS_RDONLY : 0);
           if (new_flags != current_flags &&
@@ -510,7 +556,9 @@
         }
     }
 
+  debug ("-> success");
   return BIND_MOUNT_SUCCESS;
+#endif /* USE_MOUNT_SETATTR_FALLBACK */
 }
 
 /**
@@ -556,6 +604,10 @@
                             failing_path);
         break;
 
+      case BIND_MOUNT_ERROR_MOUNT_SETATTR:
+        string = xasprintf ("mount_setattr() failed at \"%s\"", failing_path);
+        break;
+
       case BIND_MOUNT_SUCCESS:
         string = xstrdup ("Success");
         break;
@@ -608,6 +660,7 @@
           case BIND_MOUNT_ERROR_READLINK_DEST_PROC_FD:
           case BIND_MOUNT_ERROR_FIND_DEST_MOUNT:
           case BIND_MOUNT_ERROR_OPEN_FD:
+          case BIND_MOUNT_ERROR_MOUNT_SETATTR:
           case BIND_MOUNT_SUCCESS:
           default:
             fprintf (stderr, ": %s", strerror (saved_errno));
@@ -617,3 +670,67 @@
   fprintf (stderr, "\n");
   exit (1);
 }
+
+static bind_mount_result
+mount_setattr_setup (const char *resolved_dest,
+                     bind_option_t options,
+                     char **failing_path)
+{
+  static bool mount_attr_supported = true;
+  bool readonly = (options & BIND_READONLY) != 0;
+  bool devices = (options & BIND_DEVICES) != 0;
+  bool recursive = (options & BIND_RECURSIVE) != 0;
+
+  if (mount_attr_supported && !opt_force_mount_setattr_fallback)
+    {
+      struct mount_attr attr = {
+        .attr_clr = 0,
+        .attr_set = MOUNT_ATTR_NOSUID,
+      };
+
+      debug ("Setting mount attributes (%s %s) on  \"%s\" %s",
+             readonly ? "ro" : "rw",
+             devices ? "dev" : "nodev",
+             resolved_dest,
+             recursive ? "recursively" : "only");
+
+      if (!devices)
+        attr.attr_set |= MOUNT_ATTR_NODEV;
+
+      if (readonly)
+        attr.attr_set |= MOUNT_ATTR_RDONLY;
+
+      unsigned int setattr_flags = AT_EMPTY_PATH;
+
+      if (recursive)
+        setattr_flags |= AT_RECURSIVE;
+
+      /* reopen dest_fd after mount() */
+      cleanup_fd int resolved_dest_fd =
+        TEMP_FAILURE_RETRY(open(resolved_dest, O_PATH | O_CLOEXEC));
+      if (resolved_dest_fd < 0)
+        {
+          if (failing_path != NULL)
+            *failing_path = xstrdup (resolved_dest);
+
+          return BIND_MOUNT_ERROR_OPEN_FD;
+        }
+
+      if (mount_setattr_wrapper (resolved_dest_fd, "", setattr_flags, &attr, 
sizeof(attr)) == 0)
+        {
+          debug ("-> success");
+          return BIND_MOUNT_SUCCESS;
+        }
+      else if (errno != ENOSYS)
+        {
+          if (failing_path != NULL)
+            *failing_path = xstrdup (resolved_dest);
+          return BIND_MOUNT_ERROR_MOUNT_SETATTR;
+        }
+
+      debug ("-> Falling back");
+    }
+  /* mount_setattr(2) isn't available, so we'll have to do this the hard way: 
*/
+  mount_attr_supported = false;
+  return mount_setattr_fallback (resolved_dest, options, failing_path);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/bind-mount.h 
new/bubblewrap-0.13.1/bind-mount.h
--- old/bubblewrap-0.12.0/bind-mount.h  2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/bind-mount.h  2026-10-14 14:13:57.000000000 +0200
@@ -37,6 +37,7 @@
   BIND_MOUNT_ERROR_REMOUNT_DEST,
   BIND_MOUNT_ERROR_REMOUNT_SUBMOUNT,
   BIND_MOUNT_ERROR_OPEN_FD,
+  BIND_MOUNT_ERROR_MOUNT_SETATTR,
 } bind_mount_result;
 
 bind_mount_result bind_mount (const char   *src,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/bubblewrap.c 
new/bubblewrap-0.13.1/bubblewrap.c
--- old/bubblewrap-0.12.0/bubblewrap.c  2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/bubblewrap.c  2026-10-14 14:13:57.000000000 +0200
@@ -21,6 +21,7 @@
 
 #include <poll.h>
 #include <sched.h>
+#include <limits.h>
 #include <pwd.h>
 #include <grp.h>
 #include <ctype.h>
@@ -78,7 +79,8 @@
 static bool opt_die_with_parent = false;
 static uid_t opt_sandbox_uid = -1;
 static gid_t opt_sandbox_gid = -1;
-static int opt_sync_fd = -1;
+static int *opt_sync_fd = NULL;
+static int opt_sync_fd_count = 0;
 static int opt_block_fd = -1;
 static int opt_userns_block_fd = -1;
 static int opt_info_fd = -1;
@@ -1041,7 +1043,7 @@
   fn = xstrdup (path);
   p = fn;
 
-  cleanup_fd int parent_fd = openat_in_root ("/newroot", "/", O_DIRECTORY);
+  cleanup_fd int parent_fd = openat_in_root ("/newroot", "/", O_DIRECTORY | 
O_PATH | O_CLOEXEC);
 
   while (*p == '/')
     p++;
@@ -1071,7 +1073,7 @@
 
       char saved = *after_component;
       *after_component = 0;
-      cleanup_fd int new_parent_fd = openat_in_root ("/newroot", fn, 
O_DIRECTORY);
+      cleanup_fd int new_parent_fd = openat_in_root ("/newroot", fn, 
O_DIRECTORY | O_PATH | O_CLOEXEC);
       *after_component = saved;
       if (new_parent_fd < 0)
         return -1;
@@ -1707,6 +1709,20 @@
   warn ("Only the last %s option will take effect", name);
 }
 
+/* Path arguments are turned into real filenames by concatenating them onto
+   "/oldroot/" or "/newroot/", so an empty path would silently be taken to
+   mean the root directory. That is never what the caller meant, so treat it
+   as a usage error. */
+static const char *
+path_argument (const char *option,
+               const char *path)
+{
+  if (path[0] == '\0')
+    die ("%s does not take an empty path argument", option);
+
+  return path;
+}
+
 static void
 make_setup_overlay_src_ops (const char *const *const argv)
 {
@@ -1728,7 +1744,7 @@
   for (i = 1; i <= next_overlay_src_count; i++)
     {
       op = setup_op_new (SETUP_OVERLAY_SRC);
-      op->source = argv[1 - 2 * i];
+      op->source = path_argument ("--overlay-src", argv[1 - 2 * i]);
     }
   next_overlay_src_count = 0;
 }
@@ -1906,7 +1922,7 @@
           if (opt_chdir_path != NULL)
             warn_only_last_option ("--chdir");
 
-          opt_chdir_path = argv[1];
+          opt_chdir_path = path_argument (arg, argv[1]);
           argv++;
           argc--;
         }
@@ -1924,7 +1940,7 @@
             die ("--remount-ro takes one argument");
 
           op = setup_op_new (SETUP_REMOUNT_RO_NO_RECURSIVE);
-          op->dest = argv[1];
+          op->dest = path_argument (arg, argv[1]);
 
           argv++;
           argc--;
@@ -1936,8 +1952,8 @@
             die ("%s takes two arguments", arg);
 
           op = setup_op_new (SETUP_BIND_MOUNT);
-          op->source = argv[1];
-          op->dest = argv[2];
+          op->source = path_argument (arg, argv[1]);
+          op->dest = path_argument (arg, argv[2]);
           if (strcmp(arg, "--bind-try") == 0)
             op->flags = ALLOW_NOTEXIST;
 
@@ -1951,8 +1967,8 @@
             die ("%s takes two arguments", arg);
 
           op = setup_op_new (SETUP_RO_BIND_MOUNT);
-          op->source = argv[1];
-          op->dest = argv[2];
+          op->source = path_argument (arg, argv[1]);
+          op->dest = path_argument (arg, argv[2]);
           if (strcmp(arg, "--ro-bind-try") == 0)
             op->flags = ALLOW_NOTEXIST;
 
@@ -1966,8 +1982,8 @@
             die ("%s takes two arguments", arg);
 
           op = setup_op_new (SETUP_DEV_BIND_MOUNT);
-          op->source = argv[1];
-          op->dest = argv[2];
+          op->source = path_argument (arg, argv[1]);
+          op->dest = path_argument (arg, argv[2]);
           if (strcmp(arg, "--dev-bind-try") == 0)
             op->flags = ALLOW_NOTEXIST;
 
@@ -1993,7 +2009,7 @@
             op = setup_op_new (SETUP_BIND_MOUNT);
           op->source = xasprintf ("/proc/self/fd/%d", src_fd);
           op->fd = src_fd;
-          op->dest = argv[2];
+          op->dest = path_argument (arg, argv[2]);
 
           argv += 2;
           argc -= 2;
@@ -2016,10 +2032,10 @@
             die ("--overlay requires at least one --overlay-src");
 
           op = setup_op_new (SETUP_OVERLAY_MOUNT);
-          op->source = argv[1];
+          op->source = path_argument (arg, argv[1]);
           workdir_op = setup_op_new (SETUP_OVERLAY_SRC);
-          workdir_op->source = argv[2];
-          op->dest = argv[3];
+          workdir_op->source = path_argument (arg, argv[2]);
+          op->dest = path_argument (arg, argv[3]);
           make_setup_overlay_src_ops (argv);
 
           argv += 3;
@@ -2034,7 +2050,7 @@
             die ("--tmp-overlay requires at least one --overlay-src");
 
           op = setup_op_new (SETUP_TMP_OVERLAY_MOUNT);
-          op->dest = argv[1];
+          op->dest = path_argument (arg, argv[1]);
           make_setup_overlay_src_ops (argv);
           opt_tmp_overlay_count++;
 
@@ -2050,7 +2066,7 @@
             die ("--ro-overlay requires at least two --overlay-src");
 
           op = setup_op_new (SETUP_RO_OVERLAY_MOUNT);
-          op->dest = argv[1];
+          op->dest = path_argument (arg, argv[1]);
           make_setup_overlay_src_ops (argv);
 
           argv += 1;
@@ -2062,7 +2078,7 @@
             die ("--proc takes an argument");
 
           op = setup_op_new (SETUP_MOUNT_PROC);
-          op->dest = argv[1];
+          op->dest = path_argument (arg, argv[1]);
 
           argv += 1;
           argc -= 1;
@@ -2103,7 +2119,7 @@
             die ("--dev takes an argument");
 
           op = setup_op_new (SETUP_MOUNT_DEV);
-          op->dest = argv[1];
+          op->dest = path_argument (arg, argv[1]);
           opt_needs_devpts = true;
 
           argv += 1;
@@ -2115,7 +2131,7 @@
             die ("--tmpfs takes an argument");
 
           op = setup_op_new (SETUP_MOUNT_TMPFS);
-          op->dest = argv[1];
+          op->dest = path_argument (arg, argv[1]);
 
           /* We historically hard-coded the mode of a tmpfs as 0755. */
           if (next_perms >= 0)
@@ -2140,7 +2156,7 @@
             die ("--mqueue takes an argument");
 
           op = setup_op_new (SETUP_MOUNT_MQUEUE);
-          op->dest = argv[1];
+          op->dest = path_argument (arg, argv[1]);
 
           argv += 1;
           argc -= 1;
@@ -2151,7 +2167,7 @@
             die ("--dir takes an argument");
 
           op = setup_op_new (SETUP_MAKE_DIR);
-          op->dest = argv[1];
+          op->dest = path_argument (arg, argv[1]);
 
           /* We historically hard-coded the mode of a --dir as 0755. */
           if (next_perms >= 0)
@@ -2177,7 +2193,7 @@
 
           op = setup_op_new (SETUP_MAKE_FILE);
           op->fd = file_fd;
-          op->dest = argv[2];
+          op->dest = path_argument (arg, argv[2]);
 
           /* We historically hard-coded the mode of a --file as 0666. */
           if (next_perms >= 0)
@@ -2203,7 +2219,7 @@
 
           op = setup_op_new (SETUP_MAKE_BIND_FILE);
           op->fd = file_fd;
-          op->dest = argv[2];
+          op->dest = path_argument (arg, argv[2]);
 
           /* This is consistent with previous bubblewrap behaviour:
            * before implementing --perms, we took the permissions
@@ -2231,7 +2247,7 @@
 
           op = setup_op_new (SETUP_MAKE_RO_BIND_FILE);
           op->fd = file_fd;
-          op->dest = argv[2];
+          op->dest = path_argument (arg, argv[2]);
 
           /* This is consistent with previous bubblewrap behaviour:
            * before implementing --perms, we took the permissions
@@ -2251,8 +2267,8 @@
             die ("--symlink takes two arguments");
 
           op = setup_op_new (SETUP_MAKE_SYMLINK);
-          op->source = argv[1];
-          op->dest = argv[2];
+          op->source = path_argument (arg, argv[1]);
+          op->dest = path_argument (arg, argv[2]);
 
           argv += 2;
           argc -= 2;
@@ -2262,7 +2278,7 @@
           if (argc < 2)
             die ("--lock-file takes an argument");
 
-          (void) lock_file_new (argv[1]);
+          (void) lock_file_new (path_argument (arg, argv[1]));
 
           argv += 1;
           argc -= 1;
@@ -2275,14 +2291,12 @@
           if (argc < 2)
             die ("--sync-fd takes an argument");
 
-          if (opt_sync_fd != -1)
-            warn_only_last_option ("--sync-fd");
-
           the_fd = strtol (argv[1], &endptr, 10);
           if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0)
             die ("Invalid fd: %s", argv[1]);
 
-          opt_sync_fd = the_fd;
+          opt_sync_fd = xrealloc (opt_sync_fd, sizeof (&opt_sync_fd[0]) * 
(opt_sync_fd_count + 1));
+          opt_sync_fd[opt_sync_fd_count++] = the_fd;
 
           argv += 1;
           argc -= 1;
@@ -2692,7 +2706,7 @@
           op = setup_op_new (SETUP_CHMOD);
           op->flags = NO_CREATE_DEST;
           op->perms = (int) perms;
-          op->dest = argv[2];
+          op->dest = path_argument (arg, argv[2]);
 
           argv += 2;
           argc -= 2;
@@ -2704,10 +2718,31 @@
       else if (has_prefix (arg, "--debug-opt="))
         {
           const char *val = arg + strlen ("--debug-opt=");
+
           if (strcmp (val, "force-openat-fallback") == 0)
-            opt_force_openat_fallback = true;
+            {
+              opt_force_openat_fallback = true;
+            }
+          else if (strcmp (val, "force-mount-setattr-fallback") == 0)
+            {
+              opt_force_mount_setattr_fallback = true;
+            }
+          else if (strcmp (val, "print-assumed-kernel") == 0)
+            {
+#ifdef HAVE_ASSUMED_KERNEL
+              printf ("%u.%u.%u\n",
+                      ASSUMED_KERNEL_MAJOR,
+                      ASSUMED_KERNEL_MINOR,
+                      ASSUMED_KERNEL_PATCH);
+#else
+              printf ("0.0.0\n");
+#endif
+              exit (0);
+            }
           else
-            die ("Unknown --debug-opt value: %s", val);
+            {
+              die ("Unknown --debug-opt value: %s", val);
+            }
         }
       else if (strcmp (arg, "--") == 0)
         {
@@ -2872,7 +2907,7 @@
   if (argc == 2 && (strcmp (argv[1], "--version") == 0))
     print_version_and_exit ();
 
-  /* Reset SIGCHILD to SIG_DFL allowing signalfd working propertly
+  /* Reset SIGCHILD to SIG_DFL allowing signalfd working properly
    * if the parent process had set SIGCHLD to SIG_IGN. */
   sigemptyset (&sa.sa_mask);
   sa.sa_handler = SIG_DFL;
@@ -2884,6 +2919,11 @@
   /* Get the (optional) privileges we need */
   acquire_privs ();
 
+#ifdef BWRAP_DEBUG
+  if (getenv ("DEBUG_INVOCATION") != NULL)
+    bwrap_is_debugging = true;
+#endif
+
   /* Never gain any more privs during exec */
   if (prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
     die_with_error ("prctl(PR_SET_NO_NEW_PRIVS) failed");
@@ -3436,7 +3476,7 @@
 
   debug ("forking for child");
 
-  if (!opt_as_pid_1 && (opt_unshare_pid || lock_files != NULL || opt_sync_fd 
!= -1))
+  if (!opt_as_pid_1 && (opt_unshare_pid || lock_files != NULL || 
opt_sync_fd_count > 0))
     {
       /* We have to have a pid 1 in the pid namespace, because
        * otherwise we'll get a bunch of zombies as nothing reaps
@@ -3458,14 +3498,16 @@
              process).
              Any other fds will been passed on to the child though. */
           {
-            int dont_close[3];
+            int *dont_close = xcalloc (opt_sync_fd_count + 2, sizeof (int));
             int j = 0;
+            int k;
             if (event_fd != -1)
               dont_close[j++] = event_fd;
-            if (opt_sync_fd != -1)
-              dont_close[j++] = opt_sync_fd;
+            for (k = 0; k < opt_sync_fd_count; k++)
+              dont_close[j++] = opt_sync_fd[k];
             dont_close[j++] = -1;
             fdwalk (close_extra_fds, dont_close);
+            free (dont_close);
           }
 
           return do_init (event_fd, pid);
@@ -3481,8 +3523,9 @@
      --sync-fd will still work unless the container process doesn't close this 
file.  */
   if (!opt_as_pid_1)
     {
-      if (opt_sync_fd != -1)
-        close (opt_sync_fd);
+      int k;
+      for (k = 0; k < opt_sync_fd_count; k++)
+        close (opt_sync_fd[k]);
     }
 
   /* We want sigchild in the child */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/bwrap.xml 
new/bubblewrap-0.13.1/bwrap.xml
--- old/bubblewrap-0.12.0/bwrap.xml     2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/bwrap.xml     2026-10-14 14:13:57.000000000 +0200
@@ -73,6 +73,10 @@
     When options are used multiple times, the last option wins, unless 
otherwise
     specified.
   </para>
+  <para>
+    An empty string is not a valid path, so options that take a path
+    reject it with an error.
+  </para>
   <para>General options:</para>
   <variablelist>
     <varlistentry>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/ci/builddeps.sh 
new/bubblewrap-0.13.1/ci/builddeps.sh
--- old/bubblewrap-0.12.0/ci/builddeps.sh       2026-08-26 12:08:29.000000000 
+0200
+++ new/bubblewrap-0.13.1/ci/builddeps.sh       2026-10-14 14:13:57.000000000 
+0200
@@ -66,6 +66,7 @@
         pkg-config \
         python3 \
         xsltproc \
+        python3-seccomp \
         ${NULL+}
 
     if [ -n "${opt_clang}" ]; then
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/meson.build 
new/bubblewrap-0.13.1/meson.build
--- old/bubblewrap-0.12.0/meson.build   2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/meson.build   2026-10-14 14:13:57.000000000 +0200
@@ -1,7 +1,7 @@
 project(
   'bubblewrap',
   'c',
-  version : '0.12.0',
+  version : '0.13.1',
   meson_version : '>=0.49.0',
   default_options : [
     'warning_level=2',
@@ -87,6 +87,10 @@
   endif
 endif
 
+if get_option('debug_logging')
+  cdata.set('BWRAP_DEBUG', 1)
+endif
+
 assume_kernel = get_option('assume_kernel')
 if assume_kernel != ''
   kernel_parts = assume_kernel.split('.')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/meson_options.txt 
new/bubblewrap-0.13.1/meson_options.txt
--- old/bubblewrap-0.12.0/meson_options.txt     2026-08-26 12:08:29.000000000 
+0200
+++ new/bubblewrap-0.13.1/meson_options.txt     2026-10-14 14:13:57.000000000 
+0200
@@ -32,6 +32,12 @@
   value : 'auto',
 )
 option(
+  'debug_logging',
+  type : 'boolean',
+  description : 'Provide debug messages, off-by-default',
+  value : false,
+)
+option(
   'program_prefix',
   type : 'string',
   description : 'Prepend string to bwrap executable name, for use with 
subprojects',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/safe_openat.c 
new/bubblewrap-0.13.1/safe_openat.c
--- old/bubblewrap-0.12.0/safe_openat.c 2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/safe_openat.c 2026-10-14 14:13:57.000000000 +0200
@@ -21,6 +21,7 @@
 
 #include "utils.h"
 #include <sys/syscall.h>
+#include <limits.h>
 #include <unistd.h>
 #include <errno.h>
 #include <stdint.h>
@@ -89,7 +90,7 @@
 
 #define consume_slashes(t) \
   ({                       \
-    typeof (t) _s = (t);   \
+    __typeof__ (t) _s = (t);   \
     while (*_s == '/')     \
       _s++;                \
     _s;                    \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/tests/test-helper.py 
new/bubblewrap-0.13.1/tests/test-helper.py
--- old/bubblewrap-0.12.0/tests/test-helper.py  2026-08-26 12:08:29.000000000 
+0200
+++ new/bubblewrap-0.13.1/tests/test-helper.py  2026-10-14 14:13:57.000000000 
+0200
@@ -1,5 +1,6 @@
 #!/usr/bin/env python3
 # Copyright 2024 Alexander Larsson
+# Copyright 2026 Collabora Ltd.
 # SPDX-License-Identifier: LGPL-2.1-or-later
 #
 # Test infrastructure for bwrap sandbox integration tests.
@@ -8,6 +9,7 @@
 
 import json
 import os
+import re
 import socket
 import subprocess
 import sys
@@ -205,10 +207,29 @@
             os.close(fd)
 
 
+# A sequence of one or more octal escapes such as \12\345
+_OCTAL_ESCAPES = re.compile(r'(?:\\[0-7]{1,3})+')
+
+
+def _octal_unescape_char(match):
+    """Replace _OCTAL_ESCAPES with their expansion"""
+    text = match.group(0)
+    assert text[0] == '\\'
+    sequences = text[1:].split('\\')
+    return bytes(
+        [int(seq, base=8) for seq in sequences]
+    ).decode('utf-8', errors='surrogateescape')
+
+
+def unescape_mount(escaped):
+    """Unescape a mount point as shown in /proc/self/mounts"""
+    return _OCTAL_ESCAPES.sub(_octal_unescape_char, escaped)
+
+
 def list_mounts():
     """Return list of mountpoints from /proc/self/mounts."""
     with open('/proc/self/mounts') as f:
-        return [line.split()[1] for line in f]
+        return [unescape_mount(line.split()[1]) for line in f]
 
 
 def can_run_bwrap():
@@ -225,6 +246,18 @@
         return False
 
 
+def get_assumed_kernel():
+    """Return the minimum kernel supported by BWRAP, e.g. 5.10.0"""
+    r = subprocess.run(
+        [BWRAP, '--debug-opt=print-assumed-kernel'],
+        stdin=subprocess.DEVNULL,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.DEVNULL,
+        check=True,
+    )
+    return tuple([int(n) for n in r.stdout.decode('ascii').strip().split('.')])
+
+
 class TAPResult(unittest.TestResult):
     def __init__(self):
         super().__init__()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/tests/test-run.sh 
new/bubblewrap-0.13.1/tests/test-run.sh
--- old/bubblewrap-0.12.0/tests/test-run.sh     2026-08-26 12:08:29.000000000 
+0200
+++ new/bubblewrap-0.13.1/tests/test-run.sh     2026-10-14 14:13:57.000000000 
+0200
@@ -172,6 +172,34 @@
 assert_file_has_content err.txt "^bwrap: Can't find source path.*source-enoent"
 ok "error prefixing"
 
+# Test that an empty path argument is rejected. Empty paths used to be
+# interpreted as the root directory, so for example --bind-try "" DEST
+# silently gave the sandbox access to the whole filesystem.
+for opt in --bind --bind-try --dev-bind --dev-bind-try --ro-bind 
--ro-bind-try; do
+    if $RUN "$opt" "" /mnt true 2>err.txt; then
+        assert_not_reached "$opt accepted an empty source"
+    fi
+    assert_file_has_content err.txt "^bwrap: $opt does not take an empty path 
argument"
+
+    if $RUN "$opt" / "" true 2>err.txt; then
+        assert_not_reached "$opt accepted an empty destination"
+    fi
+    assert_file_has_content err.txt "^bwrap: $opt does not take an empty path 
argument"
+done
+
+for opt in --chdir --dev --dir --mqueue --proc --remount-ro --tmpfs; do
+    if $RUN "$opt" "" true 2>err.txt; then
+        assert_not_reached "$opt accepted an empty path"
+    fi
+    assert_file_has_content err.txt "^bwrap: $opt does not take an empty path 
argument"
+done
+
+if $RUN --symlink /usr "" true 2>err.txt; then
+    assert_not_reached "--symlink accepted an empty destination"
+fi
+assert_file_has_content err.txt "^bwrap: --symlink does not take an empty path 
argument"
+ok "empty path arguments are rejected"
+
 if ! ${is_uidzero}; then
     # When invoked as non-root, check that by default we have no caps left
     for OPT in "" "--unshare-user-try --as-pid-1" "--unshare-user-try" 
"--as-pid-1"; do
@@ -292,6 +320,7 @@
     else
         ok_skip "/mnt does not exist or is a symlink"
     fi
+    rm "$tempfile"
 else
     ok_skip "mktemp not found"
     ok_skip "mktemp not found"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/tests/test-sandbox.py 
new/bubblewrap-0.13.1/tests/test-sandbox.py
--- old/bubblewrap-0.12.0/tests/test-sandbox.py 2026-08-26 12:08:29.000000000 
+0200
+++ new/bubblewrap-0.13.1/tests/test-sandbox.py 2026-10-14 14:13:57.000000000 
+0200
@@ -26,6 +26,7 @@
 
 BWRAP = _helper.BWRAP
 can_run_bwrap = _helper.can_run_bwrap
+get_assumed_kernel = _helper.get_assumed_kernel
 in_sandbox = _helper.in_sandbox
 list_mounts = _helper.list_mounts
 DataFd = _helper.DataFd
@@ -137,7 +138,15 @@
                             f'expected bwrap to fail, stderr: 
{result.stderr!r}')
 
     def assertMountFlags(self, path, expected, unexpected):
-        flags = os.statvfs(path).f_flag
+        try:
+            flags = os.statvfs(path).f_flag
+        except PermissionError:
+            if path.endswith('/doc'):
+                # https://github.com/flatpak/xdg-desktop-portal/issues/553
+                return
+            else:
+                raise
+
         for f in expected:
             self.assertTrue(flags & f, f'{path}: expected flag {f:#x} not set')
         for f in unexpected:
@@ -308,13 +317,35 @@
 
     @in_sandbox()
     def test_ro_bind_root_is_recursive(self):
+        self._test_ro_bind_root_is_recursive()
+
+    @in_sandbox('--debug-opt=force-mount-setattr-fallback')
+    def _test_ro_bind_root_is_recursive_fallback(self):
+        self._test_ro_bind_root_is_recursive()
+
+    def test_ro_bind_root_is_recursive_fallback(self):
+        if get_assumed_kernel() >= (5, 12, 0):
+            self.skipTest('mount_setattr() fallback not compiled')
+        else:
+            self._test_ro_bind_root_is_recursive_fallback()
+
+    def _test_ro_bind_root_is_recursive(self):
         """The base --ro-bind / / should apply read-only to sub-mounts."""
         skip_prefixes = ('/dev', '/proc', '/sys', '/tmp')
         for mountpoint in list_mounts():
             if any(mountpoint == p or mountpoint.startswith(p + '/')
                    for p in skip_prefixes):
                 continue
-            flags = os.statvfs(mountpoint).f_flag
+
+            try:
+                flags = os.statvfs(mountpoint).f_flag
+            except PermissionError:
+                if mountpoint.endswith('/doc'):
+                    # https://github.com/flatpak/xdg-desktop-portal/issues/553
+                    return
+                else:
+                    raise
+
             self.assertTrue(
                 flags & os.ST_RDONLY,
                 f'{mountpoint} is not read-only',
@@ -481,7 +512,7 @@
 
     def test_hostname(self):
         result = run_bwrap('--unshare-uts', '--hostname', 'testhost',
-                           'hostname')
+                           'uname', '-n')
         self.assertEqual(result.returncode, 0)
         self.assertEqual(result.stdout.strip(), b'testhost')
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/utils.c 
new/bubblewrap-0.13.1/utils.c
--- old/bubblewrap-0.12.0/utils.c       2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/utils.c       2026-10-14 14:13:57.000000000 +0200
@@ -28,6 +28,10 @@
 #include <selinux/selinux.h>
 #endif
 
+#ifndef __NR_pivot_root
+#error Linux kernel headers with __NR_pivot_root are required
+#endif
+
 #ifndef HAVE_SELINUX_2_3
 /* libselinux older than 2.3 weren't const-correct */
 #define setexeccon(x) setexeccon ((security_context_t) x)
@@ -35,6 +39,10 @@
 #define security_check_context(x) security_check_context ((security_context_t) 
x)
 #endif
 
+#ifdef BWRAP_DEBUG
+bool bwrap_is_debugging = false;
+#endif
+
 bool bwrap_level_prefix = false;
 int proc_fd = -1;
 
@@ -44,6 +52,11 @@
             va_list args,
             const char *detail)
 {
+#ifdef BWRAP_DEBUG
+  if (severity == LOG_DEBUG && !bwrap_is_debugging)
+    return;
+#endif
+
   if (bwrap_level_prefix)
     fprintf (stderr, "<%d>", severity);
 
@@ -900,12 +913,7 @@
 int
 pivot_root (const char * new_root, const char * put_old)
 {
-#ifdef __NR_pivot_root
   return syscall (__NR_pivot_root, new_root, put_old);
-#else
-  errno = ENOSYS;
-  return -1;
-#endif
 }
 
 char *
@@ -1096,3 +1104,34 @@
       src++;
     }
 }
+
+
+/* Enable mount_setattr for systems where the kernel is new enough but
+ * the glibc may lag behind, like it might happen with the Steam runtime.
+ *
+ * This could be expanded for other architectures, but these seem like
+ * the most likely to be backported to old LTS operating systems */
+#ifndef __NR_mount_setattr
+# if (defined(__x86_64__) && defined(__LP64__)) \
+     || defined(__i386__) \
+     || (defined(__aarch64__) && defined(__LP64__))
+#   define __NR_mount_setattr 442
+# endif
+#endif
+
+int
+mount_setattr_wrapper (int dirfd, const char *path, unsigned int flags,
+                       struct mount_attr *attr, size_t size)
+{
+#ifdef __NR_mount_setattr
+  return syscall (__NR_mount_setattr, dirfd, path, flags, attr, size);
+#else
+  (void) dirfd;
+  (void) path;
+  (void) flags;
+  (void) attr;
+  (void) size;
+  errno = ENOSYS;
+  return -1;
+#endif
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bubblewrap-0.12.0/utils.h 
new/bubblewrap-0.13.1/utils.h
--- old/bubblewrap-0.12.0/utils.h       2026-08-26 12:08:29.000000000 +0200
+++ new/bubblewrap-0.13.1/utils.h       2026-10-14 14:13:57.000000000 +0200
@@ -33,7 +33,8 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#if 0
+#ifdef BWRAP_DEBUG
+extern bool bwrap_is_debugging;
 #define debug(...) bwrap_log (LOG_DEBUG, __VA_ARGS__)
 #else
 #define debug(...)
@@ -158,6 +159,7 @@
 int   label_create_file (const char *file_label);
 
 extern bool opt_force_openat_fallback;
+extern bool opt_force_mount_setattr_fallback;
 
 int safe_openat (int dirfd,
                  const char *rootfs,
@@ -254,7 +256,9 @@
 static inline void
 cleanup_fdsetp (FdSet *set)
 {
-  for (size_t i = 0; i < set->len; i++)
+  size_t i;
+
+  for (i = 0; i < set->len; i++)
     if (set->fds[i] >= 0)
       close (set->fds[i]);
   free (set->fds);
@@ -284,3 +288,35 @@
                  ...);
 void strappend_escape_for_mount_options (StringBuilder *dest,
                                          const char    *src);
+
+#ifndef MOUNT_ATTR_RDONLY
+
+#include <linux/types.h>
+
+struct mount_attr
+{
+  __u64 attr_set;
+  __u64 attr_clr;
+  __u64 propagation;
+  __u64 userns_fd;
+};
+
+#define MOUNT_ATTR_RDONLY       0x00000001
+#define MOUNT_ATTR_NOSUID       0x00000002
+#define MOUNT_ATTR_NODEV        0x00000004
+#define MOUNT_ATTR_NOEXEC       0x00000008
+#define MOUNT_ATTR__ATIME       0x00000070
+#define MOUNT_ATTR_RELATIME     0x00000000
+#define MOUNT_ATTR_NOATIME      0x00000010
+#define MOUNT_ATTR_STRICTATIME  0x00000020
+#define MOUNT_ATTR_NODIRATIME   0x00000080
+#define MOUNT_ATTR_IDMAP        0x00100000
+#define MOUNT_ATTR_NOSYMFOLLOW  0x00200000
+#endif
+
+#ifndef AT_RECURSIVE
+#define AT_RECURSIVE  0x8000
+#endif
+
+int mount_setattr_wrapper (int dirfd, const char *path, unsigned int flags,
+                           struct mount_attr *attr, size_t size);

Reply via email to