Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Date: Tue, 6 Feb 2024 18:01:42 +0100
From: Solar Designer <solar@...nwall.com>
To: oss-security@...ts.openwall.com
Subject: CVE-2024-1048: grub2-set-bootflag may be abused to fill up /boot, bypass RLIMIT_NPROC

Hi,

Summary:

This message is about issues in grub-set-bootflag.c commonly installed
as grub2-set-bootflag, which is Red Hat's addition (not part of upstream
GRUB project) used at least in Fedora and RHEL and its downstreams.  It
is a SUID root program.  I think its latest development source code is
currently located in this branch:

https://github.com/rhboot/grub2/tree/fedora-40

On non-OSTree distros, this program's purpose appears to be purely
cosmetic - hide the boot menu if the system had already successfully
booted up with its current kernel and a user had successfully logged in.

Impact of the issues I identified (through my work at CIQ on Rocky
Linux) is rather limited - denial of service and resource limit bypass.

I pre-notified Red Hat grub2 package maintainers about upcoming issues
in this program in late December, and reported them in detail via Red
Hat Bugzilla on January 3:

https://bugzilla.redhat.com/show_bug.cgi?id=2256678

(This is currently a private "bug", hopefully it will be opened soon.)

I also reported this to linux-distros on January 24, and today February 6
is the coordinated public disclosure.

Attached are my currently proposed patches (two revisions, see below),
tested by me on Rocky Linux 9.3, and (for the later revision) also by
people at Red Hat.

Red Hat assigned this issue CVE-2024-1048 and rated it as CVSSv3.1 Base
Score 3.3 and Moderate severity, which I agree with:

CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L - 3.3

Technically, the RLIMIT_NPROC bypass could mean S:C A:H, resulting in a
score of 6.5, however in practice for this to matter the resource limits
would need to be set up, which by default and on most systems they are
not anyway.  That is, by default almost the same kind and extent of DoS
is possible by a simple "fork bomb" from the user's account, so there's
no additional vulnerability.

I'd like to thank Red Hat, and especially Marta Lewandowska for her help
in coordinating this disclosure and testing the patches.

Overall, I think that at least on Enterprise Linux distros unprivileged
setting of boot flags should be disabled by default.  It is of
questionable value and isn't worth the risk.  That said, I understand
that for now it may be easier for distros to patch than to re-think it.

Detail:

In 2019, Tavis Ormandy reported that the original implementation of
grub2-set-bootflag could be abused to truncate the grubenv file.  This
is CVE-2019-14865 and was fixed back then:

https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2019-14865
https://access.redhat.com/errata/RHSA-2020:0335

Taking a fresh look at grub2-set-bootflag, I saw some other ways in
which users could still abuse this little program:

1. After CVE-2019-14865 fix, grub2-set-bootflag no longer rewrites the
grubenv file in-place, but writes into a temporary file and renames it
over the original, checking for error returns from each call first.
This prevents the original file truncation vulnerability, but it can
leave the temporary file around if the program is killed before it can
rename or remove the file.  There are still many ways to get the program
killed, such as through RLIMIT_FSIZE triggering SIGXFSZ (tested,
reliable) or by careful timing (tricky) of signals sent by process group
leader, pty, pre-scheduled timers, SIGXCPU (probably not an exhaustive
list).  Invoking the program multiple times fills up /boot (or if /boot
is not separate, then it can fill up the root filesystem).  Since the
files are tiny, the filesystem is likely to run out of free inodes
before it'd run out of blocks, but the effect is similar - can't create
new files after this point (but still can add data to existing files,
such as logs).

2. After CVE-2019-14865 fix, grub2-set-bootflag naively tries to protect
itself from signals by becoming full root.  (This does protect it from
signals sent by the user directly to the PID, but e.g. "kill -9 -1" by
the user still works.)  A side effect of such "protection" is that it's
possible to invoke more concurrent instances of grub2-set-bootflag than
the user's RLIMIT_NPROC would normally permit (as specified e.g. in
/etc/security/limits.conf, or say in Apache httpd's RLimitNPROC if
grub2-set-bootflag would be abused by a website script), thereby
exhausting system resources (e.g., bypassing RAM usage limit if
RLIMIT_AS was also set).

3. umask is inherited.  Again, due to how the CVE-2019-14865 fix creates
a new file, and due to how mkstemp() works, this affects grubenv's new
file permissions.  Luckily, mkstemp() forces them to be no more relaxed
than 0600, but the user ends up being able to set them e.g. to 0.
Luckily, at least in my testing GRUB still works fine even when the file
has such (lack of) permissions.

The attached -1 patch deals with my example abuses above as follows:

1. RLIMIT_FSIZE is pre-checked, so this specific way to get the process
killed should no longer work.  However, this isn't a complete fix
because there are other ways to get the process killed after it has
created the temporary file.

The patch also fixes bug 1975892 ("RFE: grub2-set-bootflag should not
write the grubenv when the flag being written is already set") and
similar for "menu_show_once", which further reduces the abuse potential.

2. RLIMIT_NPROC bypass should be avoided by not becoming full root (aka
dropping the partial "kill protection").

3. A safe umask is set.

The -1 patch is a partial fix (temporary files can still accumulate, but
this is harder to trigger).  It should be safe to use.

The attached -7 patch additionally switches to usage of per-user fixed
temporary filenames along with a weird locking mechanism, which is
explained in source code comments.  This is a more complete fix
(temporary files can't accumulate).  Unfortunately, it introduces new
risks (by working on a temporary file shared between the user's
invocations), which are _hopefully_ avoided by the patch's elaborate
logic.  I actually got it wrong at first, which suggests that this logic
is hard to reason about, and more errors or omissions are possible.  It
also relies on the kernel's primitives' exact semantics to a greater
extent (nothing out of the ordinary, though).

Both patches also fix potential 1- or 2-byte over-read of env[] if its
content is malformed - this was not a security issue since the grubenv
file is trusted input, and the fix is just for robustness.

Also attached is a program I wrote and used to test the unusual approach
to locking implemented in the -7 patch here.

Remaining issues that I think cannot reasonably be fixed without a
redesign (e.g., having per-flag files with nothing else in them) and
without introducing new issues:

A. A user can still revert a concurrent user's attempt of setting the
other flag - or of making other changes to grubenv by means other than
this program.

B. One leftover temporary file per user is still possible.

Needs comments by people more familiar with GRUB and its configurations
in use:

C. One hopefully non-issue (but I am not sure): can "menu_show_once"
possibly make the system stuck at next boot?  Apparently, not with
defaults, but maybe along with other GRUB settings in place?  If so, it
could be unsafe to expose setting this flag to users.  A misfeature?

Security hardening not yet implemented (would require changes or at
least decisions outside of this program's code):

D. If this program's functionality is really desirable anywhere at all,
perhaps its availability should vary by distro - e.g., have it on (some
builds of) Fedora, but not on Enterprise Linux distros - and then don't
make this program SUID root where that is not needed.

E. The program could refuse to work (exit early) if invoked by an
unexpected system pseudo-user.  Apparently, it's expected to be invoked
by all normal users, but we can nevertheless disallow uid < 1000, so the
program couldn't be abused by a compromised system pseudo-user account
in a multi-vulnerability multi-step attack.

F. grubenv could be made a symlink into a subdirectory writable by a
group, then SGID to that group could be used, mostly to reduce impact of
some other (yet unidentified) vulnerabilities/attacks on the program.

Regarding remaining issue/idea D above, even RHEL installs
/usr/lib/systemd/user/grub-boot-success.service, which then fails to run
upon user login when the program is not user-accessible.  The impact
from this failure, however, appears to be very limited - just some noise
in the logs.  The -7 patch includes a piece to reduce such noise if the
program is installed e.g. mode 755.

Overall, my understanding is that the program (and other related parts
using the boot success flag) is most useful on systems with OSTree,
which means some builds of Fedora, right?  Per Wikipedia it's "Fedora's
atomic spins (Silverblue, Kinoite, and Sericea)".
https://en.wikipedia.org/wiki/OSTree

Should we get rid of it on other distros?  Or on the contrary, should we
make real, non-cosmetic use of the boot flag?  If not setting the flag
would trigger automatic fallback to the previous kernel, that could be a
valuable enough feature to justify some risks, but on the other hand
such fallback would also be unexpected by many and it'd be a security
concern on its own.  A server could successfully boot into the new
kernel and be in use without any Unix user logins to it occurring until
next reboot.  It shouldn't then revert to the old kernel just because no
one had logged in.  So the feature would need to be opt-in by the
sysadmin or/and the criteria for fallback would need to be different.

Alexander

View attachment "grub-set-bootflag-rocky-1.patch" of type "text/plain" (2112 bytes)

View attachment "grub-set-bootflag-rocky-7.patch" of type "text/plain" (6387 bytes)

View attachment "locktest.c" of type "text/x-c" (2348 bytes)

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.