Skip to content

Commit ad83595

Browse files
below: add information about CVE-2025-27591
1 parent 8124c2e commit ad83595

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed

crates/below/RUSTSEC-0000-0000.md

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
```toml
2+
[advisory]
3+
id = "RUSTSEC-0000-0000"
4+
package = "below"
5+
date = "2025-03-12"
6+
url = "https://www.openwall.com/lists/oss-security/2025/03/12/1"
7+
# Valid categories: "code-execution", "crypto-failure", "denial-of-service", "file-disclosure"
8+
# "format-injection", "memory-corruption", "memory-exposure", "privilege-escalation"
9+
categories = ["privilege-escalation"]
10+
aliases = ["CVE-2025-27591"]
11+
cvss = "CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
12+
13+
[versions]
14+
patched = [">= 0.9.0"]
15+
```
16+
17+
# World Writable Directory in /var/log/below Allows Local Privilege Escalation
18+
19+
Below [2] is a tool for recording and displaying system data like
20+
hardware utilization and cgroup information on Linux. In January 2025,
21+
Below was packaged and submitted to openSUSE Tumbleweed. Below runs as a
22+
systemd service with `root` privileges. The SUSE security team monitors
23+
additions and changes to systemd service unit files in openSUSE
24+
Tumbleweed, and through this we noticed problematic log directory
25+
permissions applied in Below's code.
26+
27+
The version we reviewed in this context was v0.8.1 [3] and this report
28+
is based on that version.
29+
30+
Upstream released a bugfix in version v0.9.0 [4] and a security advisory
31+
[5] on GitHub.
32+
33+
## 2) Symlink Attack in `/var/log/below/error_root.log`
34+
35+
Below's systemd service runs with full `root` privileges. It attempts to
36+
create a world-writable directory in `/var/log/below`. Even if the
37+
directory already exists, the Rust code ensures [6] that it receives
38+
mode 0777 permissions:
39+
40+
```
41+
if perm.mode() & 0o777 != 0o777 {
42+
perm.set_mode(0o777);
43+
match dir.set_permissions(perm) {
44+
Ok(()) => {}
45+
Err(e) => {
46+
bail!(
47+
"Failed to set permissions on {}: {}",
48+
path.to_string_lossy(),
49+
e
50+
);
51+
}
52+
}
53+
}
54+
```
55+
56+
This logic leads to different outcomes depending on the packaging on Linux
57+
distributions:
58+
59+
- in openSUSE Tumbleweed the directory was packaged with 01755
60+
permissions (below.spec [7] line 73), thus causing the
61+
`set_permissions()` call to run, resulting in a directory with mode
62+
0777 during runtime.
63+
- in Gentoo Linux the directory is created with mode 01755 resulting in
64+
the same outcome as on openSUSE Tumbleweed (below.ebuild [8]). Where
65+
the 01755 mode is exactly coming from is not fully clear, maybe the
66+
`cargo` build process assigns these permissions during installation.
67+
- in Fedora Linux the directory is packaged with 01777 permissions, thus
68+
the `set_permissions()` code will not run, because the `if` condition
69+
masks out the sticky bit. The directory stays at mode 01777
70+
(rust-below.spec [9]).
71+
- the Arch Linux AUR package [10] (maybe wrongly) does not pre-create
72+
the log directory. Thus the `set_permissions()` code will run and
73+
create the directory with mode 0777.
74+
75+
Below creates a log file in `/var/log/below/error_root.log` and assigns
76+
mode 0666 to it. This (somewhat confusingly) happens via a `log_dir`
77+
variable [11], which has been changed to point to the `error_root.log`
78+
file. The 0666 permission assignment to the logfile happens in
79+
`logging::setup()` [12], also accompanied by a somewhat strange comment
80+
in the code.
81+
82+
A local unprivileged attacker can stage a symlink attack in this
83+
location and cause an arbitrary file in the system to obtain 0666
84+
permissions, likely leading to a full local root exploit, if done right,
85+
e.g. by pointing the symlink to `/etc/shadow`. Even if the file already
86+
exists it can be removed and replaced by a symlink, because of the
87+
world-writable directory permissions. The attack is thus not limited to
88+
scenarios in which the file has not yet been created by Below.
89+
90+
We believe the actual intention of this code might have been to assign
91+
mode 01777 (i.e. carrying a sticky bit). The sticky bit is neither
92+
contained in the `if` condition nor in the `set_permissions()` call,
93+
though. With the sticky bit set the Linux kernel's `protected_symlinks`
94+
logic, which is enabled on most Linux distributions, would protect from
95+
symlink attacks.
96+
97+
## 3) Further Issues
98+
99+
Even on Fedora Linux, where `/var/log/below` has "safe" 01777
100+
permissions, there is a time window during which problems can arise. As
101+
long as `below.service` has not been started, another local user can
102+
pre-create `/var/log/below/error_root.log` and e.g. place a FIFO special
103+
file there. This will pose a local DoS against the below service, since
104+
it will fail to open the path and thus fail to start.
105+
106+
If `/var/log/below` were to be deleted for any reason, then Below would
107+
still recreate it using the bad 0777 mode permissions, which can also
108+
happen on distributions that initially package `/var/log/below` using
109+
permissions that do not trigger the `set_permissions()` call in Below's
110+
code.
111+
112+
Below applies many world-writable and world-readable permissions under
113+
`/var/log/below`. This seems a strange choice. For some reason the
114+
internal state data of Below is also stored within the log directory in
115+
`/var/log/below/store`. The data is fully world-readable, which could
116+
result in information leaks, if Below stores system information there
117+
that would not otherwise be accessible to unprivileged local users. We
118+
did not check if this applies, though. By pre-creating this directory
119+
before `below.service` runs for the first time, an unprivileged user can
120+
control all of its contents, possibly violating the integrity of Below
121+
in various ways.
122+
123+
The world-writable logfile `error_root.log` makes no sense to us as
124+
well. Why should arbitrary users in the system be able to modify the log
125+
data of Below? This allows log spoofing by local users. Even making the
126+
logfile world-readable is considered bad style by some people these
127+
days. Why `/var/log/below` should be world-writable in the first place
128+
is also unclear to us. Ideally only `root` or a dedicated `below`
129+
service user should be allowed to write there.
130+
131+
## 4) Bugfix
132+
133+
Upstream published a bugfix in commit 10e73a21d67 [13] which is part of
134+
Below v0.9.0 [4]. The commit basically removes all problematic
135+
permission assignments from the code, stating that these directories are
136+
better setup by systemd. This seems to refer to an added systemd
137+
directive `LogsDirectory=below` in the `below.service` file.
138+
139+
With this change no world-writable directories or files should turn up
140+
in `/var/log/below` anymore, and the most severe issues from this report
141+
are addressed. The possible matter of world-readable log and store files
142+
remains, though.
143+
144+
We did not get any details from upstream about the design decisions in
145+
Below that led to this issue or about any further changes that upstream
146+
intends to perform to improve security in this area.
147+
148+
## 5) CVE Assignment
149+
150+
Upstream assigned CVE-2025-27591 for this issue.
151+
152+
## 6) Hardening Suggestions
153+
154+
It could be considered to apply hardening directives in Below's systemd
155+
service unit that prevent some attack types. Most prominently,
156+
restricting write access for the daemon to a range of well known
157+
locations comes to mind.
158+
159+
## 7) Timeline
160+
161+
2025-01-20: We noticed the issue and started tracking it privately in bsc#1236109 [14].
162+
2025-01-20: We shared the information with Meta via its security bug report system [15], offering coordinated disclosure.
163+
2025-01-21: We received an initial automated reply from Meta.
164+
2025-02-21: We received an update that the report would be forwarded to the appropriate engineering team.
165+
2025-02-26: We were awarded a bug bounty for the report but did not receive any details about the publication, bugfix or CVE assignment. We will donate the bug bounty to open source projects and other non-profit organizations.
166+
2025-02-26: Our Below packager updated the openSUSE Tumbleweed package to the newly released version v0.9.0 [4], which happened to already contain the bugfix for the issue.
167+
2025-02-27: We identified commit 10e73a21d67 [13] as the likely bugfix and inquired with upstream once more about technical details and whether this is the complete bugfix they intended to apply.
168+
2025-02-28: We received an automated reply about the bugfix status of the issue.
169+
2025-03-03: We received a confirmation that commit 10e73a21d67 [13] is the intended bugfix and that further steps (including a possible CVE assignment) are handled internally.
170+
2025-03-03: We inquired whether it is okay for us to publish the full report at this time.
171+
2025-03-07: We did not get a response about publication from upstream so far. Since the bugfix was public but not clearly marked as a security issue we shared this report with the linux-distros [16] mailing list, suggesting an embargo of 5 days before general publication.
172+
2025-03-08: Michel Lind, a member of the linux-distros mailing list who is also a Meta engineer, involved upstream internally about the impending disclosure.
173+
2025-03-08: Upstream reached out to us stating that a GitHub security advisory on the issue is planned in the following week. They also shared the CVE assignment with us. They asked us to postpone publication on our end until that happens.
174+
2025-03-10: We responded that postponing publication is okay with us. We also pointed out that the linux-distros mailing list has a maximum embargo period of 14 days, which limited the maximum postponement to 2025-03-21.
175+
2025-03-12: Upstream published a GitHub advisory [5]. Thus general publication could happen on the date originally proposed by us on the linux-distros mailing list.
176+
177+
[1]: https://security.opensuse.org/2025/03/12/below-world-writable-log-dir.html
178+
[2]: https://github.com/facebookincubator/below
179+
[3]: https://github.com/facebookincubator/below/releases/tag/v0.8.1
180+
[4]: https://github.com/facebookincubator/below/releases/tag/v0.9.0
181+
[5]: https://github.com/facebookincubator/below/security/advisories/GHSA-9mc5-7qhg-fp3w
182+
[6]: https://github.com/facebookincubator/below/blob/v0.8.1/below/src/main.rs#L379
183+
[7]: https://build.opensuse.org/projects/openSUSE:Factory/packages/below/files/below.spec?expand=1&rev=5e78e7f743f87bea8648eeee673c649b
184+
[8]: https://github.com/gentoo/gentoo/blob/master/sys-process/below/below-0.8.1-r1.ebuild#L344
185+
[9]: https://src.fedoraproject.org/rpms/rust-below/blob/6ae58353b5d12e58462425c20a2aedfbae2e769a/f/rust-below.spec#_108
186+
[10]: https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=below#n34
187+
[11]: https://github.com/facebookincubator/below/blob/v0.8.1/below/src/main.rs#L552
188+
[12]: https://github.com/facebookincubator/below/blob/v0.8.1/below/src/open_source/logging.rs#L68
189+
[13]: https://github.com/facebookincubator/below/commit/10e73a21d67baa2cd613ee92ce999cda145e1a83
190+
[14]: https://bugzilla.suse.com/show_bug.cgi?id=1236109
191+
[15]: https://bugbounty.meta.com
192+
[16]: https://oss-security.openwall.org/wiki/mailing-lists/distros

0 commit comments

Comments
 (0)