mirror of
https://github.com/openai/codex.git
synced 2026-05-25 05:24:37 +00:00
vendor: update bubblewrap to 0.11.2 (#21389)
## Why `codex-rs/vendor/bubblewrap` had fallen behind upstream, and upstream `v0.11.2` is the current Bubblewrap release. The release is a security update for `CVE-2026-41163`, affecting setuid Bubblewrap builds, and deprecates setuid support in favor of the default non-setuid build mode. ## What changed - Refreshed the vendored Bubblewrap sources under `codex-rs/vendor/bubblewrap` to upstream `v0.11.2`. - Brought in the upstream `-Dsupport_setuid` build option, which defaults setuid support off. - Updated vendored release notes and documentation files included with Bubblewrap. ## Verification Not run locally; this PR only refreshes the vendored upstream Bubblewrap source snapshot. Upstream release: https://github.com/containers/bubblewrap/releases/tag/v0.11.2
This commit is contained in:
47
codex-rs/vendor/bubblewrap/NEWS.md
vendored
47
codex-rs/vendor/bubblewrap/NEWS.md
vendored
@@ -1,3 +1,50 @@
|
||||
bubblewrap 0.11.2
|
||||
=================
|
||||
|
||||
Released: 2026-04-23
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* In setuid mode, don't run the low-privileged parts parts of the setup
|
||||
as dumpable, as that allows it to be ptraced which can lead to problems.
|
||||
This is CVE-2026-41163, and was reported by François Diakhate.
|
||||
|
||||
Enhancements:
|
||||
|
||||
* New build option `-Dsupport_setuid`, which if set to false (which
|
||||
is the default) disables the support for setuid. Binaries built
|
||||
with this will refuse to run if made setuid. We recommend building
|
||||
normal bubblewrap binaries like this, which allows you to safely
|
||||
ignore any security issues that only affect setuid mode.
|
||||
|
||||
bubblewrap 0.11.1
|
||||
=================
|
||||
|
||||
Released: 2026-03-21
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* Reset disposition of `SIGCHLD`, restoring normal subprocess management
|
||||
if bwrap was run from a process that was ignoring that signal,
|
||||
such as Erlang or volumeicon (#705, Joel Pelaez Jorge)
|
||||
|
||||
* Don't ignore `--userns 0`, `--userns2 0` or `--pidns 0` if used
|
||||
(#731, Daniel Cazares).
|
||||
Note that using a fd number ≥ 3 for these purposes is still
|
||||
preferred, to avoid confusion with the stdin, stdout, stderr
|
||||
that will be inherited by the command inside the container.
|
||||
|
||||
* Fix grammar in an error message (#694, J. Neuschäfer)
|
||||
|
||||
* Fix a broken link in the documentation (#729, Aaron Brooks)
|
||||
|
||||
Internal changes:
|
||||
|
||||
* Enable user namespaces in Github Actions configuration, fixing a CI
|
||||
regression with newer Ubuntu (#728, Joel Pelaez Jorge)
|
||||
|
||||
* Clarify comments (#737, Simon McVittie)
|
||||
|
||||
bubblewrap 0.11.0
|
||||
=================
|
||||
|
||||
|
||||
31
codex-rs/vendor/bubblewrap/README.md
vendored
31
codex-rs/vendor/bubblewrap/README.md
vendored
@@ -12,23 +12,24 @@ on the host.
|
||||
User namespaces
|
||||
---------------
|
||||
|
||||
There is an effort in the Linux kernel called
|
||||
There is an feature in the Linux kernel called
|
||||
[user namespaces](https://www.google.com/search?q=user+namespaces+site%3Ahttps%3A%2F%2Flwn.net)
|
||||
which attempts to allow unprivileged users to use container features.
|
||||
While significant progress has been made, there are
|
||||
[still concerns](https://lwn.net/Articles/673597/) about it, and
|
||||
it is not available to unprivileged users in several production distributions
|
||||
such as CentOS/Red Hat Enterprise Linux 7, Debian Jessie, etc.
|
||||
which allows unprivileged users to use container features. Bubblewrap uses these to
|
||||
build the sandbox, allowing any user to use the tool.
|
||||
|
||||
See for example
|
||||
[CVE-2016-3135](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3135)
|
||||
which is a local root vulnerability introduced by userns.
|
||||
[This March 2016 post](https://lkml.org/lkml/2016/3/9/555) has some
|
||||
more discussion.
|
||||
Historically, not all Linux distributions supported (at least by
|
||||
default) unprivileged user namespaces, so bubblewrap supports a second
|
||||
mode of operation when the binary is setuid root. In that setup
|
||||
bubblewrap could be viewed as setuid implementation of a *subset* of
|
||||
user namespaces. However, not all features of bubblewrap work in
|
||||
this mode.
|
||||
|
||||
Bubblewrap could be viewed as setuid implementation of a *subset* of
|
||||
user namespaces. Emphasis on subset - specifically relevant to the
|
||||
above CVE, bubblewrap does not allow control over iptables.
|
||||
However, setuid mode is deprecated, as most recent Linux distributions
|
||||
support unprivileged user namespaces, and setuid binaries carry
|
||||
significant risks. By default, bubblewrap binaries refuse to work if
|
||||
setuid, and you must build explicitly with ` -Dsupport_setuid=true` to
|
||||
enable it to work. Later versions of bubblewrap aims to completely
|
||||
remove this support.
|
||||
|
||||
The original bubblewrap code existed before user namespaces - it inherits code from
|
||||
[xdg-app helper](https://cgit.freedesktop.org/xdg-app/xdg-app/tree/common/xdg-app-helper.c?id=4c3bf179e2e4a2a298cd1db1d045adaf3f564532)
|
||||
@@ -151,7 +152,7 @@ sandbox. You can also change what the value of uid/gid should be in the sandbox.
|
||||
IPC namespaces ([CLONE_NEWIPC](https://linux.die.net/man/2/clone)): The sandbox will get its own copy of all the
|
||||
different forms of IPCs, like SysV shared memory and semaphores.
|
||||
|
||||
PID namespaces ([CLONE_NEWPID](https://linux.die.net/man/2/clone)): The sandbox will not see any processes outside the sandbox. Additionally, bubblewrap will run a trivial pid1 inside your container to handle the requirements of reaping children in the sandbox. This avoids what is known now as the [Docker pid 1 problem](https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/).
|
||||
PID namespaces ([CLONE_NEWPID](https://linux.die.net/man/2/clone)): The sandbox will not see any processes outside the sandbox. Additionally, bubblewrap will run a trivial pid1 inside your container to handle the requirements of reaping children in the sandbox. This avoids what is known now as the [Docker pid 1 problem](https://blog.phusion.nl/docker-and-the-pid-1-zombie-reaping-problem/).
|
||||
|
||||
|
||||
Network namespaces ([CLONE_NEWNET](https://linux.die.net/man/2/clone)): The sandbox will not see the network. Instead it will have its own network namespace with only a loopback device.
|
||||
|
||||
7
codex-rs/vendor/bubblewrap/SECURITY.md
vendored
7
codex-rs/vendor/bubblewrap/SECURITY.md
vendored
@@ -15,6 +15,13 @@ between the user and the OS, because anything bubblewrap could do, a
|
||||
malicious user could equally well do by writing their own tool equivalent
|
||||
to bubblewrap.
|
||||
|
||||
Since 0.11.2, unless compiled with the `-Dsupport_setuid=true` option,
|
||||
setuid root support is disabled. In this mode bubblewrap will refuse
|
||||
to operate if the binary has been made setuid. For binaries built like
|
||||
this it is safe to ignore any bubblewrap CVEs that are described as
|
||||
affecting setuid mode only. This is the recommended way to package
|
||||
bubblewrap.
|
||||
|
||||
### Sandbox security
|
||||
|
||||
bubblewrap is a toolkit for constructing sandbox environments.
|
||||
|
||||
50
codex-rs/vendor/bubblewrap/bubblewrap.c
vendored
50
codex-rs/vendor/bubblewrap/bubblewrap.c
vendored
@@ -55,7 +55,11 @@ static uid_t real_uid;
|
||||
static gid_t real_gid;
|
||||
static uid_t overflow_uid;
|
||||
static gid_t overflow_gid;
|
||||
#ifdef ENABLE_SUPPORT_SETUID
|
||||
static bool is_privileged; /* See acquire_privs() */
|
||||
#else
|
||||
#define is_privileged 0
|
||||
#endif
|
||||
static const char *argv0;
|
||||
static const char *host_tty_dev;
|
||||
static int proc_fd = -1;
|
||||
@@ -840,13 +844,16 @@ set_ambient_capabilities (void)
|
||||
static void
|
||||
acquire_privs (void)
|
||||
{
|
||||
uid_t euid, new_fsuid;
|
||||
uid_t euid;
|
||||
|
||||
euid = geteuid ();
|
||||
|
||||
/* Are we setuid ? */
|
||||
if (real_uid != euid)
|
||||
{
|
||||
#ifdef ENABLE_SUPPORT_SETUID
|
||||
uid_t new_fsuid;
|
||||
|
||||
if (euid != 0)
|
||||
die ("Unexpected setuid user %d, should be 0", euid);
|
||||
|
||||
@@ -868,13 +875,16 @@ acquire_privs (void)
|
||||
/* setfsuid can't properly report errors, check that it worked (as per manpage) */
|
||||
new_fsuid = setfsuid (-1);
|
||||
if (new_fsuid != real_uid)
|
||||
die ("Unable to set fsuid (was %d)", (int)new_fsuid);
|
||||
die_with_error ("Unable to set fsuid (was %d)", (int)new_fsuid);
|
||||
|
||||
/* We never need capabilities after execve(), so lets drop everything from the bounding set */
|
||||
drop_cap_bounding_set (true);
|
||||
|
||||
/* Keep only the required capabilities for setup */
|
||||
set_required_caps ();
|
||||
#else
|
||||
die ("setuid use of bubblewrap is not supported in this build");
|
||||
#endif
|
||||
}
|
||||
else if (real_uid != 0 && has_caps ())
|
||||
{
|
||||
@@ -937,7 +947,8 @@ switch_to_user_with_privs (void)
|
||||
/* Call setuid() and use capset() to adjust capabilities */
|
||||
static void
|
||||
drop_privs (bool keep_requested_caps,
|
||||
bool already_changed_uid)
|
||||
bool already_changed_uid,
|
||||
bool set_dumpable)
|
||||
{
|
||||
assert (!keep_requested_caps || !is_privileged);
|
||||
/* Drop root uid */
|
||||
@@ -947,9 +958,12 @@ drop_privs (bool keep_requested_caps,
|
||||
|
||||
drop_all_caps (keep_requested_caps);
|
||||
|
||||
/* We don't have any privs now, so mark us dumpable which makes /proc/self be owned by the user instead of root */
|
||||
if (prctl (PR_SET_DUMPABLE, 1, 0, 0, 0) != 0)
|
||||
die_with_error ("can't set dumpable");
|
||||
if (set_dumpable)
|
||||
{
|
||||
/* We don't have any privs now, so mark us dumpable which makes /proc/self be owned by the user instead of root */
|
||||
if (prctl (PR_SET_DUMPABLE, 1, 0, 0, 0) != 0)
|
||||
die_with_error ("can't set dumpable");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1154,7 +1168,9 @@ privileged_op (int privileged_op_socket,
|
||||
break;
|
||||
|
||||
case PRIV_SEP_OP_OVERLAY_MOUNT:
|
||||
if (mount ("overlay", arg2, "overlay", MS_MGC_VAL, arg1) != 0)
|
||||
if (is_privileged)
|
||||
die ("Overlay mounts are not supported in setuid mode");
|
||||
if (mount ("overlay", arg2, "overlay", MS_MGC_VAL | MS_NOSUID | MS_NODEV, arg1) != 0)
|
||||
{
|
||||
/* The standard message for ELOOP, "Too many levels of symbolic
|
||||
* links", is not helpful here. */
|
||||
@@ -1172,6 +1188,8 @@ privileged_op (int privileged_op_socket,
|
||||
something manages to send hacked priv-sep operation requests. */
|
||||
if (!opt_unshare_uts)
|
||||
die ("Refusing to set hostname in original namespace");
|
||||
if (arg1 == NULL)
|
||||
die ("Hostname argument is NULL");
|
||||
if (sethostname (arg1, strlen(arg1)) != 0)
|
||||
die_with_error ("Can't set hostname to %s", arg1);
|
||||
break;
|
||||
@@ -3112,7 +3130,7 @@ main (int argc,
|
||||
}
|
||||
|
||||
/* Switch to the custom user ns before the clone, gets us privs in that ns (assuming its a child of the current and thus allowed) */
|
||||
if (opt_userns_fd > 0 && setns (opt_userns_fd, CLONE_NEWUSER) != 0)
|
||||
if (opt_userns_fd != -1 && setns (opt_userns_fd, CLONE_NEWUSER) != 0)
|
||||
{
|
||||
if (errno == EINVAL)
|
||||
die ("Joining the specified user namespace failed, it might not be a descendant of the current user namespace.");
|
||||
@@ -3178,11 +3196,11 @@ main (int argc,
|
||||
|
||||
/* Initial launched process, wait for pid 1 or exec:ed command to exit */
|
||||
|
||||
if (opt_userns2_fd > 0 && setns (opt_userns2_fd, CLONE_NEWUSER) != 0)
|
||||
if (opt_userns2_fd != -1 && setns (opt_userns2_fd, CLONE_NEWUSER) != 0)
|
||||
die_with_error ("Setting userns2 failed");
|
||||
|
||||
/* We don't need any privileges in the launcher, drop them immediately. */
|
||||
drop_privs (false, false);
|
||||
drop_privs (false, false, true);
|
||||
|
||||
/* Optionally bind our lifecycle to that of the parent */
|
||||
handle_die_with_parent ();
|
||||
@@ -3219,7 +3237,7 @@ main (int argc,
|
||||
return monitor_child (event_fd, pid, setup_finished_pipe[0]);
|
||||
}
|
||||
|
||||
if (opt_pidns_fd > 0)
|
||||
if (opt_pidns_fd != -1)
|
||||
{
|
||||
if (setns (opt_pidns_fd, CLONE_NEWPID) != 0)
|
||||
die_with_error ("Setting pidns failed");
|
||||
@@ -3369,8 +3387,10 @@ main (int argc,
|
||||
|
||||
if (child == 0)
|
||||
{
|
||||
/* Unprivileged setup process */
|
||||
drop_privs (false, true);
|
||||
/* Unprivileged setup process.
|
||||
* Note: Don't set dumpable, because we can still perform privileged
|
||||
* operations via privileged_op(). */
|
||||
drop_privs (false, true, false);
|
||||
close (privsep_sockets[0]);
|
||||
setup_newroot (opt_unshare_pid, privsep_sockets[1]);
|
||||
exit (0);
|
||||
@@ -3446,7 +3466,7 @@ main (int argc,
|
||||
die_with_error ("chdir /");
|
||||
}
|
||||
|
||||
if (opt_userns2_fd > 0 && setns (opt_userns2_fd, CLONE_NEWUSER) != 0)
|
||||
if (opt_userns2_fd != -1 && setns (opt_userns2_fd, CLONE_NEWUSER) != 0)
|
||||
die_with_error ("Setting userns2 failed");
|
||||
|
||||
if (opt_unshare_user && opt_userns_block_fd == -1 &&
|
||||
@@ -3499,7 +3519,7 @@ main (int argc,
|
||||
}
|
||||
|
||||
/* All privileged ops are done now, so drop caps we don't need */
|
||||
drop_privs (!is_privileged, true);
|
||||
drop_privs (!is_privileged, true, true);
|
||||
|
||||
if (opt_block_fd != -1)
|
||||
{
|
||||
|
||||
7
codex-rs/vendor/bubblewrap/meson.build
vendored
7
codex-rs/vendor/bubblewrap/meson.build
vendored
@@ -1,7 +1,7 @@
|
||||
project(
|
||||
'bubblewrap',
|
||||
'c',
|
||||
version : '0.11.0',
|
||||
version : '0.11.2',
|
||||
meson_version : '>=0.49.0',
|
||||
default_options : [
|
||||
'warning_level=2',
|
||||
@@ -91,6 +91,11 @@ if get_option('require_userns')
|
||||
cdata.set('ENABLE_REQUIRE_USERNS', 1)
|
||||
endif
|
||||
|
||||
if get_option('support_setuid')
|
||||
cdata.set('ENABLE_SUPPORT_SETUID', 1)
|
||||
warning('running bubblewrap setuid is deprecated and risky. Most recent operating systems support unprivileged user namespaces and we recommend using that. Support for this will be removed in the next version.')
|
||||
endif
|
||||
|
||||
configure_file(
|
||||
output : 'config.h',
|
||||
configuration : cdata,
|
||||
|
||||
6
codex-rs/vendor/bubblewrap/meson_options.txt
vendored
6
codex-rs/vendor/bubblewrap/meson_options.txt
vendored
@@ -41,6 +41,12 @@ option(
|
||||
type : 'string',
|
||||
description : 'Path to Python 3, or empty to use python3',
|
||||
)
|
||||
option(
|
||||
'support_setuid',
|
||||
type : 'boolean',
|
||||
description : 'Support setuid mode (deprecated)',
|
||||
value : false,
|
||||
)
|
||||
option(
|
||||
'require_userns',
|
||||
type : 'boolean',
|
||||
|
||||
4
codex-rs/vendor/bubblewrap/network.c
vendored
4
codex-rs/vendor/bubblewrap/network.c
vendored
@@ -50,7 +50,7 @@ static int
|
||||
rtnl_send_request (int rtnl_fd,
|
||||
struct nlmsghdr *header)
|
||||
{
|
||||
struct sockaddr_nl dst_addr = { .nl_family = AF_NETLINK, .nl_pid = 0, .nl_groups = 0 };
|
||||
struct sockaddr_nl dst_addr = { AF_NETLINK, 0 };
|
||||
ssize_t sent;
|
||||
|
||||
sent = TEMP_FAILURE_RETRY (sendto (rtnl_fd, (void *) header, header->nlmsg_len, 0,
|
||||
@@ -139,7 +139,7 @@ loopback_setup (void)
|
||||
int r, if_loopback;
|
||||
cleanup_fd int rtnl_fd = -1;
|
||||
char buffer[1024];
|
||||
struct sockaddr_nl src_addr = { .nl_family = AF_NETLINK, .nl_pid = 0, .nl_groups = 0 };
|
||||
struct sockaddr_nl src_addr = { AF_NETLINK, 0 };
|
||||
struct nlmsghdr *header;
|
||||
struct ifaddrmsg *addmsg;
|
||||
struct ifinfomsg *infomsg;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
bubblewrap release checklist
|
||||
============================
|
||||
|
||||
* Collect release notes in `NEWS`
|
||||
* Update version number in `meson.build` and release date in `NEWS`
|
||||
* Collect release notes in `NEWS.md`
|
||||
* Update version number in `meson.build` and release date in `NEWS.md`
|
||||
* Commit the changes
|
||||
* `meson dist -C ${builddir}`
|
||||
* Do any final smoke-testing, e.g. update a package, install and test it
|
||||
* `git evtag sign v$VERSION`
|
||||
* Include the release notes from `NEWS` in the tag message
|
||||
* Include the release notes from `NEWS.md` in the tag message
|
||||
* `git push --atomic origin main v$VERSION`
|
||||
* https://github.com/containers/bubblewrap/releases/new
|
||||
* Fill in the new version's tag in the "Tag version" box
|
||||
|
||||
13
codex-rs/vendor/bubblewrap/utils.c
vendored
13
codex-rs/vendor/bubblewrap/utils.c
vendored
@@ -510,14 +510,18 @@ ensure_file (const char *path,
|
||||
the create file will fail in the read-only
|
||||
case with EROFS instead of EEXIST.
|
||||
|
||||
We're trying to set up a mount point for a non-directory, so any
|
||||
non-directory, non-symlink is acceptable - it doesn't necessarily
|
||||
have to be a regular file. */
|
||||
We're trying to set up a mount point for a non-directory, for which
|
||||
the kernel will accept any non-directory. If it's a symlink, follow
|
||||
it and look at the target: again, any non-directory is good enough.
|
||||
We'll only get S_ISLNK if the path is a dangling symlink (target
|
||||
doesn't exist). */
|
||||
if (stat (path, &buf) == 0 &&
|
||||
!S_ISDIR (buf.st_mode) &&
|
||||
!S_ISLNK (buf.st_mode))
|
||||
return 0;
|
||||
|
||||
/* If the file didn't exist, create it. If it was a dangling symlink
|
||||
* (S_ISLNK above) then this will create the target of the symlink. */
|
||||
if (create_file (path, mode, NULL) != 0 && errno != EEXIST)
|
||||
return -1;
|
||||
|
||||
@@ -681,7 +685,8 @@ ensure_dir (const char *path,
|
||||
/* We check this ahead of time, otherwise
|
||||
the mkdir call can fail in the read-only
|
||||
case with EROFS instead of EEXIST on some
|
||||
filesystems (such as NFS) */
|
||||
filesystems (such as NFS).
|
||||
We follow symlinks: it's OK if path is a symlink to a directory. */
|
||||
if (stat (path, &buf) == 0)
|
||||
{
|
||||
if (!S_ISDIR (buf.st_mode))
|
||||
|
||||
Reference in New Issue
Block a user