mirror of
https://git.FreeBSD.org/doc.git
synced 2026-06-02 19:35:07 +00:00
Add EN-26:13 and SA-26:18 through SA-26:24.
Approved by: so
This commit is contained in:
@@ -1,6 +1,34 @@
|
||||
# Sort advisories by year, month and day
|
||||
# $FreeBSD$
|
||||
|
||||
[[advisories]]
|
||||
name = "FreeBSD-SA-26:24.cap_net"
|
||||
date = "2026-05-20"
|
||||
|
||||
[[advisories]]
|
||||
name = "FreeBSD-SA-26:23.bsdinstall"
|
||||
date = "2026-05-20"
|
||||
|
||||
[[advisories]]
|
||||
name = "FreeBSD-SA-26:22.libcasper"
|
||||
date = "2026-05-20"
|
||||
|
||||
[[advisories]]
|
||||
name = "FreeBSD-SA-26:21.ptrace"
|
||||
date = "2026-05-20"
|
||||
|
||||
[[advisories]]
|
||||
name = "FreeBSD-SA-26:20.fusefs"
|
||||
date = "2026-05-20"
|
||||
|
||||
[[advisories]]
|
||||
name = "FreeBSD-SA-26:19.file"
|
||||
date = "2026-05-20"
|
||||
|
||||
[[advisories]]
|
||||
name = "FreeBSD-SA-26:18.setcred"
|
||||
date = "2026-05-20"
|
||||
|
||||
[[advisories]]
|
||||
name = "FreeBSD-SA-26:17.libnv"
|
||||
date = "2026-04-29"
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# Sort errata notices by year, month and day
|
||||
# $FreeBSD$
|
||||
|
||||
[[notices]]
|
||||
name = "FreeBSD-EN-26:13.freebsd-update"
|
||||
date = "2026-05-20"
|
||||
|
||||
[[notices]]
|
||||
name = "FreeBSD-EN-26:12.freebsd-update"
|
||||
date = "2026-05-01"
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
=============================================================================
|
||||
FreeBSD-EN-26:13.freebsd-update Errata Notice
|
||||
The FreeBSD Project
|
||||
|
||||
Topic: freebsd-update attempts to merge a generated file
|
||||
|
||||
Category: core
|
||||
Module: freebsd-update
|
||||
Announced: 2026-05-20
|
||||
Affects: All supported versions of FreeBSD.
|
||||
Corrected: 2026-05-19 13:59:37 UTC (stable/15, 15.0-STABLE)
|
||||
2026-05-20 19:39:27 UTC (releng/15.0, 15.0-RELEASE-p9)
|
||||
2026-05-19 13:59:57 UTC (stable/14, 14.4-STABLE)
|
||||
2026-05-20 19:39:53 UTC (releng/14.4, 14.4-RELEASE-p5)
|
||||
2026-05-20 19:40:31 UTC (releng/14.3, 14.3-RELEASE-p14)
|
||||
|
||||
For general information regarding FreeBSD Errata Notices and Security
|
||||
Advisories, including descriptions of the fields above, security
|
||||
branches, and the following sections, please visit
|
||||
<URL:https://security.FreeBSD.org/>.
|
||||
|
||||
I. Background
|
||||
|
||||
The freebsd-update utility is used both to apply binary updates for security
|
||||
advisories and errata notices, and to upgrade from one FreeBSD release to
|
||||
another.
|
||||
|
||||
In the latter scenario, when it detects local changes to a configuration file
|
||||
which is affected by the upgrade, freebsd-update will perform a three-way
|
||||
merge and prompt the user to manually resolve any conflicts between local and
|
||||
incoming changes.
|
||||
|
||||
The certctl utility has been used since FreeBSD 12.0 to manage a hashed
|
||||
directory of root certificates for use when validating TLS server
|
||||
certificates. Since FreeBSD 15.0, certctl also maintains a bundle for the
|
||||
benefit of applications which either do not support the hashed directory
|
||||
format or need to preload the trust store prior to entering capability mode,
|
||||
a chroot, or similar.
|
||||
|
||||
II. Problem Description
|
||||
|
||||
When upgrading from FreeBSD 15.0 to FreeBSD 15.1, freebsd-update incorrectly
|
||||
treats the certificate bundle /etc/ssl/cert.pem as a configuration file. In
|
||||
most cases, the three-way merge results in conflicts which the user is then
|
||||
asked to resolve. The bundle is not human-readable, and merging it serves no
|
||||
purpose since freebsd-update regenerates the entire certificate store at the
|
||||
end of the upgrade.
|
||||
|
||||
When upgrading from an older FreeBSD release to FreeBSD 15.0 or 15.1, if
|
||||
/etc/ssl/cert.pem is present (e.g. as provided by the ETCSYMLINK option of
|
||||
the security/ca_root_nss port, or manually created by an administrator),
|
||||
freebsd-update will emit a non-fatal error message and pause until the user
|
||||
acknowledges the message.
|
||||
|
||||
III. Impact
|
||||
|
||||
Users upgrading from 15.0 to 15.1 may be presented with one or more merge
|
||||
conflicts in thousands of lines of Base64-encoded ASN.1 data.
|
||||
|
||||
Users upgrading from older releases to 15.0 or 15.1 may encounter a non-fatal
|
||||
error message with no clear resolution, reducing user confidence in the
|
||||
upgrade process.
|
||||
|
||||
IV. Workaround
|
||||
|
||||
If prompted to resolve conflicts, exit the editor and force freebsd-update
|
||||
to accept the unmerged file by typing "ACCEPT" (all upper-case, without the
|
||||
quotes). The bundle will be regenerated at the end of the upgrade process
|
||||
and the system will be fully functional.
|
||||
|
||||
V. Solution
|
||||
|
||||
Upgrade your system to a supported FreeBSD stable or release / security
|
||||
branch (releng) dated after the correction date.
|
||||
|
||||
Perform one of the following:
|
||||
|
||||
1) To update your system installed from base system packages:
|
||||
|
||||
Systems running a 15.0-RELEASE version of FreeBSD on the amd64 or arm64
|
||||
platforms, which were installed using base system packages, can be updated
|
||||
via the pkg(8) utility:
|
||||
|
||||
# pkg upgrade -r FreeBSD-base
|
||||
|
||||
2) To update your system installed from binary distribution sets:
|
||||
|
||||
Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms
|
||||
which were not installed using base system packages can be updated via the
|
||||
freebsd-update(8) utility:
|
||||
|
||||
# freebsd-update fetch
|
||||
# freebsd-update install
|
||||
|
||||
3) To update your system via a source code patch:
|
||||
|
||||
The following patches have been verified to apply to the applicable
|
||||
FreeBSD release branches.
|
||||
|
||||
a) Download the relevant patch from the location below, and verify the
|
||||
detached PGP signature using your PGP utility.
|
||||
|
||||
# fetch https://security.FreeBSD.org/patches/EN-26:13/freebsd-update.patch
|
||||
# fetch https://security.FreeBSD.org/patches/EN-26:13/freebsd-update.patch.asc
|
||||
# gpg --verify freebsd-update.patch.asc
|
||||
|
||||
b) Apply the patch. Execute the following commands as root:
|
||||
|
||||
# cd /usr/src
|
||||
# patch < /path/to/patch
|
||||
|
||||
c) Recompile the operating system using buildworld and installworld as
|
||||
described in <URL:https://www.FreeBSD.org/handbook/makeworld.html>.
|
||||
|
||||
VI. Correction details
|
||||
|
||||
This issue is corrected as of the corresponding Git commit hash in the
|
||||
following stable and release branches:
|
||||
|
||||
Branch/path Hash Revision
|
||||
- -------------------------------------------------------------------------
|
||||
stable/15/ b97f143b6ca9 stable/15-n283610
|
||||
releng/15.0/ 2709755d39f5 releng/15.0-n281037
|
||||
stable/14/ 7d9c1d3895b3 stable/14-n274144
|
||||
releng/14.4/ 081a9e933033 releng/14.4-n273701
|
||||
releng/14.3/ a1b3818746e3 releng/14.3-n271501
|
||||
- -------------------------------------------------------------------------
|
||||
|
||||
Run the following command to see which files were modified by a
|
||||
particular commit:
|
||||
|
||||
# git show --stat <commit hash>
|
||||
|
||||
Or visit the following URL, replacing NNNNNN with the hash:
|
||||
|
||||
<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>
|
||||
|
||||
To determine the commit count in a working tree (for comparison against
|
||||
nNNNNNN in the table above), run:
|
||||
|
||||
# git rev-list --count --first-parent HEAD
|
||||
|
||||
VII. References
|
||||
|
||||
The latest revision of this advisory is available at
|
||||
<URL:https://security.FreeBSD.org/advisories/FreeBSD-EN-26:13.freebsd-update.asc>
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAEBCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKGEbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvgJQP/RY20Qr2cM3gsEsVSt5+
|
||||
xXS/yCXu+IZq/ALOzw4RvqzdqvVzlA3U2VgSXpucnkrV0rABc7yxLbmvTVj6GOG7
|
||||
yvKXSmV58akQoUbnOtwHZF4x+4A9+Y3BzGIWUrzh014ll4MyhGw/4ekFiu36J0Mg
|
||||
QBDPkAy+3jrCTE3i2aAF1w1gLYdyIfDwGYQHqpPCsMmGhHuleogGqmhc5pH2J30g
|
||||
fPRLe8a4njizX5aT15TZvo6U5sQC6tll4DBUqTWh6k49XxSELKQwYgXhqhespI++
|
||||
yZ327VPwkVgaYI0C96LCV5SVB811BvFAKXKzjItKOWpJyg6HpB8hiSEubqlWW7zX
|
||||
vltqLyf8qe15wZPvrs1kgX2kH9ZJXYwJ9W5z5kY8sk/DCYos+bxtEQ47CU5u6/nF
|
||||
h01i3mAwOdh0/br7Y7hRS4eekNg9XUpu9dakJdhpJjbRylS6I6wK/C/f89L+qmgP
|
||||
4jq20TCFHQ2riVHxhOG3nSGkP+5CsIUnjg94x/EKK9xA9DZb0D5/Vy+hQYhJ5qza
|
||||
q5TKkv72vb32LKFKvzXXJbCrRlJr6bmCOMXYRGZwDzKzfd5jrVwzlIfooiaQ28bj
|
||||
g2egNBCe69H0SboydGi6J4yciBn3TeBHilfPuDLxs2eRZmYFd4wVD4wnigsysL2J
|
||||
JETeDqmCxDDqbzhIYf3XL7Pt
|
||||
=zyAg
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,170 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
=============================================================================
|
||||
FreeBSD-SA-26:18.setcred Security Advisory
|
||||
The FreeBSD Project
|
||||
|
||||
Topic: Stack buffer overflow via setcred(2)
|
||||
|
||||
Category: core
|
||||
Module: setcred
|
||||
Announced: 2026-05-20
|
||||
Credits: Ryan of Calif.io
|
||||
Credits: Przemyslaw Frasunek
|
||||
Affects: All supported versions of FreeBSD.
|
||||
Corrected: 2026-01-06 13:34:30 UTC (stable/15, 15.0-STABLE)
|
||||
2026-05-20 19:39:28 UTC (releng/15.0, 15.0-RELEASE-p9)
|
||||
2026-05-20 19:37:54 UTC (stable/14, 14.4-STABLE)
|
||||
2026-05-20 19:39:54 UTC (releng/14.4, 14.4-RELEASE-p5)
|
||||
2026-05-20 19:40:32 UTC (releng/14.3, 14.3-RELEASE-p14)
|
||||
CVE Name: CVE-2026-45250
|
||||
|
||||
This vulnerability was independently reported by multiple parties prior to
|
||||
publication.
|
||||
|
||||
For general information regarding FreeBSD Security Advisories,
|
||||
including descriptions of the fields above, security branches, and the
|
||||
following sections, please visit <URL:https://security.FreeBSD.org/>.
|
||||
|
||||
I. Background
|
||||
|
||||
System calls are the programmatic interface through which user-space
|
||||
processes request services from the operating system kernel, providing a
|
||||
controlled boundary between unprivileged application code and privileged
|
||||
kernel operations.
|
||||
|
||||
setcred(2) is a system call which enables a privileged process to atomically
|
||||
set its full credential set, including the real, effective, and saved user
|
||||
and group identifiers, as well as the list of supplementary groups. It is
|
||||
intended for use by programs such as login(1) and PAM(3)-aware authentication
|
||||
frameworks that must transition a process into a target user context in a
|
||||
single, race-free operation, replacing the need for multiple discrete calls
|
||||
to setuid(2), setgid(2), and setgroups(2).
|
||||
|
||||
II. Problem Description
|
||||
|
||||
The setcred(2) system call is only available to privileged users. However,
|
||||
before the privilege level of the caller is checked, the user-supplied list
|
||||
of supplementary groups is copied into a fixed-size kernel stack buffer
|
||||
without first validating its length. If the supplied list exceeds the
|
||||
capacity of that buffer, a stack buffer overflow occurs.
|
||||
|
||||
III. Impact
|
||||
|
||||
Because the bounds check on the supplementary groups list occurs after the
|
||||
kernel stack buffer has already been written, an unprivileged local user may
|
||||
trigger the overflow without holding any special privilege. Successful
|
||||
exploitation may allow an attacker to execute arbitrary code in the context
|
||||
of the kernel, allowing an unprivileged local user to gain elevated
|
||||
privileges on the affected system.
|
||||
|
||||
IV. Workaround
|
||||
|
||||
No workaround is available.
|
||||
|
||||
V. Solution
|
||||
|
||||
Upgrade your vulnerable system to a supported FreeBSD stable or
|
||||
release / security branch (releng) dated after the correction date,
|
||||
and reboot the system.
|
||||
|
||||
Perform one of the following:
|
||||
|
||||
1) To update your vulnerable system installed from base system packages:
|
||||
|
||||
Systems running a 15.0-RELEASE version of FreeBSD on the amd64 or arm64
|
||||
platforms, which were installed using base system packages, can be updated
|
||||
via the pkg(8) utility:
|
||||
|
||||
# pkg upgrade -r FreeBSD-base
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
2) To update your vulnerable system installed from binary distribution sets:
|
||||
|
||||
Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms
|
||||
which were not installed using base system packages can be updated via the
|
||||
freebsd-update(8) utility:
|
||||
|
||||
# freebsd-update fetch
|
||||
# freebsd-update install
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
3) To update your vulnerable system via a source code patch:
|
||||
|
||||
The following patches have been verified to apply to the applicable
|
||||
FreeBSD release branches.
|
||||
|
||||
a) Download the relevant patch from the location below, and verify the
|
||||
detached PGP signature using your PGP utility.
|
||||
|
||||
[FreeBSD 15.x]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:18/setcred-15.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:18/setcred-15.patch.asc
|
||||
# gpg --verify setcred-15.patch.asc
|
||||
|
||||
[FreeBSD 14.x]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:18/setcred-14.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:18/setcred-14.patch.asc
|
||||
# gpg --verify setcred-14.patch.asc
|
||||
|
||||
b) Apply the patch. Execute the following commands as root:
|
||||
|
||||
# cd /usr/src
|
||||
# patch < /path/to/patch
|
||||
|
||||
c) Recompile your kernel as described in
|
||||
<URL:https://www.FreeBSD.org/handbook/kernelconfig.html> and reboot the
|
||||
system.
|
||||
|
||||
VI. Correction details
|
||||
|
||||
This issue is corrected as of the corresponding Git commit hash in the
|
||||
following stable and release branches:
|
||||
|
||||
Branch/path Hash Revision
|
||||
- -------------------------------------------------------------------------
|
||||
stable/15/ b6cba9028457 stable/15-n281743
|
||||
releng/15.0/ d98c0a494a42 releng/15.0-n281038
|
||||
stable/14/ 8eb0bbbd2e46 stable/14-n274162
|
||||
releng/14.4/ 34da5845b8d4 releng/14.4-n273702
|
||||
releng/14.3/ bfff5c180193 releng/14.3-n271502
|
||||
- -------------------------------------------------------------------------
|
||||
|
||||
Run the following command to see which files were modified by a
|
||||
particular commit:
|
||||
|
||||
# git show --stat <commit hash>
|
||||
|
||||
Or visit the following URL, replacing NNNNNN with the hash:
|
||||
|
||||
<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>
|
||||
|
||||
To determine the commit count in a working tree (for comparison against
|
||||
nNNNNNN in the table above), run:
|
||||
|
||||
# git rev-list --count --first-parent HEAD
|
||||
|
||||
VII. References
|
||||
|
||||
<URL:https://www.cve.org/CVERecord?id=CVE-2026-45250>
|
||||
|
||||
The latest revision of this advisory is available at
|
||||
<URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-26:18.setcred.asc>
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAEBCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKGobFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvSpsP/38o7yHdNEMNMPPOBtKZ
|
||||
2dn/vmcOo1srkhUx0kl2EVBzirSDsTVkWfUq1Txg5JA7/pG3On/YiaAmUMi9jHqy
|
||||
q0tgkyO/scKGWNDYmFIA9QAXAwwSUZnT+eEwt3IawOzquezD/qr++CCimntSUzsu
|
||||
IP3oMFYaw9JvMF6Z6tTfcYYA02CF7nRrtIJtrxfWkgyDoMoikHsNW4o2LXJTz4bV
|
||||
2uk7BuQKbDc3gxoEBYd0bulXBa9DHsrfS59eEnbb8txrBjt21aQGjBY8SJSoFyYh
|
||||
yZixmadpZ9J4oTBc03hOO2Z2BN5f/QficGIU4t0wj0A8EcsrspFMDRj2xd/5zi86
|
||||
VLqiQf6WJbgVyytUe5aYbBPC6eH2TRnMWaOERbocNS6xQKcYpZYqwnVZ77n6tPb4
|
||||
wKQd+qKYM74lf0BPCBc60h7yo9e6Qd8puGolyL05qdZVB+c3m0qB000gsyNFytFs
|
||||
kQSovaXFf4r0DCEuBixE/Ic5ADwl7A4pCIxqwWwJlnrj77XCobNEQJtajkrapXsU
|
||||
MSLQ20RuRiVNesgyjP9dZCk8enuOl96TwrvdkyqvSJgb0Gw3XEeyCWT4dAE+Fh3A
|
||||
n8RhQeY6YWWk+DOiuw5Q5v2PyoBNoV8jV2AjeXzhIOQsyWGeSYQ2GeFu6PW3UyzQ
|
||||
olNjUPjprNwteRkUuGHmE3zQ
|
||||
=6aG+
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,173 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
=============================================================================
|
||||
FreeBSD-SA-26:19.file Security Advisory
|
||||
The FreeBSD Project
|
||||
|
||||
Topic: Kernel use-after-free via file descriptor syscalls
|
||||
|
||||
Category: core
|
||||
Module: file
|
||||
Announced: 2026-05-20
|
||||
Credits: 75Acol, Lexpl0it, fcgboy, and robinzeng2015
|
||||
Credits: Ryan at Calif.io
|
||||
Affects: All supported versions of FreeBSD.
|
||||
Corrected: 2026-05-20 19:36:37 UTC (stable/15, 15.0-STABLE)
|
||||
2026-05-20 19:39:31 UTC (releng/15.0, 15.0-RELEASE-p9)
|
||||
2026-05-20 19:37:57 UTC (stable/14, 14.4-STABLE)
|
||||
2026-05-20 19:39:57 UTC (releng/14.4, 14.4-RELEASE-p5)
|
||||
2026-05-20 19:40:34 UTC (releng/14.3, 14.3-RELEASE-p14)
|
||||
CVE Name: CVE-2026-45251
|
||||
|
||||
This vulnerability was independently reported by multiple parties prior to
|
||||
publication. The reporters' findings prompted a broader review by the
|
||||
FreeBSD Security Team, which identified additional occurrences of the same
|
||||
issue in related code. All known exploitable instances are corrected by this
|
||||
update.
|
||||
|
||||
For general information regarding FreeBSD Security Advisories,
|
||||
including descriptions of the fields above, security branches, and the
|
||||
following sections, please visit <URL:https://security.FreeBSD.org/>.
|
||||
|
||||
I. Background
|
||||
|
||||
FreeBSD implements a number of file descriptor types. Traditionally file
|
||||
descriptors are used to perform file or network I/O, but other variants
|
||||
exist such as process descriptors, which enable operations on a particular
|
||||
process.
|
||||
|
||||
The select(2) and poll(2) system calls allow applications to wait for events
|
||||
related to the object to which a file descriptor refers. These system calls
|
||||
are implemented for many different file descriptor types. For instance, a
|
||||
process descriptor may be used with either system call to wait for the target
|
||||
process to exit.
|
||||
|
||||
II. Problem Description
|
||||
|
||||
A file descriptor can be closed while a thread is blocked in a poll(2) or
|
||||
select(2) call waiting for that descriptor. Because the blocked thread does
|
||||
not hold a reference to the underlying object, this closure may result in the
|
||||
object being freed while the thread remains blocked. In this situation, the
|
||||
kernel must remove the blocked thread from the per-object wait queue prior to
|
||||
freeing the object.
|
||||
|
||||
In the case of some file descriptor types, the kernel failed to unlink
|
||||
blocked threads from the object before freeing it. When the blocked thread
|
||||
is subsequently woken, it accesses memory that has already been freed
|
||||
resulting in a use-after-free vulnerability.
|
||||
|
||||
III. Impact
|
||||
|
||||
The use-after-free vulnerability may be triggered by an unprivileged local
|
||||
user and can be exploited to obtain superuser privileges.
|
||||
|
||||
IV. Workaround
|
||||
|
||||
No workaround is available.
|
||||
|
||||
V. Solution
|
||||
|
||||
Upgrade your vulnerable system to a supported FreeBSD stable or
|
||||
release / security branch (releng) dated after the correction date, and
|
||||
reboot the system.
|
||||
|
||||
Perform one of the following:
|
||||
|
||||
1) To update your vulnerable system installed from base system packages:
|
||||
|
||||
Systems running a 15.0-RELEASE version of FreeBSD on the amd64 or arm64
|
||||
platforms, which were installed using base system packages, can be updated
|
||||
via the pkg(8) utility:
|
||||
|
||||
# pkg upgrade -r FreeBSD-base
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
2) To update your vulnerable system installed from binary distribution sets:
|
||||
|
||||
Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms
|
||||
which were not installed using base system packages can be updated via the
|
||||
freebsd-update(8) utility:
|
||||
|
||||
# freebsd-update fetch
|
||||
# freebsd-update install
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
3) To update your vulnerable system via a source code patch:
|
||||
|
||||
The following patches have been verified to apply to the applicable
|
||||
FreeBSD release branches.
|
||||
|
||||
a) Download the relevant patch from the location below, and verify the
|
||||
detached PGP signature using your PGP utility.
|
||||
|
||||
[FreeBSD 15.x]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:19/file-15.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:19/file-15.patch.asc
|
||||
# gpg --verify file-15.patch.asc
|
||||
|
||||
[FreeBSD 14.x]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:19/file-14.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:19/file-14.patch.asc
|
||||
# gpg --verify file-14.patch.asc
|
||||
|
||||
b) Apply the patch. Execute the following commands as root:
|
||||
|
||||
# cd /usr/src
|
||||
# patch < /path/to/patch
|
||||
|
||||
c) Recompile your kernel as described in
|
||||
<URL:https://www.FreeBSD.org/handbook/kernelconfig.html> and reboot the
|
||||
system.
|
||||
|
||||
VI. Correction details
|
||||
|
||||
This issue is corrected as of the corresponding Git commit hash in the
|
||||
following stable and release branches:
|
||||
|
||||
Branch/path Hash Revision
|
||||
- -------------------------------------------------------------------------
|
||||
stable/15/ 53a78e582a6f stable/15-n283641
|
||||
releng/15.0/ af79f4148450 releng/15.0-n281041
|
||||
stable/14/ b90b25c3779e stable/14-n274164
|
||||
releng/14.4/ 8d8694c224e2 releng/14.4-n273704
|
||||
releng/14.3/ 659818009d15 releng/14.3-n271504
|
||||
- -------------------------------------------------------------------------
|
||||
|
||||
Run the following command to see which files were modified by a
|
||||
particular commit:
|
||||
|
||||
# git show --stat <commit hash>
|
||||
|
||||
Or visit the following URL, replacing NNNNNN with the hash:
|
||||
|
||||
<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>
|
||||
|
||||
To determine the commit count in a working tree (for comparison against
|
||||
nNNNNNN in the table above), run:
|
||||
|
||||
# git rev-list --count --first-parent HEAD
|
||||
|
||||
VII. References
|
||||
|
||||
<URL:https://www.cve.org/CVERecord?id=CVE-2026-45251>
|
||||
|
||||
The latest revision of this advisory is available at
|
||||
<URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-26:19.file.asc>
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAEBCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKG4bFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvA78P/iRlQXxVUpth5tRn2FiC
|
||||
lseIWOmh3DVI1OjwFQ30VydwnA5rlOqPPTpF2hsT0ee3ExS6pUKITi3735BmkPvT
|
||||
KvnOKkY9A2DdzXJQ9eZvrVJRN1/VlKx8Us1VmWWRxPHghmcqqTY0wN2lFcsyqcpN
|
||||
6Wdi51z+X5sLWZZsLsvqAskWiCNqUzBSSWqCTLEW0tBD9AoW2BPQcpAeEmx4MDch
|
||||
Hk2/pecoUL2T/hu3bjo60CTp3R7E4gPt9wM5Ejf32vwsW0sTNkTmy7HbZCNmYHZw
|
||||
R764O4i4poDzccTiXxuhXdrIDXmRQwTyB9d6S12OmP8ec8dAQzm9p5xl4HoHhOho
|
||||
9zTMCiLoU+ApN1H+bXqN9JvmZ9hfxGqdPaJgZRkQ11xRHg8tz48SigON/vxlbYff
|
||||
ln9EJ+NGEcskrbUAG8cUCJ3/a8A7xLQo07TpvyddeUc6ufk+nFEBzNS3rpaFNy5y
|
||||
GqFIOzqISRSsE1tf6rrItULQEKWtOMUYvAbrcLRwPAQ1cav+sOv9YlfpW36s1+mc
|
||||
CyuXDh3pbN5biajjImGO1CYN92mq/Jfz/cRnvQub+78T+4w6yAxj53fBNg97tIOI
|
||||
b7EISAnbgGj5akQRGJXJ84iuYij9xTPEOCSbfgAqsWXKz6l/bgSoVUhq/e0/dXKA
|
||||
sr+3pjhi5P7N66SvO+7iEpYI
|
||||
=iM1b
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,164 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
=============================================================================
|
||||
FreeBSD-SA-26:20.fusefs Security Advisory
|
||||
The FreeBSD Project
|
||||
|
||||
Topic: Heap overflow in FUSE_LISTXATTR
|
||||
|
||||
Category: core
|
||||
Module: fusefs
|
||||
Announced: 2026-05-20
|
||||
Credits: Joshua Rogers of AISLE Research Team
|
||||
Affects: All supported versions of FreeBSD.
|
||||
Corrected: 2026-05-20 19:36:38 UTC (stable/15, 15.0-STABLE)
|
||||
2026-05-20 19:39:32 UTC (releng/15.0, 15.0-RELEASE-p9)
|
||||
2026-05-20 19:37:58 UTC (stable/14, 14.4-STABLE)
|
||||
2026-05-20 19:39:58 UTC (releng/14.4, 14.4-RELEASE-p5)
|
||||
2026-05-20 19:40:36 UTC (releng/14.3, 14.3-RELEASE-p14)
|
||||
CVE Name: CVE-2026-45252
|
||||
|
||||
For general information regarding FreeBSD Security Advisories,
|
||||
including descriptions of the fields above, security branches, and the
|
||||
following sections, please visit <URL:https://security.FreeBSD.org/>.
|
||||
|
||||
I. Background
|
||||
|
||||
The fusefs file system delegates file system operations to a userspace
|
||||
daemon. This daemon ordinarily requires root privileges to operate. When
|
||||
the "vfs.usermount" sysctl is set to 1 (not the default), unprivileged users
|
||||
are permitted to run such daemons and mount fusefs file systems.
|
||||
|
||||
II. Problem Description
|
||||
|
||||
When a fusefs file system implements extended attributes, the kernel may send
|
||||
a FUSE_LISTXATTR message to the userspace daemon to retrieve the list of extended
|
||||
attributes for a given file. The FUSE protocol requires the daemon to return
|
||||
a packed list of NUL-terminated strings. The fusefs kernel module calls
|
||||
strlen() on this daemon-supplied buffer without first verifying that the
|
||||
entire list is NUL-terminated.
|
||||
|
||||
III. Impact
|
||||
|
||||
If a malicious daemon sends a non-NUL-terminated list, the fusefs kernel
|
||||
module may read beyond the end of one heap-allocated buffer and potentially
|
||||
write beyond the end of a second buffer. A malicious daemon could disclose
|
||||
up to 253 bytes of kernel heap memory, or it could inject up to 250
|
||||
attacker-controlled bytes into unallocated kernel heap space.
|
||||
|
||||
IV. Workaround
|
||||
|
||||
No workaround is available, but systems that do not load the fusefs kernel
|
||||
module or set vfs.usermount=1 are unaffected.
|
||||
|
||||
V. Solution
|
||||
|
||||
Upgrade your vulnerable system to a supported FreeBSD stable or
|
||||
release / security branch (releng) dated after the correction date, and
|
||||
reboot the system.
|
||||
|
||||
Perform one of the following:
|
||||
|
||||
1) To update your vulnerable system installed from base system packages:
|
||||
|
||||
Systems running a 15.0-RELEASE version of FreeBSD on the amd64 or arm64
|
||||
platforms, which were installed using base system packages, can be updated
|
||||
via the pkg(8) utility:
|
||||
|
||||
# pkg upgrade -r FreeBSD-base
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
2) To update your vulnerable system installed from binary distribution sets:
|
||||
|
||||
Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms
|
||||
which were not installed using base system packages can be updated via the
|
||||
freebsd-update(8) utility:
|
||||
|
||||
# freebsd-update fetch
|
||||
# freebsd-update install
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
3) To update your vulnerable system via a source code patch:
|
||||
|
||||
The following patches have been verified to apply to the applicable
|
||||
FreeBSD release branches.
|
||||
|
||||
a) Download the relevant patch from the location below, and verify the
|
||||
detached PGP signature using your PGP utility.
|
||||
|
||||
[FreeBSD 15.0]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:20/fusefs-15.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:20/fusefs-15.patch.asc
|
||||
# gpg --verify fusefs-15.patch.asc
|
||||
|
||||
[FreeBSD 14.4]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:20/fusefs-14.4.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:20/fusefs-14.4.patch.asc
|
||||
# gpg --verify fusefs-14.4.patch.asc
|
||||
|
||||
[FreeBSD 14.3]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:20/fusefs-14.3.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:20/fusefs-14.3.patch.asc
|
||||
# gpg --verify fusefs-14.3.patch.asc
|
||||
|
||||
b) Apply the patch. Execute the following commands as root:
|
||||
|
||||
# cd /usr/src
|
||||
# patch < /path/to/patch
|
||||
|
||||
c) Recompile your kernel as described in
|
||||
<URL:https://www.FreeBSD.org/handbook/kernelconfig.html> and reboot the
|
||||
system.
|
||||
|
||||
VI. Correction details
|
||||
|
||||
This issue is corrected as of the corresponding Git commit hash in the
|
||||
following stable and release branches:
|
||||
|
||||
Branch/path Hash Revision
|
||||
- -------------------------------------------------------------------------
|
||||
stable/15/ df3f3fa82775 stable/15-n283642
|
||||
releng/15.0/ 0dd8b983db3c releng/15.0-n281042
|
||||
stable/14/ 25148c51c8c6 stable/14-n274165
|
||||
releng/14.4/ 6a299460f159 releng/14.4-n273705
|
||||
releng/14.3/ 53f3bf4ee1ce releng/14.3-n271505
|
||||
- -------------------------------------------------------------------------
|
||||
|
||||
Run the following command to see which files were modified by a
|
||||
particular commit:
|
||||
|
||||
# git show --stat <commit hash>
|
||||
|
||||
Or visit the following URL, replacing NNNNNN with the hash:
|
||||
|
||||
<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>
|
||||
|
||||
To determine the commit count in a working tree (for comparison against
|
||||
nNNNNNN in the table above), run:
|
||||
|
||||
# git rev-list --count --first-parent HEAD
|
||||
|
||||
VII. References
|
||||
|
||||
<URL:https://www.cve.org/CVERecord?id=CVE-2026-45252>
|
||||
|
||||
The latest revision of this advisory is available at
|
||||
<URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-26:20.fusefs.asc>
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAEBCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKHIbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvobkP/R3O3bwsnJkhG1NQ6pKh
|
||||
UFcwpZ8TSAqtccHZRQz2zoKTqu/EeClT7Bdgw/Qa8gbZ7IfZgS8AJaR7e4fgpE96
|
||||
AhHU6cbyZrpwvWUatIKgX57032+M1ioMiz9g0KbGg4W4WKe/QHj4yt45F7qRfLNb
|
||||
BD7Qp7E0XtV+UrNXkhOQQmHyVTpB85tK/e5Yc+vcSgAQ3LWrzwO4zED4f78e3faw
|
||||
oiLm1oE/Vx0jfrRKsnCECdJS532xlfH6iJ2/2ZXfUthGQmZQe34wOMwYS0EcaGZV
|
||||
TQoLwsg5qLj4hJOGMCZk4X4TjrkoQquWdsAQetB8tqXIyw7QEgbMIIbhS3mQZ5CW
|
||||
aEq3wbYMowxCMb/6Dd/R56wDqyGI2Z6GHmUT58M0OSIIISfsD+UHOCW2lrQQ5zrI
|
||||
o1O/IFAvqsmCN6JQzFgC3KC8BLLZWzxf5Bun6yOls/YA31zOXAen0isnbOvVnGot
|
||||
42Dy65fENCUQMt+p3eDDLQzxDhlqGAGbiqysBmxwTA5Wqc4furv7O0wmBPwOOGeH
|
||||
NqlKYsqO9u4kEW2lTCPs7R5+wsc+EACc07kikDQgp1m59JlkMfmXU4Kbcgw9r4GR
|
||||
9OWtidfTCDGmt9mXzJVKaBurgJ1iqsBfzzLamWo0iDpUMgUP7VA9jVjVbUmtjH1V
|
||||
qAWdXCXwrbOr+eA50IIPxkal
|
||||
=HzW3
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,163 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
=============================================================================
|
||||
FreeBSD-SA-26:21.ptrace Security Advisory
|
||||
The FreeBSD Project
|
||||
|
||||
Topic: Missing validation in ptrace(PT_SC_REMOTE)
|
||||
|
||||
Category: core
|
||||
Module: ptrace
|
||||
Announced: 2026-05-20
|
||||
Credits: Yuxiang Yang, Yizhou Zhao, Ao Wang, Xuewei Feng, Qi Li,
|
||||
and Ke Xu from Tsinghua University using GLM-5.1 from Z.ai
|
||||
Credits: Ryan at Calif.io
|
||||
Affects: All supported versions of FreeBSD.
|
||||
Corrected: 2026-05-20 19:36:40 UTC (stable/15, 15.0-STABLE)
|
||||
2026-05-20 19:39:34 UTC (releng/15.0, 15.0-RELEASE-p9)
|
||||
2026-05-20 19:37:59 UTC (stable/14, 14.4-STABLE)
|
||||
2026-05-20 19:39:59 UTC (releng/14.4, 14.4-RELEASE-p5)
|
||||
2026-05-20 19:40:37 UTC (releng/14.3, 14.3-RELEASE-p14)
|
||||
CVE Name: CVE-2026-45253
|
||||
|
||||
This vulnerability was independently reported by multiple parties prior to
|
||||
publication.
|
||||
|
||||
For general information regarding FreeBSD Security Advisories,
|
||||
including descriptions of the fields above, security branches, and the
|
||||
following sections, please visit <URL:https://security.FreeBSD.org/>.
|
||||
|
||||
I. Background
|
||||
|
||||
The ptrace(2) system call provides facilities for a debugger to control the
|
||||
execution of a target process and to obtain status information about it.
|
||||
Among other capabilities, it permits a debugger to execute arbitrary system
|
||||
calls in the target process via the PT_SC_REMOTE operation.
|
||||
|
||||
II. Problem Description
|
||||
|
||||
ptrace(PT_SC_REMOTE) failed to properly validate parameters for the syscall(2)
|
||||
and __syscall(2) meta-system calls. As a result, a user with the ability to
|
||||
debug a process may trigger arbitrary code execution in the kernel, even if
|
||||
the target process has no special privileges.
|
||||
|
||||
III. Impact
|
||||
|
||||
The missing validation allows an unprivileged local user to escalate
|
||||
privileges, potentially gaining full control of the affected system.
|
||||
|
||||
IV. Workaround
|
||||
|
||||
No workaround is available.
|
||||
|
||||
V. Solution
|
||||
|
||||
Upgrade your vulnerable system to a supported FreeBSD stable or
|
||||
release / security branch (releng) dated after the correction date, and
|
||||
reboot the system.
|
||||
|
||||
Perform one of the following:
|
||||
|
||||
1) To update your vulnerable system installed from base system packages:
|
||||
|
||||
Systems running a 15.0-RELEASE version of FreeBSD on the amd64 or arm64
|
||||
platforms, which were installed using base system packages, can be updated
|
||||
via the pkg(8) utility:
|
||||
|
||||
# pkg upgrade -r FreeBSD-base
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
2) To update your vulnerable system installed from binary distribution sets:
|
||||
|
||||
Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms
|
||||
which were not installed using base system packages can be updated via the
|
||||
freebsd-update(8) utility:
|
||||
|
||||
# freebsd-update fetch
|
||||
# freebsd-update install
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
3) To update your vulnerable system via a source code patch:
|
||||
|
||||
The following patches have been verified to apply to the applicable
|
||||
FreeBSD release branches.
|
||||
|
||||
a) Download the relevant patch from the location below, and verify the
|
||||
detached PGP signature using your PGP utility.
|
||||
|
||||
[FreeBSD 15.0]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:21/ptrace-15.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:21/ptrace-15.patch.asc
|
||||
# gpg --verify ptrace-15.patch.asc
|
||||
|
||||
[FreeBSD 14.4]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:21/ptrace-14.4.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:21/ptrace-14.4.patch.asc
|
||||
# gpg --verify ptrace-14.4.patch.asc
|
||||
|
||||
[FreeBSD 14.3]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:21/ptrace-14.3.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:21/ptrace-14.3.patch.asc
|
||||
# gpg --verify ptrace-14.3.patch.asc
|
||||
|
||||
b) Apply the patch. Execute the following commands as root:
|
||||
|
||||
# cd /usr/src
|
||||
# patch < /path/to/patch
|
||||
|
||||
c) Recompile your kernel as described in
|
||||
<URL:https://www.FreeBSD.org/handbook/kernelconfig.html> and reboot the
|
||||
system.
|
||||
|
||||
VI. Correction details
|
||||
|
||||
This issue is corrected as of the corresponding Git commit hash in the
|
||||
following stable and release branches:
|
||||
|
||||
Branch/path Hash Revision
|
||||
- -------------------------------------------------------------------------
|
||||
stable/15/ 3b4afab9add2 stable/15-n283643
|
||||
releng/15.0/ fd24dd0b38a8 releng/15.0-n281043
|
||||
stable/14/ fac902a3e039 stable/14-n274166
|
||||
releng/14.4/ c21d23f0f8be releng/14.4-n273706
|
||||
releng/14.3/ 45bd421661c4 releng/14.3-n271506
|
||||
- -------------------------------------------------------------------------
|
||||
|
||||
Run the following command to see which files were modified by a
|
||||
particular commit:
|
||||
|
||||
# git show --stat <commit hash>
|
||||
|
||||
Or visit the following URL, replacing NNNNNN with the hash:
|
||||
|
||||
<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>
|
||||
|
||||
To determine the commit count in a working tree (for comparison against
|
||||
nNNNNNN in the table above), run:
|
||||
|
||||
# git rev-list --count --first-parent HEAD
|
||||
|
||||
VII. References
|
||||
|
||||
<URL:https://www.cve.org/CVERecord?id=CVE-2026-45253>
|
||||
|
||||
The latest revision of this advisory is available at
|
||||
<URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-26:21.ptrace.asc>
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAEBCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKHcbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvLd0QAOQGyaTmlTQJTS+EIPMU
|
||||
+poVU59Fe4L+/+H8LSibnCPBbycH1bv6m9e906s/za0IBLGVq7PhY0U1YtPO5++J
|
||||
A86nLzgqk4hEU5RWmA3+dnLYrIxOf3fVvSev/XAZe/1eWwcljYRCtqLV+IBmyxeZ
|
||||
amfYoXliUTuZHO+r+88HVAgDy6efZ3IlnHF9iMlpsF0IFezpgFh4E6tiJk9/pMlz
|
||||
wuXpHCm34rEjy6bvQaDP9G1zXGszrEatT25d9rKZnHscZCQuRgtpLaOVCuH8oDca
|
||||
+1PFTfTNJnepH9Ir1nSaYLViZdHfuDK40CafZm54q4669AramrySoxNJlnNHOiMK
|
||||
DN4aqxMfW5xCEEK+fIJYqTyW2L3WzRJ8tm3bF/zzsMYTsNmclcklzmuMNqsGQls1
|
||||
TGIhb+J+e0vkdZOpuJaT65pmGaF2dJeBvwNsIMJgtY3yotUPbDFD1ALNVUwIkKYh
|
||||
m68XK0Ykw93ySLjbORUVFLP5nv5PvYtubAy37q5tskN6hXLlyX5a0QxIL5T5u0jx
|
||||
hwDnyl4UAHGmkBM8U0CnaQbixP/yV0p5q+3NtpBurHB74tov593/U1eroydDywRl
|
||||
Mw2R3k7AFIC5CszwMA6J0l3W2tLq/j7tcTQ/8CNgPpP/TPVntQxQShxB93F+/MdX
|
||||
n9D4phEb7cKk4Y9QIBKkdbYZ
|
||||
=egz5
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,155 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
=============================================================================
|
||||
FreeBSD-SA-26:22.libcasper Security Advisory
|
||||
The FreeBSD Project
|
||||
|
||||
Topic: select(2) file descriptor set overflow causes stack overflow
|
||||
|
||||
Category: core
|
||||
Module: libcasper
|
||||
Announced: 2026-05-20
|
||||
Credits: Joshua Rogers of AISLE Research Team
|
||||
Affects: All supported versions of FreeBSD.
|
||||
Corrected: 2026-05-20 19:36:41 UTC (stable/15, 15.0-STABLE)
|
||||
2026-05-20 19:39:35 UTC (releng/15.0, 15.0-RELEASE-p9)
|
||||
2026-05-20 19:38:00 UTC (stable/14, 14.4-STABLE)
|
||||
2026-05-20 19:40:00 UTC (releng/14.4, 14.4-RELEASE-p5)
|
||||
2026-05-20 19:40:38 UTC (releng/14.3, 14.3-RELEASE-p14)
|
||||
CVE Name: CVE-2026-39461
|
||||
|
||||
For general information regarding FreeBSD Security Advisories,
|
||||
including descriptions of the fields above, security branches, and the
|
||||
following sections, please visit <URL:https://security.FreeBSD.org/>.
|
||||
|
||||
I. Background
|
||||
|
||||
libcasper(3) allows Capsicum-sandboxed applications to access system
|
||||
interfaces that are otherwise unavailable within the sandbox. It is
|
||||
used by numerous programs in the base system.
|
||||
|
||||
II. Problem Description
|
||||
|
||||
libcasper(3) communicates with helper processes via UNIX domain sockets, and
|
||||
uses the select(2) system call to wait for data to become available.
|
||||
However, it does not verify that its socket descriptor fits within
|
||||
select(2)'s descriptor set size limit of FD_SETSIZE (1024).
|
||||
|
||||
III. Impact
|
||||
|
||||
An attacker able to cause an application using libcasper(3) to allocate large
|
||||
file descriptors, e.g., by opening many descriptors and executing a program
|
||||
which is not careful to close them upon startup, may trigger stack
|
||||
corruption. If the target application runs with setuid root privileges, this
|
||||
could be used to escalate local privileges.
|
||||
|
||||
IV. Workaround
|
||||
|
||||
No workaround is available.
|
||||
|
||||
V. Solution
|
||||
|
||||
Upgrade your vulnerable system to a supported FreeBSD stable or
|
||||
release / security branch (releng) dated after the correction date.
|
||||
|
||||
Perform one of the following:
|
||||
|
||||
1) To update your vulnerable system installed from base system packages:
|
||||
|
||||
Systems running a 15.0-RELEASE version of FreeBSD on the amd64 or arm64
|
||||
platforms, which were installed using base system packages, can be updated
|
||||
via the pkg(8) utility:
|
||||
|
||||
# pkg upgrade -r FreeBSD-base
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
2) To update your vulnerable system installed from binary distribution sets:
|
||||
|
||||
Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms,
|
||||
or the i386 platform on FreeBSD 13, which were not installed using base
|
||||
system packages, can be updated via the freebsd-update(8) utility:
|
||||
|
||||
# freebsd-update fetch
|
||||
# freebsd-update install
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
3) To update your vulnerable system via a source code patch:
|
||||
|
||||
The following patches have been verified to apply to the applicable
|
||||
FreeBSD release branches.
|
||||
|
||||
a) Download the relevant patch from the location below, and verify the
|
||||
detached PGP signature using your PGP utility.
|
||||
|
||||
[FreeBSD 15.x]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:22/libcasper-15.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:22/libcasper-15.patch.asc
|
||||
# gpg --verify libcasper-15.patch.asc
|
||||
|
||||
[FreeBSD 14.x]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:22/libcasper-14.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:22/libcasper-14.patch.asc
|
||||
# gpg --verify libcasper-14.patch.asc
|
||||
|
||||
b) Apply the patch. Execute the following commands as root:
|
||||
|
||||
# cd /usr/src
|
||||
# patch < /path/to/patch
|
||||
|
||||
c) Recompile the operating system using buildworld and installworld as
|
||||
described in <URL:https://www.FreeBSD.org/handbook/makeworld.html>.
|
||||
|
||||
Restart the applicable daemons, or reboot the system.
|
||||
|
||||
VI. Correction details
|
||||
|
||||
This issue is corrected as of the corresponding Git commit hash in the
|
||||
following stable and release branches:
|
||||
|
||||
Branch/path Hash Revision
|
||||
- -------------------------------------------------------------------------
|
||||
stable/15/ 23929d729d1a stable/15-n283644
|
||||
releng/15.0/ e22f3f55c360 releng/15.0-n281044
|
||||
stable/14/ 9e74d5e2e5e4 stable/14-n274167
|
||||
releng/14.4/ ae34dd1a391f releng/14.4-n273707
|
||||
releng/14.3/ cbec31838173 releng/14.3-n271507
|
||||
- -------------------------------------------------------------------------
|
||||
|
||||
Run the following command to see which files were modified by a
|
||||
particular commit:
|
||||
|
||||
# git show --stat <commit hash>
|
||||
|
||||
Or visit the following URL, replacing NNNNNN with the hash:
|
||||
|
||||
<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>
|
||||
|
||||
To determine the commit count in a working tree (for comparison against
|
||||
nNNNNNN in the table above), run:
|
||||
|
||||
# git rev-list --count --first-parent HEAD
|
||||
|
||||
VII. References
|
||||
|
||||
<URL:https://www.cve.org/CVERecord?id=CVE-2026-39461>
|
||||
|
||||
The latest revision of this advisory is available at
|
||||
<URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-26:22.libcasper.asc>
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAEBCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKHsbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrveQAP/iyv1O1XI6tSrRictadU
|
||||
9tBJFE5WlWGPrB8ID/12nLsKaTM5hzbA1G+v8c3So3FaSEl+m7D8BTri4X0XPibQ
|
||||
5Pp4v67MO+yqsNxOjwyqAizOnD5bk/sEUuBV5JijZuqsAiEWFw5l0dKDU83zt3vu
|
||||
hyk8/eeKuIxEwDiWQoeE32RM3BupY1ClWp46kiSjvOVzUK04miHQjgFFnVqkBuI7
|
||||
DeanTjzCw3g+RQNTRKVGE2LYRLFHka6m4Z5RYT7beFOLdlD58T7lvQLl3l3f2QSR
|
||||
hXcq5RxAhf4omPkm432fIdd4nev4gti3rxJC76NM2rIHGeSlRd4O7MHreNwNkU2O
|
||||
8Rv8IWMCM20zZCtbov7q8XbTqKp8JXSJ/8g15iZuZ4wk+THnpRy7dsRe5eYQvVbB
|
||||
J/zBKB9xMXGp69+88uZHDsSSoS841pkZ61+MlxeK4xC3MO6tlTO0Hannhmy8WCb4
|
||||
U5GimvX3EcvhGeBWRvPTdPJY9EcrDPDU2djaiFzPZZ7rrUjR8YJ685fyj161nnb+
|
||||
ibubcwiz7ygQu8b9T0rc1AV5ZTAC/QAlRarDpRNx2Ynh/FlZ89n+N5LnSHwGXc/v
|
||||
/P+ob/5AqdLfyofw5pcx/FVuAiK4bjqDGGYuZw1tplg/L7AV3k87zIMYdCgr3e95
|
||||
PyQCsFAG014gMVETPGHKm6/7
|
||||
=ypPx
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,155 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
=============================================================================
|
||||
FreeBSD-SA-26:23.bsdinstall Security Advisory
|
||||
The FreeBSD Project
|
||||
|
||||
Topic: Remote code execution via installer Wi-Fi access point scans
|
||||
|
||||
Category: core
|
||||
Module: bsdinstall
|
||||
Announced: 2026-05-20
|
||||
Credits: Austin Ralls
|
||||
Affects: All supported versions of FreeBSD.
|
||||
Corrected: 2026-05-20 19:36:43 UTC (stable/15, 15.0-STABLE)
|
||||
2026-05-20 19:39:37 UTC (releng/15.0, 15.0-RELEASE-p9)
|
||||
2026-05-20 19:38:03 UTC (stable/14, 14.4-STABLE)
|
||||
2026-05-20 19:40:02 UTC (releng/14.4, 14.4-RELEASE-p5)
|
||||
2026-05-20 19:40:40 UTC (releng/14.3, 14.3-RELEASE-p14)
|
||||
CVE Name: CVE-2026-45255
|
||||
|
||||
For general information regarding FreeBSD Security Advisories,
|
||||
including descriptions of the fields above, security branches, and the
|
||||
following sections, please visit <URL:https://security.FreeBSD.org/>.
|
||||
|
||||
I. Background
|
||||
|
||||
bsdinstall and bsdconfig are utilities that provide an interactive
|
||||
configuration mechanism for FreeBSD. Among other functionality, they can be
|
||||
used to configure FreeBSD to automatically join a Wi-Fi network.
|
||||
|
||||
II. Problem Description
|
||||
|
||||
When bsdinstall or bsdconfig are prompted to scan for nearby Wi-Fi networks,
|
||||
they build up a list of network names and use bsddialog(1) to prompt the user
|
||||
to select a network. This is implemented using a shell script, and the code
|
||||
which handled network names was not careful to prevent expansion by the
|
||||
shell. As a result, a suitably crafted network name can be used to execute
|
||||
commands via a subshell.
|
||||
|
||||
III. Impact
|
||||
|
||||
The problem can be exploited to execute code as root on the system running
|
||||
bsdinstall or bsdconfig. The attacker would need to create an access point
|
||||
with a specially crafted name and be within range of a Wi-Fi scan. Note that
|
||||
bsdinstall and bsdconfig are vulnerable as soon as the user prompts them to
|
||||
scan for nearby networks; they do not need to actually select the malicious
|
||||
network.
|
||||
|
||||
IV. Workaround
|
||||
|
||||
Avoid using bsdinstall or bsdconfig to scan for Wi-Fi networks, and instead
|
||||
configure Wi-Fi manually.
|
||||
|
||||
V. Solution
|
||||
|
||||
Upgrade your vulnerable system to a supported FreeBSD stable or
|
||||
release / security branch (releng) dated after the correction date.
|
||||
|
||||
Perform one of the following:
|
||||
|
||||
1) To update your vulnerable system installed from base system packages:
|
||||
|
||||
Systems running a 15.0-RELEASE version of FreeBSD on the amd64 or arm64
|
||||
platforms, which were installed using base system packages, can be updated
|
||||
via the pkg(8) utility:
|
||||
|
||||
# pkg upgrade -r FreeBSD-base
|
||||
|
||||
2) To update your vulnerable system installed from binary distribution sets:
|
||||
|
||||
Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms
|
||||
which were not installed using base system packages can be updated via the
|
||||
freebsd-update(8) utility:
|
||||
|
||||
# freebsd-update fetch
|
||||
# freebsd-update install
|
||||
|
||||
3) To update your vulnerable system via a source code patch:
|
||||
|
||||
The following patches have been verified to apply to the applicable
|
||||
FreeBSD release branches.
|
||||
|
||||
a) Download the relevant patch from the location below, and verify the
|
||||
detached PGP signature using your PGP utility.
|
||||
|
||||
[FreeBSD 15.x]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:23/bsdinstall-15.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:23/bsdinstall-15.patch.asc
|
||||
# gpg --verify bsdinstall-15.patch.asc
|
||||
|
||||
[FreeBSD 14.x]
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:23/bsdinstall-14.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:23/bsdinstall-14.patch.asc
|
||||
# gpg --verify bsdinstall-14.patch.asc
|
||||
|
||||
b) Apply the patch. Execute the following commands as root:
|
||||
|
||||
# cd /usr/src
|
||||
# patch < /path/to/patch
|
||||
|
||||
c) Recompile the operating system using buildworld and installworld as
|
||||
described in <URL:https://www.FreeBSD.org/handbook/makeworld.html>.
|
||||
|
||||
VI. Correction details
|
||||
|
||||
This issue is corrected as of the corresponding Git commit hash in the
|
||||
following stable and release branches:
|
||||
|
||||
Branch/path Hash Revision
|
||||
- -------------------------------------------------------------------------
|
||||
stable/15/ 6f5674b97fd6 stable/15-n283646
|
||||
releng/15.0/ b89f48ade920 releng/15.0-n281046
|
||||
stable/14/ f15df0adbcd2 stable/14-n274170
|
||||
releng/14.4/ dd50cc216e4d releng/14.4-n273709
|
||||
releng/14.3/ 9cb0be8381f7 releng/14.3-n271509
|
||||
- -------------------------------------------------------------------------
|
||||
|
||||
Run the following command to see which files were modified by a
|
||||
particular commit:
|
||||
|
||||
# git show --stat <commit hash>
|
||||
|
||||
Or visit the following URL, replacing NNNNNN with the hash:
|
||||
|
||||
<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>
|
||||
|
||||
To determine the commit count in a working tree (for comparison against
|
||||
nNNNNNN in the table above), run:
|
||||
|
||||
# git rev-list --count --first-parent HEAD
|
||||
|
||||
VII. References
|
||||
|
||||
<URL:https://www.cve.org/CVERecord?id=CVE-2026-45255>
|
||||
|
||||
The latest revision of this advisory is available at
|
||||
<URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-26:23.bsdinstall.asc>
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAEBCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKH8bFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvTloP/0369bPHpZf0yt9C2VEk
|
||||
NyOeFq+58zQGrz+RRrXA6Vg2xNdaD3fcjpVzAoqzscuE2T7VqZkpi6cS+cbzEE40
|
||||
NXX+d7qPgd5udqJR4gL8+90KWj7yQ9Wl0tnbV8wTLE6km/Dma+MXuDJrIqUl8Tsb
|
||||
q9hXGPfeymptS2vkR1Nj3VxEhDg0CCQz3bGD1sln7Oj63amX8HkHO9MwW8zHTyGj
|
||||
pcMqEF2sN3Zz0WyyaBf5XS9G0EP0BpicDIcF1NiwYbPi0rlA/nU/zjACfao7lEJk
|
||||
/XCq/iBKQsOiicvNGhoms/ku4YLNQv/L40FSJFNm8wmUsJD4fh6ll2+5Rm88666e
|
||||
gJUcBiLEzlKFogiel4JLqXMBaAZseV6Py8B+puAYh2eFCa/3aF6w2QppMj4jIHCL
|
||||
xEC/XUoBXN+34riiOCkPuSPqmgktvw7oZOBuk5DpV6qt7kdkInZ9i4HQnR13dhlF
|
||||
vLW88oyuO+2dUn+LiLaHi6f7gxkHcgyOOa/N60D95E9+d6Aop9otyMxNRFbSiQ7I
|
||||
x13B4j9ONtdAwL0uYJ+HPNHIfGTBHtpFzt62JfKdWqbSa5oVQrU5aq6wfMjMVupI
|
||||
sYCq+XNTN0MVr4iHowDPqwuEi0+RBoPOQPIXFZRfJr4uTdeim5dzX6fjfe95KIps
|
||||
3nJWEVEXVF/FiFWL3C+Lk3Cv
|
||||
=Y3q0
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,160 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
=============================================================================
|
||||
FreeBSD-SA-26:24.cap_net Security Advisory
|
||||
The FreeBSD Project
|
||||
|
||||
Topic: Incorrect libcap_net limitation list manipulation
|
||||
|
||||
Category: core
|
||||
Module: libcap_net
|
||||
Announced: 2026-05-20
|
||||
Credits: Joshua Rogers of AISLE Research Team
|
||||
Affects: All supported versions of FreeBSD.
|
||||
Corrected: 2026-05-19 23:03:59 UTC (stable/15, 15.0-STABLE)
|
||||
2026-05-20 19:39:38 UTC (releng/15.0, 15.0-RELEASE-p9)
|
||||
2026-05-19 23:04:13 UTC (stable/14, 14.4-STABLE)
|
||||
2026-05-20 19:40:03 UTC (releng/14.4, 14.4-RELEASE-p5)
|
||||
2026-05-20 19:40:41 UTC (releng/14.3, 14.3-RELEASE-p14)
|
||||
CVE Name: CVE-2026-45254
|
||||
|
||||
For general information regarding FreeBSD Security Advisories,
|
||||
including descriptions of the fields above, security branches, and the
|
||||
following sections, please visit <URL:https://security.FreeBSD.org/>.
|
||||
|
||||
I. Background
|
||||
|
||||
libcasper(3) allows Capsicum-sandboxed applications to define and use system
|
||||
interfaces which are otherwise not available in a capability sandbox, through
|
||||
implementing special services. One of these services, libcap_net, enables
|
||||
networking capabilities within the restricted environment.
|
||||
|
||||
Casper services allow the application to define fine-grained limits on each
|
||||
operation handled by the service. Each service maintains a specific list of
|
||||
permitted operations. Certain operations can be further restricted by
|
||||
specifying an explicit list of allowed names. For example, libcap_net allows
|
||||
the application to limit the addresses to which the application may bind or
|
||||
connect. If it attempts to use libcap_net to bind or connect to addresses
|
||||
outside the allowed list, the operation will fail.
|
||||
|
||||
In keeping with Capsicum's capability model, once a set of limits is applied,
|
||||
subsequent adjustments may only narrow the set of permitted operations to a
|
||||
subset of the current one.
|
||||
|
||||
II. Problem Description
|
||||
|
||||
In the case of the cap_net service, when a key present in the old limit was
|
||||
omitted from the new limit, the missing key was treated as "allow any"
|
||||
instead of being rejected.
|
||||
|
||||
III. Impact
|
||||
|
||||
In certain scenarios, an application that had previously restricted a subset
|
||||
of network operations could ask for a new limit that extended the permissions
|
||||
of the process.
|
||||
|
||||
IV. Workaround
|
||||
|
||||
No workaround is available. Note that no FreeBSD base system software is
|
||||
affected by this issue.
|
||||
|
||||
V. Solution
|
||||
|
||||
Upgrade your vulnerable system to a supported FreeBSD stable or
|
||||
release / security branch (releng) dated after the correction date.
|
||||
|
||||
Perform one of the following:
|
||||
|
||||
1) To update your vulnerable system installed from base system packages:
|
||||
|
||||
Systems running a 15.0-RELEASE version of FreeBSD on the amd64 or arm64
|
||||
platforms, which were installed using base system packages, can be updated
|
||||
via the pkg(8) utility:
|
||||
|
||||
# pkg upgrade -r FreeBSD-base
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
2) To update your vulnerable system installed from binary distribution sets:
|
||||
|
||||
Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms
|
||||
which were not installed using base system packages can be updated via the
|
||||
freebsd-update(8) utility:
|
||||
|
||||
# freebsd-update fetch
|
||||
# freebsd-update install
|
||||
# shutdown -r +10min "Rebooting for a security update"
|
||||
|
||||
3) To update your vulnerable system via a source code patch:
|
||||
|
||||
The following patches have been verified to apply to the applicable
|
||||
FreeBSD release branches.
|
||||
|
||||
a) Download the relevant patch from the location below, and verify the
|
||||
detached PGP signature using your PGP utility.
|
||||
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:24/cap_net.patch
|
||||
# fetch https://security.FreeBSD.org/patches/SA-26:24/cap_net.patch.asc
|
||||
# gpg --verify cap_net.patch.asc
|
||||
|
||||
b) Apply the patch. Execute the following commands as root:
|
||||
|
||||
# cd /usr/src
|
||||
# patch < /path/to/patch
|
||||
|
||||
c) Recompile the operating system using buildworld and installworld as
|
||||
described in <URL:https://www.FreeBSD.org/handbook/makeworld.html>.
|
||||
|
||||
Restart all daemons that use the library, or reboot the system.
|
||||
|
||||
VI. Correction details
|
||||
|
||||
This issue is corrected as of the corresponding Git commit hash in the
|
||||
following stable and release branches:
|
||||
|
||||
Branch/path Hash Revision
|
||||
- -------------------------------------------------------------------------
|
||||
stable/15/ 7eb3fd691d64 stable/15-n283630
|
||||
releng/15.0/ f69df16fcc20 releng/15.0-n281047
|
||||
stable/14/ b79faca1c596 stable/14-n274156
|
||||
releng/14.4/ f977328c7277 releng/14.4-n273710
|
||||
releng/14.3/ b3baecf08405 releng/14.3-n271510
|
||||
- -------------------------------------------------------------------------
|
||||
|
||||
Run the following command to see which files were modified by a
|
||||
particular commit:
|
||||
|
||||
# git show --stat <commit hash>
|
||||
|
||||
Or visit the following URL, replacing NNNNNN with the hash:
|
||||
|
||||
<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>
|
||||
|
||||
To determine the commit count in a working tree (for comparison against
|
||||
nNNNNNN in the table above), run:
|
||||
|
||||
# git rev-list --count --first-parent HEAD
|
||||
|
||||
VII. References
|
||||
|
||||
<URL:https://www.cve.org/CVERecord?id=CVE-2026-45254>
|
||||
|
||||
The latest revision of this advisory is available at
|
||||
<URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-26:24.cap_net.asc>
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAEBCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKIMbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvCBgQANie9vi7Gg5seuAZqAjF
|
||||
JozB+Gs6qaHzHu1CcsDSjbm3Sx5l7p5vbdTR/qsdj9WJbORSI7l5CgB175s8Dbcn
|
||||
PrBYNHCa/+lQEMjRkxGrQF9+qr0W48jrARBgauqqzrYTXHAtLGG1e4S6s83w0IJP
|
||||
wZ/3zoEOb7dzcfvxOXSSa+BGcIirmzctg886IH1+EvQKluARzAMxFhNTMwbMMRe7
|
||||
k0duMSU7KIlh2C23aMLUPlj1Su52gbiSMz3fDgl4i1cbo3xnQPQNWZnnlu8u+ZCB
|
||||
2pXQoNag7AHTzaOMvOtIyYKXfR9OLdPa4Ii6D38s6WTUb5q0GmS6G7ISYOAnTM+3
|
||||
TEvH2uhOpq8bySWb6TEx1ppedyIwZ+awocQ9XUeDvarJGCCTlBQ3kV08TMKKZxPA
|
||||
/DOWHJ9KSgKku9sKaLpbTNacpDmkipIEgKZdicifA9KpvH7frBlvwVsTzERVm/qy
|
||||
SVySVCqSE5fpYo6FN3Mo0GfN3EnBU2aYpPRx3RHvzKHTbQSU7iaNOu+Iki6GJuiH
|
||||
HTQ6oaWHmNAkotNN5tAdmDXrm9wnMncCbMT1JHrtEDanJWgKWEovhK1mw6LhHlg1
|
||||
K+bvyTB6LyZYnOZXhb9540tXfyrmjdTzM/jNMZL1Z5AYjy1FfDdTxH460gIsy6PU
|
||||
f4TRsebl2L+EThYrx6pjoj5D
|
||||
=K5/f
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,11 @@
|
||||
--- usr.sbin/freebsd-update/freebsd-update.sh.orig
|
||||
+++ usr.sbin/freebsd-update/freebsd-update.sh
|
||||
@@ -2576,7 +2576,7 @@
|
||||
|
||||
# Some files need special treatment.
|
||||
case ${F} in
|
||||
- /etc/spwd.db | /etc/pwd.db | /etc/login.conf.db)
|
||||
+ /etc/spwd.db | /etc/pwd.db | /etc/login.conf.db | /etc/ssl/cert.pem)
|
||||
# Don't merge these -- we're rebuild them
|
||||
# after updates are installed.
|
||||
cp merge/old/${F} merge/new/${F}
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKGkbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvFPUP/RdMliKc4ZoFZcXJtLCH
|
||||
fUAAsi+ypPYpy+/8dJs8QGmkUD/ypzcZCHp6drAV6dnjkJL9J3HexUnFPnMAErOV
|
||||
yQYqyL8bZfxhbbvlYEPT8eFmpARdMMT648lUmtiR8Eoh/YcX1hjsVRDmMNMdq9hn
|
||||
XCwffFhvgtjxvaVePJn8K6WnN+Yze4JxO5qSFxcAPP9MlKID0Y+BMlXnXfaJn+c/
|
||||
F/GCjJLObn0N58BKwB5gyOAGZVP8HyUvOB+LSL/Sw6c+OcOCPnMT6BQeN2dzlPlo
|
||||
Pw3ccZu81ZNOmYIR+f3TTSCngTGgmKQafvO7TQUdKbpaDMtwL6VeZqarlAgascNb
|
||||
UccstnGYZ4RnlCsjdh7+vv4CgGVQzDrvVPiQFxYHZpzyc1sXht8Ecl4iImepsBmN
|
||||
O7k0SlDGoBJ+0GLJDIDa5FMTPUuroyLYTrBDu0MRvLrhrfYrOlnakFkNb/8V0uYC
|
||||
7PmBtc78u/KDtvzvBwYy8ycufkweRsMuNqCDSXI7LvS304iOCLfv/U0F+HWDJ/e2
|
||||
bFtiK8pcmXE44YP0xmU0YBPadQSOO4yrJV5WDuH8dTzZNE752oeGtlSjKpR1zwsC
|
||||
ahT6tGsCdCy2+v6Oy/5ekGD7EofIZ9/z33rr9xGwtWuuYPtX3nnY4Q1Z3p5DOWJ9
|
||||
4IetBflMI9TI84oAcIB5WCTe
|
||||
=Zmj1
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,15 @@
|
||||
--- sys/kern/kern_prot.c.orig
|
||||
+++ sys/kern/kern_prot.c
|
||||
@@ -527,10 +527,10 @@
|
||||
*/
|
||||
*groups = wcred->sc_supp_groups_nb < CRED_SMALLGROUPS_NB ?
|
||||
smallgroups : malloc((wcred->sc_supp_groups_nb + 1) *
|
||||
- sizeof(*groups), M_TEMP, M_WAITOK);
|
||||
+ sizeof(gid_t), M_TEMP, M_WAITOK);
|
||||
|
||||
error = copyin(wcred->sc_supp_groups, *groups + 1,
|
||||
- wcred->sc_supp_groups_nb * sizeof(*groups));
|
||||
+ wcred->sc_supp_groups_nb * sizeof(gid_t));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
wcred->sc_supp_groups = *groups + 1;
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKGwbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvyUAQAOW9vodMeIny/sYwja/h
|
||||
i5tiMAYzjX6fT81v8VRRMBu32VRwCp9Y93nhuDlCmrEOr0BUw1makjSX1LKTXU1U
|
||||
9Qe22KInT51Ri79z2Q4R8IynYSXACqvBcFXOtrtybbC2Vi41wJKUz7DUXZrVS4+N
|
||||
5uBqJ/jYI3/Yxf04vragPa8Zv6ZdXlmkwcMia5HvFgITKT7FfItHxJC9df3UHj5a
|
||||
Hi1BA+vQgmJKd8a19rwSJtquMLh1tKDL8M1FQ4fkXi0uKvnSuEy5B4JBm9TbyNnl
|
||||
yP/22eVLVNmEuTiS5uhsuOchtKv/hBHYLarcciBlta6Foiw7YyqiXUgX2NwhNSUa
|
||||
lSJR8b87Zrt79JhbyC2tfJ1KUHHVWEalOKgjgg40Zrbqs1AfAD8iNzfGo4hWSM3X
|
||||
6o7CuVYsu4KmMVWP4qCYrjkdyHt++Cs3c9a+s2gLdP3egZAjnuuOtD9Pg6P8ZzZw
|
||||
PeOI4MyGjKN2EDTa5/X6jKCl79ygU2vkhhbcvhBu53T8UUyLp7RmCw173y/bjm9K
|
||||
nbN7pVtcLj8nUKKqzxZv5ZiRdZcoj7J/EWhvUb9Uz7EYqc9Qx1VEAl2bWUBGttBS
|
||||
ReQkMQiC2ilfNowLKvSlnporTH30UW5JlaBzkMG1go2CBVQNEV3umX4nXTQiYlSp
|
||||
qKQvsqfNgxBdCTDq6FsNCu65
|
||||
=BocE
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,15 @@
|
||||
--- sys/kern/kern_prot.c.orig
|
||||
+++ sys/kern/kern_prot.c
|
||||
@@ -554,10 +554,10 @@
|
||||
*/
|
||||
*groups = wcred->sc_supp_groups_nb <= CRED_SMALLGROUPS_NB ?
|
||||
smallgroups : malloc(wcred->sc_supp_groups_nb *
|
||||
- sizeof(*groups), M_TEMP, M_WAITOK);
|
||||
+ sizeof(gid_t), M_TEMP, M_WAITOK);
|
||||
|
||||
error = copyin(wcred->sc_supp_groups, *groups,
|
||||
- wcred->sc_supp_groups_nb * sizeof(*groups));
|
||||
+ wcred->sc_supp_groups_nb * sizeof(gid_t));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
wcred->sc_supp_groups = *groups;
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKG0bFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvIiQQAOUHGIICFi6oBcTzbnl3
|
||||
yFA/Gm3j9S2zjHcfN3TSOTbuuBNxx2sy7JLdDsG45VRGVdK1sS3gtQv65mey4rXD
|
||||
U5tTbkIJaGnPYFfwoYBppFGcQtjhzgqt2YWatkOr28GPv5EKRY0NfPwqObaiMJy/
|
||||
L2StoZFwlFGe104dNmqLyDZ5/lDEWAXZgCaZRElk7odOT7wjnZJEcJKqIw1FDrXP
|
||||
FrrZPZBbt4hha0KdyFY2A/ddM6Mnve14LoLW10nCFOpQH1+DMORSMoGdXuoFDWDX
|
||||
K4nL5scWSbJnkQY5PBmJo6kN2mGMkMLCwpYbAyr6WXeS8WDF9bE8/I6C4EFa4JsG
|
||||
D4aynWbE6VpJ35thyKd4p4+YI7VXuLtYVKdlJE0GGNV92qBb2pwCAtjVqfAogDMj
|
||||
B1DuG+fcUPEtNS/aBn1A1BdM7UPTNDrp5X6L35e5MqVBU8ScWCgi0zQiscY3LvmR
|
||||
BigmHWVeUcStLM+cCSAedhwKhXvJkpsoRVqzvLkIba+mL77YJh10s8zTzPWrlFV0
|
||||
k3G3U5yw/vhRIvkhoe6V5k4aw0lcNY4DDWai8xTjgd4T8hM+k7syjw8Q3uHBESyv
|
||||
dag0q/OHLrSA/DLUhOjnHtfDaKjNAsfkW1QJINbGaZbbWrL8WB4jUZ1Lu7SPNHxj
|
||||
It9S1CwDOvNRusx0xDnkUQUU
|
||||
=i9RG
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,203 @@
|
||||
--- sys/dev/netmap/netmap_freebsd.c.orig
|
||||
+++ sys/dev/netmap/netmap_freebsd.c
|
||||
@@ -119,6 +119,7 @@
|
||||
taskqueue_drain(si->ntfytq, &si->ntfytask);
|
||||
taskqueue_free(si->ntfytq);
|
||||
si->ntfytq = NULL;
|
||||
+ seldrain(&si->si);
|
||||
knlist_delete(&si->si.si_note, curthread, /*islocked=*/0);
|
||||
knlist_destroy(&si->si.si_note);
|
||||
/* now we don't need the mutex anymore */
|
||||
--- sys/kern/sys_procdesc.c.orig
|
||||
+++ sys/kern/sys_procdesc.c
|
||||
@@ -273,6 +273,7 @@
|
||||
KASSERT((pd->pd_flags & PDF_CLOSED),
|
||||
("procdesc_free: !PDF_CLOSED"));
|
||||
|
||||
+ seldrain(&pd->pd_selinfo);
|
||||
knlist_destroy(&pd->pd_selinfo.si_note);
|
||||
PROCDESC_LOCK_DESTROY(pd);
|
||||
free(pd, M_PROCDESC);
|
||||
@@ -315,10 +316,7 @@
|
||||
procdesc_free(pd);
|
||||
return (1);
|
||||
}
|
||||
- if (pd->pd_flags & PDF_SELECTED) {
|
||||
- pd->pd_flags &= ~PDF_SELECTED;
|
||||
- selwakeup(&pd->pd_selinfo);
|
||||
- }
|
||||
+ selwakeup(&pd->pd_selinfo);
|
||||
KNOTE_LOCKED(&pd->pd_selinfo.si_note, NOTE_EXIT);
|
||||
PROCDESC_UNLOCK(pd);
|
||||
return (0);
|
||||
@@ -433,10 +431,8 @@
|
||||
PROCDESC_LOCK(pd);
|
||||
if (pd->pd_flags & PDF_EXITED)
|
||||
revents |= POLLHUP;
|
||||
- if (revents == 0) {
|
||||
+ else
|
||||
selrecord(td, &pd->pd_selinfo);
|
||||
- pd->pd_flags |= PDF_SELECTED;
|
||||
- }
|
||||
PROCDESC_UNLOCK(pd);
|
||||
return (revents);
|
||||
}
|
||||
--- sys/sys/procdesc.h.orig
|
||||
+++ sys/sys/procdesc.h
|
||||
@@ -86,7 +86,6 @@
|
||||
* Flags for the pd_flags field.
|
||||
*/
|
||||
#define PDF_CLOSED 0x00000001 /* Descriptor has closed. */
|
||||
-#define PDF_SELECTED 0x00000002 /* Issue selwakeup(). */
|
||||
#define PDF_EXITED 0x00000004 /* Process exited. */
|
||||
#define PDF_DAEMON 0x00000008 /* Don't exit when procdesc closes. */
|
||||
|
||||
--- tests/sys/kern/Makefile.orig
|
||||
+++ tests/sys/kern/Makefile
|
||||
@@ -27,6 +27,7 @@
|
||||
.endif
|
||||
ATF_TESTS_C+= ktrace_test
|
||||
ATF_TESTS_C+= module_test
|
||||
+ATF_TESTS_C+= procdesc
|
||||
ATF_TESTS_C+= ptrace_test
|
||||
TEST_METADATA.ptrace_test+= timeout="15"
|
||||
ATF_TESTS_C+= reaper
|
||||
@@ -85,6 +86,7 @@
|
||||
LIBADD.kcov+= pthread
|
||||
CFLAGS.ktls_test+= -DOPENSSL_API_COMPAT=0x10100000L
|
||||
LIBADD.ktls_test+= crypto util
|
||||
+LIBADD.procdesc+= pthread
|
||||
LIBADD.socket_msg_waitall+= pthread
|
||||
LIBADD.socket_splice+= pthread
|
||||
LIBADD.sendfile_helper+= pthread
|
||||
--- /dev/null
|
||||
+++ tests/sys/kern/procdesc.c
|
||||
@@ -0,0 +1,128 @@
|
||||
+/*-
|
||||
+ * SPDX-License-Identifier: BSD-2-Clause
|
||||
+ *
|
||||
+ * Copyright (c) 2026 ConnectWise
|
||||
+ * Copyright (c) 2026 Mark Johnston <markj@FreeBSD.org>
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions
|
||||
+ * are met:
|
||||
+ * 1. Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ * 2. Redistributions in binary form must reproduce the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer in the
|
||||
+ * documentation and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
+ * SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+#include <sys/types.h>
|
||||
+#include <sys/user.h>
|
||||
+#include <sys/proc.h>
|
||||
+#include <sys/procdesc.h>
|
||||
+#include <sys/sysctl.h>
|
||||
+#include <sys/wait.h>
|
||||
+
|
||||
+#include <poll.h>
|
||||
+#include <pthread.h>
|
||||
+#include <stdio.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+#include <atf-c.h>
|
||||
+
|
||||
+/* Tests for procdesc(4) that aren't specific to any one syscall */
|
||||
+
|
||||
+static void *
|
||||
+poll_procdesc(void *arg)
|
||||
+{
|
||||
+ struct pollfd pfd;
|
||||
+
|
||||
+ pfd.fd = *(int *)arg;
|
||||
+ pfd.events = POLLHUP;
|
||||
+ (void)poll(&pfd, 1, 5000);
|
||||
+ return ((void *)(uintptr_t)pfd.revents);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Regression test to exercise the case where a procdesc is closed while a
|
||||
+ * thread is poll()ing it.
|
||||
+ */
|
||||
+ATF_TC_WITHOUT_HEAD(poll_close_race);
|
||||
+ATF_TC_BODY(poll_close_race, tc)
|
||||
+{
|
||||
+ pthread_t thr;
|
||||
+ pid_t pid;
|
||||
+ uintptr_t revents;
|
||||
+ int error, pd;
|
||||
+
|
||||
+ pid = pdfork(&pd, PD_DAEMON);
|
||||
+ ATF_REQUIRE_MSG(pid >= 0, "pdfork: %s", strerror(errno));
|
||||
+ if (pid == 0) {
|
||||
+ pause();
|
||||
+ _exit(0);
|
||||
+ }
|
||||
+
|
||||
+ error = pthread_create(&thr, NULL, poll_procdesc, &pd);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_create: %s", strerror(error));
|
||||
+
|
||||
+ /* Wait for the thread to block in poll(2). */
|
||||
+ usleep(250000);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(close(pd) == 0, "close: %s", strerror(errno));
|
||||
+
|
||||
+ error = pthread_join(thr, (void *)&revents);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_join: %s", strerror(error));
|
||||
+ ATF_REQUIRE_EQ(revents, POLLNVAL);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Verify that poll(2) of a procdesc returns POLLHUP when the process exits.
|
||||
+ */
|
||||
+ATF_TC_WITHOUT_HEAD(poll_exit_wakeup);
|
||||
+ATF_TC_BODY(poll_exit_wakeup, tc)
|
||||
+{
|
||||
+ pthread_t thr;
|
||||
+ uintptr_t revents;
|
||||
+ pid_t pid;
|
||||
+ int error, pd;
|
||||
+
|
||||
+ pid = pdfork(&pd, PD_DAEMON);
|
||||
+ ATF_REQUIRE_MSG(pid >= 0, "pdfork: %s", strerror(errno));
|
||||
+ if (pid == 0) {
|
||||
+ pause();
|
||||
+ _exit(0);
|
||||
+ }
|
||||
+
|
||||
+ error = pthread_create(&thr, NULL, poll_procdesc, &pd);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_create: %s", strerror(error));
|
||||
+
|
||||
+ /* Wait for the thread to block in poll(2). */
|
||||
+ usleep(250000);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(pdkill(pd, SIGKILL) == 0,
|
||||
+ "pdkill: %s", strerror(errno));
|
||||
+
|
||||
+ error = pthread_join(thr, (void *)&revents);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_join: %s", strerror(error));
|
||||
+ ATF_REQUIRE_EQ(revents, POLLHUP);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(close(pd) == 0, "close: %s", strerror(errno));
|
||||
+}
|
||||
+
|
||||
+ATF_TP_ADD_TCS(tp)
|
||||
+{
|
||||
+ ATF_TP_ADD_TC(tp, poll_close_race);
|
||||
+ ATF_TP_ADD_TC(tp, poll_exit_wakeup);
|
||||
+
|
||||
+ return (atf_no_error());
|
||||
+}
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKG8bFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvNpoP/jb1grG0Pi0UGPNjwt/V
|
||||
nrNT+blyuF/QgBj59Qs8ukTjZ9pkPCYtRFGPRvE046gLGgZxtRflqSchT7MHFi11
|
||||
EOe1QX74PFqHYNuTlBndaidapx3J6TOe+KbrriG7yWsaYbjpI7iiu+ebsU4arU8L
|
||||
60N/EAiES6Eu8T7uQysOWXNbI0Tp0zehwK/W7Z9H2iiGtggU25MFMgcdFj+onwH+
|
||||
qKznW5/2xHiv3/P4k83RMkbSKb0oLAvUvTIGuMSTaLtr1sGkkajrKmxJiiGYZuGK
|
||||
Zfw3wEWBZdTs5QM51CAnkqQaDEwxmUsOn70onXeeiTjcpzr7aTwVqSzd6NgJ+xkv
|
||||
rr1gbfBDRgJW3Uk3/wOwAUGk4a6E3kDW3u2lc6hPD3TfTjrrBlE/XaT0Lkc//Trz
|
||||
up2ebnjRaai9fsMjhA62k2H+hNXsioAzOe/t3aAEjTcCHKqLtyJ0cGEhAmfJvxE6
|
||||
c7h6q17hxNnT6fhfqqdfZ4c+JUBA3jiio/RQVL1/x+NzJiZxjRnzct28tuN9Y8am
|
||||
BepYRa6pWSet8s7J8L5KNREmBHEgwLwqybKXCEJpjoQn9cQXTTb5M8eJkIa+V86q
|
||||
nMDZ6TONl1OHeqiH7uhB47W38+jXGWeFMSromI5+spoKLax3m5zlJwkULMJJi8Vk
|
||||
UAdh/UQz3TX+Bw129dVDQES+
|
||||
=J8vU
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,467 @@
|
||||
--- sys/dev/netmap/netmap_freebsd.c.orig
|
||||
+++ sys/dev/netmap/netmap_freebsd.c
|
||||
@@ -119,6 +119,7 @@
|
||||
taskqueue_drain(si->ntfytq, &si->ntfytask);
|
||||
taskqueue_free(si->ntfytq);
|
||||
si->ntfytq = NULL;
|
||||
+ seldrain(&si->si);
|
||||
knlist_delete(&si->si.si_note, curthread, /*islocked=*/0);
|
||||
knlist_destroy(&si->si.si_note);
|
||||
/* now we don't need the mutex anymore */
|
||||
--- sys/kern/kern_jaildesc.c.orig
|
||||
+++ sys/kern/kern_jaildesc.c
|
||||
@@ -197,10 +197,7 @@
|
||||
JAILDESC_LOCK(jd);
|
||||
if (hint == NOTE_JAIL_REMOVE) {
|
||||
jd->jd_flags |= JDF_REMOVED;
|
||||
- if (jd->jd_flags & JDF_SELECTED) {
|
||||
- jd->jd_flags &= ~JDF_SELECTED;
|
||||
- selwakeup(&jd->jd_selinfo);
|
||||
- }
|
||||
+ selwakeup(&jd->jd_selinfo);
|
||||
}
|
||||
KNOTE_LOCKED(&jd->jd_selinfo.si_note, hint);
|
||||
JAILDESC_UNLOCK(jd);
|
||||
@@ -257,6 +254,7 @@
|
||||
}
|
||||
prison_free(pr);
|
||||
}
|
||||
+ seldrain(&jd->jd_selinfo);
|
||||
knlist_destroy(&jd->jd_selinfo.si_note);
|
||||
JAILDESC_LOCK_DESTROY(jd);
|
||||
free(jd, M_JAILDESC);
|
||||
@@ -276,10 +274,8 @@
|
||||
JAILDESC_LOCK(jd);
|
||||
if (jd->jd_flags & JDF_REMOVED)
|
||||
revents |= POLLHUP;
|
||||
- if (revents == 0) {
|
||||
+ else
|
||||
selrecord(td, &jd->jd_selinfo);
|
||||
- jd->jd_flags |= JDF_SELECTED;
|
||||
- }
|
||||
JAILDESC_UNLOCK(jd);
|
||||
return (revents);
|
||||
}
|
||||
--- sys/kern/sys_procdesc.c.orig
|
||||
+++ sys/kern/sys_procdesc.c
|
||||
@@ -270,6 +270,7 @@
|
||||
KASSERT((pd->pd_flags & PDF_CLOSED),
|
||||
("procdesc_free: !PDF_CLOSED"));
|
||||
|
||||
+ seldrain(&pd->pd_selinfo);
|
||||
knlist_destroy(&pd->pd_selinfo.si_note);
|
||||
PROCDESC_LOCK_DESTROY(pd);
|
||||
free(pd, M_PROCDESC);
|
||||
@@ -312,10 +313,7 @@
|
||||
procdesc_free(pd);
|
||||
return (1);
|
||||
}
|
||||
- if (pd->pd_flags & PDF_SELECTED) {
|
||||
- pd->pd_flags &= ~PDF_SELECTED;
|
||||
- selwakeup(&pd->pd_selinfo);
|
||||
- }
|
||||
+ selwakeup(&pd->pd_selinfo);
|
||||
KNOTE_LOCKED(&pd->pd_selinfo.si_note, NOTE_EXIT);
|
||||
PROCDESC_UNLOCK(pd);
|
||||
return (0);
|
||||
@@ -430,10 +428,8 @@
|
||||
PROCDESC_LOCK(pd);
|
||||
if (pd->pd_flags & PDF_EXITED)
|
||||
revents |= POLLHUP;
|
||||
- if (revents == 0) {
|
||||
+ else
|
||||
selrecord(td, &pd->pd_selinfo);
|
||||
- pd->pd_flags |= PDF_SELECTED;
|
||||
- }
|
||||
PROCDESC_UNLOCK(pd);
|
||||
return (revents);
|
||||
}
|
||||
--- sys/sys/jaildesc.h.orig
|
||||
+++ sys/sys/jaildesc.h
|
||||
@@ -71,7 +71,6 @@
|
||||
/*
|
||||
* Flags for the jd_flags field
|
||||
*/
|
||||
-#define JDF_SELECTED 0x00000001 /* issue selwakeup() */
|
||||
#define JDF_REMOVED 0x00000002 /* jail was removed */
|
||||
#define JDF_OWNING 0x00000004 /* closing descriptor removes jail */
|
||||
|
||||
--- sys/sys/procdesc.h.orig
|
||||
+++ sys/sys/procdesc.h
|
||||
@@ -86,7 +86,6 @@
|
||||
* Flags for the pd_flags field.
|
||||
*/
|
||||
#define PDF_CLOSED 0x00000001 /* Descriptor has closed. */
|
||||
-#define PDF_SELECTED 0x00000002 /* Issue selwakeup(). */
|
||||
#define PDF_EXITED 0x00000004 /* Process exited. */
|
||||
#define PDF_DAEMON 0x00000008 /* Don't exit when procdesc closes. */
|
||||
|
||||
--- tests/sys/kern/Makefile.orig
|
||||
+++ tests/sys/kern/Makefile
|
||||
@@ -22,6 +22,7 @@
|
||||
ATF_TESTS_C+= fdgrowtable_test
|
||||
ATF_TESTS_C+= getdirentries_test
|
||||
ATF_TESTS_C+= jail_lookup_root
|
||||
+ATF_TESTS_C+= jaildesc
|
||||
ATF_TESTS_C+= inotify_test
|
||||
ATF_TESTS_C+= kill_zombie
|
||||
.if ${MK_OPENSSL} != "no"
|
||||
@@ -31,6 +32,7 @@
|
||||
ATF_TESTS_C+= listener_wakeup
|
||||
ATF_TESTS_C+= module_test
|
||||
ATF_TESTS_C+= prace
|
||||
+ATF_TESTS_C+= procdesc
|
||||
ATF_TESTS_C+= ptrace_test
|
||||
TEST_METADATA.ptrace_test+= timeout="15"
|
||||
ATF_TESTS_C+= reaper
|
||||
@@ -84,6 +86,7 @@
|
||||
|
||||
LIBADD.copy_file_range+= md
|
||||
LIBADD.jail_lookup_root+= jail util
|
||||
+LIBADD.jaildesc+= pthread
|
||||
CFLAGS.sys_getrandom+= -I${SRCTOP}/sys/contrib/zstd/lib
|
||||
LIBADD.sys_getrandom+= zstd
|
||||
LIBADD.sys_getrandom+= c
|
||||
@@ -95,6 +98,7 @@
|
||||
CFLAGS.ktls_test+= -DOPENSSL_API_COMPAT=0x10100000L
|
||||
LIBADD.ktls_test+= crypto util
|
||||
LIBADD.listener_wakeup+= pthread
|
||||
+LIBADD.procdesc+= pthread
|
||||
LIBADD.shutdown_dgram+= pthread
|
||||
LIBADD.socket_msg_waitall+= pthread
|
||||
LIBADD.socket_splice+= pthread
|
||||
--- /dev/null
|
||||
+++ tests/sys/kern/jaildesc.c
|
||||
@@ -0,0 +1,201 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2026 Mark Johnston <markj@FreeBSD.org>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: BSD-2-Clause
|
||||
+ */
|
||||
+
|
||||
+#include <sys/param.h>
|
||||
+#include <sys/jail.h>
|
||||
+#include <sys/uio.h>
|
||||
+
|
||||
+#include <atf-c.h>
|
||||
+#include <errno.h>
|
||||
+#include <poll.h>
|
||||
+#include <pthread.h>
|
||||
+#include <pwd.h>
|
||||
+#include <string.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/*
|
||||
+ * Create a persistent jail and return an owning descriptor for it.
|
||||
+ * The jail is removed when the returned descriptor is closed.
|
||||
+ */
|
||||
+static int
|
||||
+create_jail(const char *name)
|
||||
+{
|
||||
+ struct iovec iov[8];
|
||||
+ int desc, jid, n;
|
||||
+
|
||||
+ desc = -1;
|
||||
+ n = 0;
|
||||
+ iov[n].iov_base = __DECONST(void *, "name");
|
||||
+ iov[n++].iov_len = strlen("name") + 1;
|
||||
+ iov[n].iov_base = __DECONST(void *, name);
|
||||
+ iov[n++].iov_len = strlen(name) + 1;
|
||||
+ iov[n].iov_base = __DECONST(void *, "path");
|
||||
+ iov[n++].iov_len = strlen("path") + 1;
|
||||
+ iov[n].iov_base = __DECONST(void *, "/");
|
||||
+ iov[n++].iov_len = strlen("/") + 1;
|
||||
+ iov[n].iov_base = __DECONST(void *, "persist");
|
||||
+ iov[n++].iov_len = strlen("persist") + 1;
|
||||
+ iov[n].iov_base = NULL;
|
||||
+ iov[n++].iov_len = 0;
|
||||
+ iov[n].iov_base = __DECONST(void *, "desc");
|
||||
+ iov[n++].iov_len = strlen("desc") + 1;
|
||||
+ iov[n].iov_base = &desc;
|
||||
+ iov[n++].iov_len = sizeof(desc);
|
||||
+ jid = jail_set(iov, n, JAIL_CREATE | JAIL_OWN_DESC);
|
||||
+ ATF_REQUIRE_MSG(jid >= 0, "jail_set: %s", strerror(errno));
|
||||
+ return (desc);
|
||||
+}
|
||||
+
|
||||
+static void *
|
||||
+poll_jaildesc(void *arg)
|
||||
+{
|
||||
+ struct pollfd pfd;
|
||||
+
|
||||
+ pfd.fd = *(int *)arg;
|
||||
+ pfd.events = POLLHUP;
|
||||
+ (void)poll(&pfd, 1, 5000);
|
||||
+ return ((void *)(uintptr_t)pfd.revents);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Regression test for the case where a jail descriptor is closed while a
|
||||
+ * thread is blocking in poll(2) on it.
|
||||
+ */
|
||||
+ATF_TC(poll_close_race);
|
||||
+ATF_TC_HEAD(poll_close_race, tc)
|
||||
+{
|
||||
+ atf_tc_set_md_var(tc, "require.user", "root");
|
||||
+}
|
||||
+ATF_TC_BODY(poll_close_race, tc)
|
||||
+{
|
||||
+ pthread_t thr;
|
||||
+ uintptr_t revents;
|
||||
+ int error, jd;
|
||||
+
|
||||
+ jd = create_jail("jaildesc_poll_close_race");
|
||||
+
|
||||
+ error = pthread_create(&thr, NULL, poll_jaildesc, &jd);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_create: %s", strerror(error));
|
||||
+
|
||||
+ /* Wait for the thread to block in poll(2). */
|
||||
+ usleep(250000);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(close(jd) == 0, "close: %s", strerror(errno));
|
||||
+
|
||||
+ error = pthread_join(thr, (void *)&revents);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_join: %s", strerror(error));
|
||||
+ ATF_REQUIRE_EQ(revents, POLLNVAL);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Verify that poll(2) of a jail descriptor returns POLLHUP when the jail
|
||||
+ * is removed.
|
||||
+ */
|
||||
+ATF_TC(poll_remove_wakeup);
|
||||
+ATF_TC_HEAD(poll_remove_wakeup, tc)
|
||||
+{
|
||||
+ atf_tc_set_md_var(tc, "require.user", "root");
|
||||
+}
|
||||
+ATF_TC_BODY(poll_remove_wakeup, tc)
|
||||
+{
|
||||
+ pthread_t thr;
|
||||
+ uintptr_t revents;
|
||||
+ int error, jd;
|
||||
+
|
||||
+ jd = create_jail("jaildesc_poll_remove_wakeup");
|
||||
+
|
||||
+ error = pthread_create(&thr, NULL, poll_jaildesc, &jd);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_create: %s", strerror(error));
|
||||
+
|
||||
+ /* Wait for the thread to block in poll(2). */
|
||||
+ usleep(250000);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(jail_remove_jd(jd) == 0,
|
||||
+ "jail_remove_jd: %s", strerror(errno));
|
||||
+
|
||||
+ error = pthread_join(thr, (void *)&revents);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_join: %s", strerror(error));
|
||||
+ ATF_REQUIRE_EQ(revents, POLLHUP);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(close(jd) == 0, "close: %s", strerror(errno));
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+get_jaildesc(const char *name)
|
||||
+{
|
||||
+ struct iovec iov[4];
|
||||
+ char namebuf[MAXHOSTNAMELEN];
|
||||
+ int desc, jid, n;
|
||||
+
|
||||
+ strlcpy(namebuf, name, sizeof(namebuf));
|
||||
+ desc = -1;
|
||||
+ n = 0;
|
||||
+ iov[n].iov_base = __DECONST(void *, "name");
|
||||
+ iov[n++].iov_len = strlen("name") + 1;
|
||||
+ iov[n].iov_base = namebuf;
|
||||
+ iov[n++].iov_len = sizeof(namebuf);
|
||||
+ iov[n].iov_base = __DECONST(void *, "desc");
|
||||
+ iov[n++].iov_len = strlen("desc") + 1;
|
||||
+ iov[n].iov_base = &desc;
|
||||
+ iov[n++].iov_len = sizeof(desc);
|
||||
+ jid = jail_get(iov, n, JAIL_GET_DESC);
|
||||
+ ATF_REQUIRE_MSG(jid >= 0, "jail_get: %s", strerror(errno));
|
||||
+ return (desc);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Regression test for the same use-after-free as poll_close_race, but with a
|
||||
+ * non-owning JAIL_GET_DESC descriptor obtained without root privileges.
|
||||
+ */
|
||||
+ATF_TC(poll_close_race_get_desc);
|
||||
+ATF_TC_HEAD(poll_close_race_get_desc, tc)
|
||||
+{
|
||||
+ atf_tc_set_md_var(tc, "require.user", "root");
|
||||
+}
|
||||
+ATF_TC_BODY(poll_close_race_get_desc, tc)
|
||||
+{
|
||||
+ struct passwd *pw;
|
||||
+ pthread_t thr;
|
||||
+ uintptr_t revents;
|
||||
+ int error, jd, owning_jd;
|
||||
+
|
||||
+ /* Create the jail as root; keep the owning descriptor for cleanup. */
|
||||
+ owning_jd = create_jail("jaildesc_poll_close_get_desc");
|
||||
+
|
||||
+ /*
|
||||
+ * Drop root privileges. jail_get(2) with JAIL_GET_DESC does not
|
||||
+ * require PRIV_JAIL_REMOVE, so a non-root process in the host prison
|
||||
+ * can obtain a read-only descriptor for any visible jail.
|
||||
+ */
|
||||
+ pw = getpwnam("nobody");
|
||||
+ ATF_REQUIRE_MSG(pw != NULL, "getpwnam: %s", strerror(errno));
|
||||
+ ATF_REQUIRE_MSG(setuid(pw->pw_uid) == 0, "setuid: %s", strerror(errno));
|
||||
+
|
||||
+ jd = get_jaildesc("jaildesc_poll_close_get_desc");
|
||||
+
|
||||
+ error = pthread_create(&thr, NULL, poll_jaildesc, &jd);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_create: %s", strerror(error));
|
||||
+
|
||||
+ /* Wait for the thread to block in poll(2). */
|
||||
+ usleep(250000);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(close(jd) == 0, "close: %s", strerror(errno));
|
||||
+
|
||||
+ error = pthread_join(thr, (void *)&revents);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_join: %s", strerror(error));
|
||||
+ ATF_REQUIRE_EQ(revents, POLLNVAL);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(close(owning_jd) == 0, "close: %s", strerror(errno));
|
||||
+}
|
||||
+
|
||||
+ATF_TP_ADD_TCS(tp)
|
||||
+{
|
||||
+ ATF_TP_ADD_TC(tp, poll_close_race);
|
||||
+ ATF_TP_ADD_TC(tp, poll_remove_wakeup);
|
||||
+ ATF_TP_ADD_TC(tp, poll_close_race_get_desc);
|
||||
+
|
||||
+ return (atf_no_error());
|
||||
+}
|
||||
--- /dev/null
|
||||
+++ tests/sys/kern/procdesc.c
|
||||
@@ -0,0 +1,128 @@
|
||||
+/*-
|
||||
+ * SPDX-License-Identifier: BSD-2-Clause
|
||||
+ *
|
||||
+ * Copyright (c) 2026 ConnectWise
|
||||
+ * Copyright (c) 2026 Mark Johnston <markj@FreeBSD.org>
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions
|
||||
+ * are met:
|
||||
+ * 1. Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ * 2. Redistributions in binary form must reproduce the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer in the
|
||||
+ * documentation and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
+ * SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+#include <sys/types.h>
|
||||
+#include <sys/user.h>
|
||||
+#include <sys/proc.h>
|
||||
+#include <sys/procdesc.h>
|
||||
+#include <sys/sysctl.h>
|
||||
+#include <sys/wait.h>
|
||||
+
|
||||
+#include <poll.h>
|
||||
+#include <pthread.h>
|
||||
+#include <stdio.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+#include <atf-c.h>
|
||||
+
|
||||
+/* Tests for procdesc(4) that aren't specific to any one syscall */
|
||||
+
|
||||
+static void *
|
||||
+poll_procdesc(void *arg)
|
||||
+{
|
||||
+ struct pollfd pfd;
|
||||
+
|
||||
+ pfd.fd = *(int *)arg;
|
||||
+ pfd.events = POLLHUP;
|
||||
+ (void)poll(&pfd, 1, 5000);
|
||||
+ return ((void *)(uintptr_t)pfd.revents);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Regression test to exercise the case where a procdesc is closed while a
|
||||
+ * thread is poll()ing it.
|
||||
+ */
|
||||
+ATF_TC_WITHOUT_HEAD(poll_close_race);
|
||||
+ATF_TC_BODY(poll_close_race, tc)
|
||||
+{
|
||||
+ pthread_t thr;
|
||||
+ pid_t pid;
|
||||
+ uintptr_t revents;
|
||||
+ int error, pd;
|
||||
+
|
||||
+ pid = pdfork(&pd, PD_DAEMON);
|
||||
+ ATF_REQUIRE_MSG(pid >= 0, "pdfork: %s", strerror(errno));
|
||||
+ if (pid == 0) {
|
||||
+ pause();
|
||||
+ _exit(0);
|
||||
+ }
|
||||
+
|
||||
+ error = pthread_create(&thr, NULL, poll_procdesc, &pd);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_create: %s", strerror(error));
|
||||
+
|
||||
+ /* Wait for the thread to block in poll(2). */
|
||||
+ usleep(250000);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(close(pd) == 0, "close: %s", strerror(errno));
|
||||
+
|
||||
+ error = pthread_join(thr, (void *)&revents);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_join: %s", strerror(error));
|
||||
+ ATF_REQUIRE_EQ(revents, POLLNVAL);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Verify that poll(2) of a procdesc returns POLLHUP when the process exits.
|
||||
+ */
|
||||
+ATF_TC_WITHOUT_HEAD(poll_exit_wakeup);
|
||||
+ATF_TC_BODY(poll_exit_wakeup, tc)
|
||||
+{
|
||||
+ pthread_t thr;
|
||||
+ uintptr_t revents;
|
||||
+ pid_t pid;
|
||||
+ int error, pd;
|
||||
+
|
||||
+ pid = pdfork(&pd, PD_DAEMON);
|
||||
+ ATF_REQUIRE_MSG(pid >= 0, "pdfork: %s", strerror(errno));
|
||||
+ if (pid == 0) {
|
||||
+ pause();
|
||||
+ _exit(0);
|
||||
+ }
|
||||
+
|
||||
+ error = pthread_create(&thr, NULL, poll_procdesc, &pd);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_create: %s", strerror(error));
|
||||
+
|
||||
+ /* Wait for the thread to block in poll(2). */
|
||||
+ usleep(250000);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(pdkill(pd, SIGKILL) == 0,
|
||||
+ "pdkill: %s", strerror(errno));
|
||||
+
|
||||
+ error = pthread_join(thr, (void *)&revents);
|
||||
+ ATF_REQUIRE_MSG(error == 0, "pthread_join: %s", strerror(error));
|
||||
+ ATF_REQUIRE_EQ(revents, POLLHUP);
|
||||
+
|
||||
+ ATF_REQUIRE_MSG(close(pd) == 0, "close: %s", strerror(errno));
|
||||
+}
|
||||
+
|
||||
+ATF_TP_ADD_TCS(tp)
|
||||
+{
|
||||
+ ATF_TP_ADD_TC(tp, poll_close_race);
|
||||
+ ATF_TP_ADD_TC(tp, poll_exit_wakeup);
|
||||
+
|
||||
+ return (atf_no_error());
|
||||
+}
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKHAbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvUPwQAL4Td5qsO6YRMxxoyd9Y
|
||||
h59xkv7KCPmLOXRLgAf+Aqxof0lqVGbxOx2e9ULzyL2InRvKEsbFCMthdYyWcR0f
|
||||
CRTLqPFWq6sAAd2s1ensgTMMn89Ei7ZJoqjPFF7Cl9EBdPRvROf+8aDLD7BXhxO4
|
||||
jwoQY0b0FR/IhhP7sfMUEy3Lg2D6E68rrFV6EvKj0CQPentHY3GFSKYh6RcOmBYP
|
||||
V1xRl27vTQOfrjIoPPSKTKyVulfjPb7k2ZNsrNozEwdG541ZGddafk+V59siyBxZ
|
||||
zt7WBNPPdqSZUOrdWEfy0WS7ejzVk+EtZejNDT5IyJciZfc+2/EGHJDHD4/13UDJ
|
||||
lUC4a5cuvSm6bf8qk1lnz1ISfPxayYK3T53lU/axasIlqOdj3jFwWl+EyMDQLmfq
|
||||
lxMskYbDobbuxmRstpET9uTQB+uAu2yg2+eej/FGzdT5p+R/54dS6kdeuU2JNFXD
|
||||
KJrlll92vMCm1U9gzW5rzzUb78xXWLl4k07PHvauaqActWXZyDPOUGH7a/Ik57BG
|
||||
2kO/EzPJZvhpYbhM7Zidfot+b9X+gO4v9YsFy02XdZhRgblIlzyvtDkl2l7drlC7
|
||||
j8fzQiEEHJxnMwhj5bxpE028cRg8XszVXgAYGHeEJMqc2mbkMh5yAVgUZX10GZtc
|
||||
lJGd4WA1yrr618fLIvXGz+re
|
||||
=3h0D
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,146 @@
|
||||
--- sys/fs/fuse/fuse_ipc.h.orig
|
||||
+++ sys/fs/fuse/fuse_ipc.h
|
||||
@@ -238,6 +238,7 @@
|
||||
#define FSESS_WARN_WB_CACHE_INCOHERENT 0x400000 /* WB cache incoherent */
|
||||
#define FSESS_WARN_ILLEGAL_INODE 0x800000 /* Illegal inode for new file */
|
||||
#define FSESS_WARN_READLINK_EMBEDDED_NUL 0x1000000 /* corrupt READLINK output */
|
||||
+#define FSESS_WARN_LSEXTATTR_NUL 0x20000000 /* Non nul-terminated xattr list */
|
||||
#define FSESS_MNTOPTS_MASK ( \
|
||||
FSESS_DAEMON_CAN_SPY | FSESS_PUSH_SYMLINKS_IN | \
|
||||
FSESS_DEFAULT_PERMISSIONS | FSESS_INTR)
|
||||
--- sys/fs/fuse/fuse_vnops.c.orig
|
||||
+++ sys/fs/fuse/fuse_vnops.c
|
||||
@@ -2806,8 +2806,8 @@
|
||||
* bsd_list, bsd_list_len - output list compatible with bsd vfs
|
||||
*/
|
||||
static int
|
||||
-fuse_xattrlist_convert(char *prefix, const char *list, int list_len,
|
||||
- char *bsd_list, int *bsd_list_len)
|
||||
+fuse_xattrlist_convert(struct fuse_data *data, char *prefix, const char *list,
|
||||
+ int list_len, char *bsd_list, int *bsd_list_len)
|
||||
{
|
||||
int len, pos, dist_to_next, prefix_len;
|
||||
|
||||
@@ -2816,7 +2816,13 @@
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
while (pos < list_len && list[pos] != '\0') {
|
||||
- dist_to_next = strlen(&list[pos]) + 1;
|
||||
+ dist_to_next = strnlen(&list[pos], list_len - pos - 1) + 1;
|
||||
+ if (list[pos + dist_to_next - 1] != '\0') {
|
||||
+ fuse_warn(data, FSESS_WARN_LSEXTATTR_NUL,
|
||||
+ "The FUSE server returned a non nul-terminated "
|
||||
+ "LISTXATTR response.");
|
||||
+ return (EIO);
|
||||
+ }
|
||||
if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
|
||||
list[pos + prefix_len] == extattr_namespace_separator) {
|
||||
len = dist_to_next -
|
||||
@@ -2872,6 +2878,7 @@
|
||||
struct fuse_listxattr_in *list_xattr_in;
|
||||
struct fuse_listxattr_out *list_xattr_out;
|
||||
struct mount *mp = vnode_mount(vp);
|
||||
+ struct fuse_data *data = fuse_get_mpdata(mp);
|
||||
struct thread *td = ap->a_td;
|
||||
struct ucred *cred = ap->a_cred;
|
||||
char *prefix;
|
||||
@@ -2949,8 +2956,6 @@
|
||||
linux_list = fdi.answ;
|
||||
/* FUSE doesn't allow the server to return more data than requested */
|
||||
if (fdi.iosize > linux_list_len) {
|
||||
- struct fuse_data *data = fuse_get_mpdata(mp);
|
||||
-
|
||||
fuse_warn(data, FSESS_WARN_LSEXTATTR_LONG,
|
||||
"server returned "
|
||||
"more extended attribute data than requested; "
|
||||
@@ -2967,7 +2972,7 @@
|
||||
* FreeBSD's format before giving it to the user.
|
||||
*/
|
||||
bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
|
||||
- err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
|
||||
+ err = fuse_xattrlist_convert(data, prefix, linux_list, linux_list_len,
|
||||
bsd_list, &bsd_list_len);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
--- tests/sys/fs/fusefs/xattr.cc.orig
|
||||
+++ tests/sys/fs/fusefs/xattr.cc
|
||||
@@ -448,6 +448,79 @@
|
||||
ASSERT_TRUE(WIFSIGNALED(status));
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * A buggy or malicious server returns a list that isn't nul-terminated. The
|
||||
+ * kernel should handle it gracefully.
|
||||
+ */
|
||||
+TEST_F(Listxattr, not_nul_terminated)
|
||||
+{
|
||||
+ uint64_t ino = 42;
|
||||
+ int ns = EXTATTR_NAMESPACE_USER;
|
||||
+ char *data;
|
||||
+ const char expected[4] = {3, 'f', 'o', 'o'};
|
||||
+ const char first[255] = "user.foo\0system.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
+ const uint8_t badlist[9] = {'u', 's', 'e', 'r', '.', 'f', 'o', 'o', 'd'};
|
||||
+ Sequence seq;
|
||||
+
|
||||
+ EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
|
||||
+ .WillRepeatedly(Invoke(
|
||||
+ ReturnImmediate([=](auto in __unused, auto& out) {
|
||||
+ SET_OUT_HEADER_LEN(out, entry);
|
||||
+ out.body.entry.attr.mode = S_IFREG | 0644;
|
||||
+ out.body.entry.nodeid = ino;
|
||||
+ out.body.entry.attr.nlink = 1;
|
||||
+ out.body.entry.attr_valid = UINT64_MAX;
|
||||
+ out.body.entry.entry_valid = UINT64_MAX;
|
||||
+ })));
|
||||
+
|
||||
+ /*
|
||||
+ * On the first LISTXATTRS call, return a big attribute just to fill
|
||||
+ * the heap with non-NUL data.
|
||||
+ */
|
||||
+ expect_listxattr(ino, 0,
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ out.body.listxattr.size = sizeof(first);
|
||||
+ SET_OUT_HEADER_LEN(out, listxattr);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+ expect_listxattr(ino, sizeof(first),
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ memcpy((void*)out.body.bytes, first, sizeof(first));
|
||||
+ out.header.len = sizeof(fuse_out_header) + sizeof(first);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+ /*
|
||||
+ * On the second LISTXATTRS call, return a malformed list with no NUL
|
||||
+ * termination. The heap might still be full of the data from the
|
||||
+ * first call.
|
||||
+ */
|
||||
+ expect_listxattr(ino, 0,
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ out.body.listxattr.size = sizeof(badlist);
|
||||
+ SET_OUT_HEADER_LEN(out, listxattr);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+ expect_listxattr(ino, sizeof(badlist),
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ memset((void*)out.body.bytes, 'x', sizeof(first));
|
||||
+ memcpy((void*)out.body.bytes, badlist, sizeof(badlist));
|
||||
+ out.header.len = sizeof(fuse_out_header) + sizeof(badlist);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+
|
||||
+ data = new char[1024];
|
||||
+
|
||||
+ ASSERT_EQ(static_cast<ssize_t>(sizeof(expected)),
|
||||
+ extattr_list_file(FULLPATH, ns, data, sizeof(data)))
|
||||
+ << strerror(errno);
|
||||
+ /*
|
||||
+ * Receiving this malformed list, the kernel should log it to dmesg and
|
||||
+ * report an IO error to the caller.
|
||||
+ */
|
||||
+ ASSERT_EQ(-1, extattr_list_file(FULLPATH, ns, data, sizeof(data)));
|
||||
+ EXPECT_EQ(EIO, errno);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Get the size of the list that it would take to list no extended attributes
|
||||
*/
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKHMbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvlI0QALm6fFHg0EXsCNa/fEx6
|
||||
oSYsueeAZgVd4T+gXdQ2Qj/Ne6LImFJiRiG2m9yhIEVCZA2l54r5UP5IpGag+g0S
|
||||
h1H8JEs2VYrc/Z7+E2xD2e3bKhwyJ5DDcoHbGALkFFaVvGDibC79yqzmBHmkBdZr
|
||||
W5DBi6YuMlDqoZVMZps00qNRnUjbLWNZXafEiuNBf1suUv14hhyI/DD+SPEXWvDG
|
||||
IXXeEO5zA7IxecZSUHZak9DQL234c/gR/+tkgVKwgY+42e9AqcTIOFTDgyZFJ56V
|
||||
OgJ5BFsFWO0lFxYPmKRvUPs2DnsvEkN+L9meT5G8BxCC3QybeBRuFoi4/5mLTNAf
|
||||
gEU6Fg/XIs/cHnRxq2nfqKigdvULAEeqqUZCIZLnPLxx5DKr42PCv5ExalV+UbTW
|
||||
826x6NQ5CNM/MncBpQJwfdwVLc3gOo+jx96I1t9Fe1RMzdho0wj2/rd9gjElkAv7
|
||||
ffDtKraDy/m2559Bmu9dLYBokeeFMtLvvGgoHMAyum3QgottdLOkqquvGETM1voP
|
||||
2dWNuynDmzf+hFIVN5LgL21TaJbYFvS0MZNmYKGyu6Lqx+9KvYyDdy/T0UGWflU0
|
||||
mSbDcCflqUfxdqo50lNzaFhn9KLAA5KhO3DcggeCEVS1ylxN+d85j4qPkROF4I6E
|
||||
DEYgzjfPApOkOUqpNXFCvtye
|
||||
=Bk3h
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,146 @@
|
||||
--- sys/fs/fuse/fuse_ipc.h.orig
|
||||
+++ sys/fs/fuse/fuse_ipc.h
|
||||
@@ -240,6 +240,7 @@
|
||||
#define FSESS_WARN_READLINK_EMBEDDED_NUL 0x1000000 /* corrupt READLINK output */
|
||||
#define FSESS_WARN_DOT_LOOKUP 0x2000000 /* Inconsistent . LOOKUP response */
|
||||
#define FSESS_WARN_INODE_MISMATCH 0x4000000 /* ino != nodeid */
|
||||
+#define FSESS_WARN_LSEXTATTR_NUL 0x20000000 /* Non nul-terminated xattr list */
|
||||
#define FSESS_MNTOPTS_MASK ( \
|
||||
FSESS_DAEMON_CAN_SPY | FSESS_PUSH_SYMLINKS_IN | \
|
||||
FSESS_DEFAULT_PERMISSIONS | FSESS_INTR)
|
||||
--- sys/fs/fuse/fuse_vnops.c.orig
|
||||
+++ sys/fs/fuse/fuse_vnops.c
|
||||
@@ -2794,8 +2794,8 @@
|
||||
* bsd_list, bsd_list_len - output list compatible with bsd vfs
|
||||
*/
|
||||
static int
|
||||
-fuse_xattrlist_convert(char *prefix, const char *list, int list_len,
|
||||
- char *bsd_list, int *bsd_list_len)
|
||||
+fuse_xattrlist_convert(struct fuse_data *data, char *prefix, const char *list,
|
||||
+ int list_len, char *bsd_list, int *bsd_list_len)
|
||||
{
|
||||
int len, pos, dist_to_next, prefix_len;
|
||||
|
||||
@@ -2804,7 +2804,13 @@
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
while (pos < list_len && list[pos] != '\0') {
|
||||
- dist_to_next = strlen(&list[pos]) + 1;
|
||||
+ dist_to_next = strnlen(&list[pos], list_len - pos - 1) + 1;
|
||||
+ if (list[pos + dist_to_next - 1] != '\0') {
|
||||
+ fuse_warn(data, FSESS_WARN_LSEXTATTR_NUL,
|
||||
+ "The FUSE server returned a non nul-terminated "
|
||||
+ "LISTXATTR response.");
|
||||
+ return (EIO);
|
||||
+ }
|
||||
if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
|
||||
list[pos + prefix_len] == extattr_namespace_separator) {
|
||||
len = dist_to_next -
|
||||
@@ -2860,6 +2866,7 @@
|
||||
struct fuse_listxattr_in *list_xattr_in;
|
||||
struct fuse_listxattr_out *list_xattr_out;
|
||||
struct mount *mp = vnode_mount(vp);
|
||||
+ struct fuse_data *data = fuse_get_mpdata(mp);
|
||||
struct thread *td = ap->a_td;
|
||||
struct ucred *cred = ap->a_cred;
|
||||
char *prefix;
|
||||
@@ -2937,8 +2944,6 @@
|
||||
linux_list = fdi.answ;
|
||||
/* FUSE doesn't allow the server to return more data than requested */
|
||||
if (fdi.iosize > linux_list_len) {
|
||||
- struct fuse_data *data = fuse_get_mpdata(mp);
|
||||
-
|
||||
fuse_warn(data, FSESS_WARN_LSEXTATTR_LONG,
|
||||
"server returned "
|
||||
"more extended attribute data than requested; "
|
||||
@@ -2955,7 +2960,7 @@
|
||||
* FreeBSD's format before giving it to the user.
|
||||
*/
|
||||
bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
|
||||
- err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
|
||||
+ err = fuse_xattrlist_convert(data, prefix, linux_list, linux_list_len,
|
||||
bsd_list, &bsd_list_len);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
--- tests/sys/fs/fusefs/xattr.cc.orig
|
||||
+++ tests/sys/fs/fusefs/xattr.cc
|
||||
@@ -448,6 +448,79 @@
|
||||
ASSERT_TRUE(WIFSIGNALED(status));
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * A buggy or malicious server returns a list that isn't nul-terminated. The
|
||||
+ * kernel should handle it gracefully.
|
||||
+ */
|
||||
+TEST_F(Listxattr, not_nul_terminated)
|
||||
+{
|
||||
+ uint64_t ino = 42;
|
||||
+ int ns = EXTATTR_NAMESPACE_USER;
|
||||
+ char *data;
|
||||
+ const char expected[4] = {3, 'f', 'o', 'o'};
|
||||
+ const char first[255] = "user.foo\0system.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
+ const uint8_t badlist[9] = {'u', 's', 'e', 'r', '.', 'f', 'o', 'o', 'd'};
|
||||
+ Sequence seq;
|
||||
+
|
||||
+ EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
|
||||
+ .WillRepeatedly(Invoke(
|
||||
+ ReturnImmediate([=](auto in __unused, auto& out) {
|
||||
+ SET_OUT_HEADER_LEN(out, entry);
|
||||
+ out.body.entry.attr.mode = S_IFREG | 0644;
|
||||
+ out.body.entry.nodeid = ino;
|
||||
+ out.body.entry.attr.nlink = 1;
|
||||
+ out.body.entry.attr_valid = UINT64_MAX;
|
||||
+ out.body.entry.entry_valid = UINT64_MAX;
|
||||
+ })));
|
||||
+
|
||||
+ /*
|
||||
+ * On the first LISTXATTRS call, return a big attribute just to fill
|
||||
+ * the heap with non-NUL data.
|
||||
+ */
|
||||
+ expect_listxattr(ino, 0,
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ out.body.listxattr.size = sizeof(first);
|
||||
+ SET_OUT_HEADER_LEN(out, listxattr);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+ expect_listxattr(ino, sizeof(first),
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ memcpy((void*)out.body.bytes, first, sizeof(first));
|
||||
+ out.header.len = sizeof(fuse_out_header) + sizeof(first);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+ /*
|
||||
+ * On the second LISTXATTRS call, return a malformed list with no NUL
|
||||
+ * termination. The heap might still be full of the data from the
|
||||
+ * first call.
|
||||
+ */
|
||||
+ expect_listxattr(ino, 0,
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ out.body.listxattr.size = sizeof(badlist);
|
||||
+ SET_OUT_HEADER_LEN(out, listxattr);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+ expect_listxattr(ino, sizeof(badlist),
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ memset((void*)out.body.bytes, 'x', sizeof(first));
|
||||
+ memcpy((void*)out.body.bytes, badlist, sizeof(badlist));
|
||||
+ out.header.len = sizeof(fuse_out_header) + sizeof(badlist);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+
|
||||
+ data = new char[1024];
|
||||
+
|
||||
+ ASSERT_EQ(static_cast<ssize_t>(sizeof(expected)),
|
||||
+ extattr_list_file(FULLPATH, ns, data, sizeof(data)))
|
||||
+ << strerror(errno);
|
||||
+ /*
|
||||
+ * Receiving this malformed list, the kernel should log it to dmesg and
|
||||
+ * report an IO error to the caller.
|
||||
+ */
|
||||
+ ASSERT_EQ(-1, extattr_list_file(FULLPATH, ns, data, sizeof(data)));
|
||||
+ EXPECT_EQ(EIO, errno);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Get the size of the list that it would take to list no extended attributes
|
||||
*/
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKHQbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvTEYP/ji9A2XSR2utdOfiMp7d
|
||||
I3Bhy66qAxYmC3xcVDwQLMe5z/7BK6lgJFfLp6Lq6cFAvKYy+cwY9iR85fAcGK60
|
||||
cInncCgFpgl3apNzBQrSg28kD2v1bIM80oaeM/uBJc2WIjKPeu5Z7DdniHiiUxae
|
||||
jknvhojwpCkd3KCktqrpW6IBHI1TtXuHJWpDPBWr9KbxEcTWUku4gfnXkLvq8yoi
|
||||
9YrMnWIK0zP322BbpEgujQengsoT2dYOQgj2YqXegLgrEiXWn/OdcmqSLSTKTl4W
|
||||
5Zdmf90hZbvUMD4jnumXAEoCG++oopec0uFkTPuFLuXTqZhSFeTAT+9P6vepyc6i
|
||||
EpoGEaSJjDlAdbpf/usp69ReROr6DHje67bMUcTpDWQXlv3fho8UirCMhOU8qAdI
|
||||
ZQS6ogJgTxz29sEfgD+raaiQYte7p3pFIA41RwXpN9g87hyMGk41GRxZMpyRtN44
|
||||
W8OUOUf1bwGpNcyu9J/z8WZ7eNT4iwuRw13IeQ7jUcz1bIt7GlnV8TiyFCc+ZsvW
|
||||
PzWx15zuWO751AzwnuUJkOR7H+xCZT48aOj5WvegdAIBpqMSz3R2veecyGsEjfRE
|
||||
pe9z06/2dNR9ZPCxW+1yA9iBZr46D+wWXAD4TCNajHDXIRUBu18blhITQmTbHqeO
|
||||
Ok5rj3IHx1CRL4kNgWDjtzHe
|
||||
=ZCVv
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,147 @@
|
||||
--- sys/fs/fuse/fuse_ipc.h.orig
|
||||
+++ sys/fs/fuse/fuse_ipc.h
|
||||
@@ -240,6 +240,7 @@
|
||||
#define FSESS_WARN_READLINK_EMBEDDED_NUL 0x1000000 /* corrupt READLINK output */
|
||||
#define FSESS_WARN_DOT_LOOKUP 0x2000000 /* Inconsistent . LOOKUP response */
|
||||
#define FSESS_WARN_INODE_MISMATCH 0x4000000 /* ino != nodeid */
|
||||
+#define FSESS_WARN_LSEXTATTR_NUL 0x20000000 /* Non nul-terminated xattr list */
|
||||
#define FSESS_MNTOPTS_MASK ( \
|
||||
FSESS_DAEMON_CAN_SPY | FSESS_PUSH_SYMLINKS_IN | \
|
||||
FSESS_DEFAULT_PERMISSIONS | FSESS_INTR)
|
||||
--- sys/fs/fuse/fuse_vnops.c.orig
|
||||
+++ sys/fs/fuse/fuse_vnops.c
|
||||
@@ -2841,8 +2841,8 @@
|
||||
* bsd_list, bsd_list_len - output list compatible with bsd vfs
|
||||
*/
|
||||
static int
|
||||
-fuse_xattrlist_convert(char *prefix, const char *list, int list_len,
|
||||
- char *bsd_list, int *bsd_list_len)
|
||||
+fuse_xattrlist_convert(struct fuse_data *data, char *prefix, const char *list,
|
||||
+ int list_len, char *bsd_list, int *bsd_list_len)
|
||||
{
|
||||
int len, pos, dist_to_next, prefix_len;
|
||||
|
||||
@@ -2851,7 +2851,14 @@
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
while (pos < list_len && list[pos] != '\0') {
|
||||
- dist_to_next = strlen(&list[pos]) + 1;
|
||||
+ dist_to_next = strnlen(&list[pos], list_len - pos - 1) + 1;
|
||||
+ if (list[pos + dist_to_next - 1] != '\0') {
|
||||
+ fuse_warn(data, FSESS_WARN_LSEXTATTR_NUL,
|
||||
+ "The FUSE server returned a non nul-terminated "
|
||||
+ "LISTXATTR response.");
|
||||
+ return (EXTERROR(EIO,
|
||||
+ "The FUSE server returned a malformed list"));
|
||||
+ }
|
||||
if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
|
||||
list[pos + prefix_len] == extattr_namespace_separator) {
|
||||
len = dist_to_next -
|
||||
@@ -2907,6 +2914,7 @@
|
||||
struct fuse_listxattr_in *list_xattr_in;
|
||||
struct fuse_listxattr_out *list_xattr_out;
|
||||
struct mount *mp = vnode_mount(vp);
|
||||
+ struct fuse_data *data = fuse_get_mpdata(mp);
|
||||
struct thread *td = ap->a_td;
|
||||
struct ucred *cred = ap->a_cred;
|
||||
char *prefix;
|
||||
@@ -2987,8 +2995,6 @@
|
||||
linux_list = fdi.answ;
|
||||
/* FUSE doesn't allow the server to return more data than requested */
|
||||
if (fdi.iosize > linux_list_len) {
|
||||
- struct fuse_data *data = fuse_get_mpdata(mp);
|
||||
-
|
||||
fuse_warn(data, FSESS_WARN_LSEXTATTR_LONG,
|
||||
"server returned "
|
||||
"more extended attribute data than requested; "
|
||||
@@ -3005,7 +3011,7 @@
|
||||
* FreeBSD's format before giving it to the user.
|
||||
*/
|
||||
bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
|
||||
- err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
|
||||
+ err = fuse_xattrlist_convert(data, prefix, linux_list, linux_list_len,
|
||||
bsd_list, &bsd_list_len);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
--- tests/sys/fs/fusefs/xattr.cc.orig
|
||||
+++ tests/sys/fs/fusefs/xattr.cc
|
||||
@@ -492,6 +492,79 @@
|
||||
ASSERT_TRUE(WIFSIGNALED(status));
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * A buggy or malicious server returns a list that isn't nul-terminated. The
|
||||
+ * kernel should handle it gracefully.
|
||||
+ */
|
||||
+TEST_F(Listxattr, not_nul_terminated)
|
||||
+{
|
||||
+ uint64_t ino = 42;
|
||||
+ int ns = EXTATTR_NAMESPACE_USER;
|
||||
+ char *data;
|
||||
+ const char expected[4] = {3, 'f', 'o', 'o'};
|
||||
+ const char first[255] = "user.foo\0system.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
+ const uint8_t badlist[9] = {'u', 's', 'e', 'r', '.', 'f', 'o', 'o', 'd'};
|
||||
+ Sequence seq;
|
||||
+
|
||||
+ EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
|
||||
+ .WillRepeatedly(Invoke(
|
||||
+ ReturnImmediate([=](auto in __unused, auto& out) {
|
||||
+ SET_OUT_HEADER_LEN(out, entry);
|
||||
+ out.body.entry.attr.mode = S_IFREG | 0644;
|
||||
+ out.body.entry.nodeid = ino;
|
||||
+ out.body.entry.attr.nlink = 1;
|
||||
+ out.body.entry.attr_valid = UINT64_MAX;
|
||||
+ out.body.entry.entry_valid = UINT64_MAX;
|
||||
+ })));
|
||||
+
|
||||
+ /*
|
||||
+ * On the first LISTXATTRS call, return a big attribute just to fill
|
||||
+ * the heap with non-NUL data.
|
||||
+ */
|
||||
+ expect_listxattr(ino, 0,
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ out.body.listxattr.size = sizeof(first);
|
||||
+ SET_OUT_HEADER_LEN(out, listxattr);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+ expect_listxattr(ino, sizeof(first),
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ memcpy((void*)out.body.bytes, first, sizeof(first));
|
||||
+ out.header.len = sizeof(fuse_out_header) + sizeof(first);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+ /*
|
||||
+ * On the second LISTXATTRS call, return a malformed list with no NUL
|
||||
+ * termination. The heap might still be full of the data from the
|
||||
+ * first call.
|
||||
+ */
|
||||
+ expect_listxattr(ino, 0,
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ out.body.listxattr.size = sizeof(badlist);
|
||||
+ SET_OUT_HEADER_LEN(out, listxattr);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+ expect_listxattr(ino, sizeof(badlist),
|
||||
+ ReturnImmediate([&](auto in __unused, auto& out) {
|
||||
+ memset((void*)out.body.bytes, 'x', sizeof(first));
|
||||
+ memcpy((void*)out.body.bytes, badlist, sizeof(badlist));
|
||||
+ out.header.len = sizeof(fuse_out_header) + sizeof(badlist);
|
||||
+ }), &seq
|
||||
+ );
|
||||
+
|
||||
+ data = new char[1024];
|
||||
+
|
||||
+ ASSERT_EQ(static_cast<ssize_t>(sizeof(expected)),
|
||||
+ extattr_list_file(FULLPATH, ns, data, sizeof(data)))
|
||||
+ << strerror(errno);
|
||||
+ /*
|
||||
+ * Receiving this malformed list, the kernel should log it to dmesg and
|
||||
+ * report an IO error to the caller.
|
||||
+ */
|
||||
+ ASSERT_EQ(-1, extattr_list_file(FULLPATH, ns, data, sizeof(data)));
|
||||
+ EXPECT_EQ(EIO, errno);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Get the size of the list that it would take to list no extended attributes
|
||||
*/
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKHUbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrv0+cP/0P7o4+JOhW/CAe6DdQI
|
||||
90ZMElw9Q/ceD4P63RTby9oFCIG1l+hEMfCeH9CoaRXuTelIrX8g+O5o+9ED3oPc
|
||||
FpPj/baTFXoq8ZnxoT18ZtGqsF/pjpZlEZx4vFLILjXMnmun9WC7Bw2X51gUxh46
|
||||
XoilE/ofXmTebRRn/cslae3DTOBezMPO59QVg+qvdQEzoPxTF6YWtGW+775ZiSEo
|
||||
i0jxBvTqNe17QKZnjMO5Mr7ZlCAmG10z8ygmWOXbtIyaSSq8I1UKzUBhnq4UUC1E
|
||||
BW7YtbYBu/ZIG9Wyg4apcN7Rb4krg2J/5wWaZnJYxLNEWM1wTjR1Mg/AFsV/1mav
|
||||
ueJBEkGRfGcTH/UbCi4nMBTizN18dATdkbQSuffU+BeTLYjylS15nramtI5BJcVa
|
||||
M2XHMVFHNvQB0bVyRwTXvwXggwSXDnIPeB/k3w+3usyY/xQ66cf5KfaNFZ/MJcRv
|
||||
hukTFXwRFt5q6Q0Emnt4whti+gn4HQNnfFHJONdXXPU2X05CGGHtg5/qTdm8wLKm
|
||||
iO8ggc3i/15gAdaPKwkWMwQyifwQ4kNYPttwqkrTz+kyCuhzftHuWNJ+ZRnh+99a
|
||||
pPNuTMZd9ZOTkjX0DebEbPZD9CZ4qiwquOMnUJ07b6xTa02BHk63D0SDIVl4vV9R
|
||||
9u08BlmYuNc2zTAFit1MychY
|
||||
=gqpB
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,164 @@
|
||||
--- sys/kern/kern_sig.c.orig
|
||||
+++ sys/kern/kern_sig.c
|
||||
@@ -2677,23 +2677,26 @@
|
||||
struct sysentvec *sv;
|
||||
struct sysent *se;
|
||||
register_t rv_saved[2];
|
||||
+ unsigned int sc;
|
||||
int error, nerror;
|
||||
- int sc;
|
||||
bool audited, sy_thr_static;
|
||||
|
||||
- sv = p->p_sysent;
|
||||
- if (sv->sv_table == NULL || sv->sv_size < tsr->ts_sa.code) {
|
||||
- tsr->ts_ret.sr_error = ENOSYS;
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
sc = tsr->ts_sa.code;
|
||||
if (sc == SYS_syscall || sc == SYS___syscall) {
|
||||
+ if (tsr->ts_nargs == 0) {
|
||||
+ tsr->ts_ret.sr_error = EINVAL;
|
||||
+ return;
|
||||
+ }
|
||||
sc = tsr->ts_sa.args[0];
|
||||
memmove(&tsr->ts_sa.args[0], &tsr->ts_sa.args[1],
|
||||
sizeof(register_t) * (tsr->ts_nargs - 1));
|
||||
}
|
||||
|
||||
+ sv = p->p_sysent;
|
||||
+ if (sv->sv_table == NULL || sc >= sv->sv_size) {
|
||||
+ tsr->ts_ret.sr_error = ENOSYS;
|
||||
+ return;
|
||||
+ }
|
||||
tsr->ts_sa.callp = se = &sv->sv_table[sc];
|
||||
|
||||
VM_CNT_INC(v_syscall);
|
||||
--- tests/sys/kern/ptrace_test.c.orig
|
||||
+++ tests/sys/kern/ptrace_test.c
|
||||
@@ -4363,6 +4363,25 @@
|
||||
REQUIRE_EQ(close(pd), 0);
|
||||
}
|
||||
|
||||
+static void
|
||||
+pt_sc_remote(pid_t pid, struct ptrace_sc_remote *pscr, int error,
|
||||
+ syscallarg_t ret)
|
||||
+{
|
||||
+ pid_t wpid;
|
||||
+ int status;
|
||||
+
|
||||
+ ATF_REQUIRE(ptrace(PT_SC_REMOTE, pid, (caddr_t)pscr, sizeof(*pscr)) !=
|
||||
+ -1);
|
||||
+ ATF_REQUIRE_EQ(pscr->pscr_ret.sr_error, error);
|
||||
+ if (error == 0)
|
||||
+ ATF_REQUIRE_EQ(pscr->pscr_ret.sr_retval[0], ret);
|
||||
+
|
||||
+ wpid = waitpid(pid, &status, 0);
|
||||
+ REQUIRE_EQ(wpid, pid);
|
||||
+ ATF_REQUIRE(WIFSTOPPED(status));
|
||||
+ REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Try using PT_SC_REMOTE to get the PID of a traced child process.
|
||||
*/
|
||||
@@ -4370,8 +4389,7 @@
|
||||
ATF_TC_BODY(ptrace__PT_SC_REMOTE_getpid, tc)
|
||||
{
|
||||
struct ptrace_sc_remote pscr;
|
||||
- pid_t fpid, wpid;
|
||||
- int status;
|
||||
+ pid_t fpid;
|
||||
|
||||
ATF_REQUIRE((fpid = fork()) != -1);
|
||||
if (fpid == 0) {
|
||||
@@ -4384,35 +4402,62 @@
|
||||
pscr.pscr_syscall = SYS_getpid;
|
||||
pscr.pscr_nargs = 0;
|
||||
pscr.pscr_args = NULL;
|
||||
- ATF_REQUIRE(ptrace(PT_SC_REMOTE, fpid, (caddr_t)&pscr, sizeof(pscr)) !=
|
||||
- -1);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_error == 0,
|
||||
- "remote getpid failed with error %d", pscr.pscr_ret.sr_error);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_retval[0] == fpid,
|
||||
- "unexpected return value %jd instead of %d",
|
||||
- (intmax_t)pscr.pscr_ret.sr_retval[0], fpid);
|
||||
-
|
||||
- wpid = waitpid(fpid, &status, 0);
|
||||
- REQUIRE_EQ(wpid, fpid);
|
||||
- ATF_REQUIRE(WIFSTOPPED(status));
|
||||
- REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
|
||||
+ pt_sc_remote(fpid, &pscr, 0, fpid);
|
||||
|
||||
pscr.pscr_syscall = SYS_getppid;
|
||||
pscr.pscr_nargs = 0;
|
||||
pscr.pscr_args = NULL;
|
||||
- ATF_REQUIRE(ptrace(PT_SC_REMOTE, fpid, (caddr_t)&pscr, sizeof(pscr)) !=
|
||||
- -1);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_error == 0,
|
||||
- "remote getppid failed with error %d", pscr.pscr_ret.sr_error);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_retval[0] == getpid(),
|
||||
- "unexpected return value %jd instead of %d",
|
||||
- (intmax_t)pscr.pscr_ret.sr_retval[0], fpid);
|
||||
+ pt_sc_remote(fpid, &pscr, 0, getpid());
|
||||
+
|
||||
+ ATF_REQUIRE(ptrace(PT_DETACH, fpid, (caddr_t)1, 0) != -1);
|
||||
+}
|
||||
+
|
||||
+ATF_TC_WITHOUT_HEAD(ptrace__PT_SC_REMOTE_syscall_validation);
|
||||
+ATF_TC_BODY(ptrace__PT_SC_REMOTE_syscall_validation, tc)
|
||||
+{
|
||||
+ struct ptrace_sc_remote pscr;
|
||||
+ quad_t code;
|
||||
+ int status;
|
||||
+ pid_t fpid, wpid;
|
||||
+
|
||||
+ code = SYS_MAXSYSCALL;
|
||||
+
|
||||
+ ATF_REQUIRE((fpid = fork()) != -1);
|
||||
+ if (fpid == 0) {
|
||||
+ trace_me();
|
||||
+ exit(0);
|
||||
+ }
|
||||
|
||||
wpid = waitpid(fpid, &status, 0);
|
||||
REQUIRE_EQ(wpid, fpid);
|
||||
ATF_REQUIRE(WIFSTOPPED(status));
|
||||
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
|
||||
|
||||
+ pscr.pscr_syscall = SYS_MAXSYSCALL;
|
||||
+ pscr.pscr_nargs = 0;
|
||||
+ pscr.pscr_args = NULL;
|
||||
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS_syscall;
|
||||
+ pscr.pscr_nargs = 0;
|
||||
+ pscr.pscr_args = NULL;
|
||||
+ pt_sc_remote(fpid, &pscr, EINVAL, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS_syscall;
|
||||
+ pscr.pscr_nargs = 1;
|
||||
+ pscr.pscr_args = (syscallarg_t *)&code;
|
||||
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS___syscall;
|
||||
+ pscr.pscr_nargs = 0;
|
||||
+ pscr.pscr_args = NULL;
|
||||
+ pt_sc_remote(fpid, &pscr, EINVAL, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS___syscall;
|
||||
+ pscr.pscr_nargs = 1;
|
||||
+ pscr.pscr_args = (syscallarg_t *)&code;
|
||||
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
|
||||
+
|
||||
ATF_REQUIRE(ptrace(PT_DETACH, fpid, (caddr_t)1, 0) != -1);
|
||||
}
|
||||
|
||||
@@ -4529,6 +4574,7 @@
|
||||
ATF_TP_ADD_TC(tp, ptrace__procdesc_wait_child);
|
||||
ATF_TP_ADD_TC(tp, ptrace__procdesc_reparent_wait_child);
|
||||
ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_getpid);
|
||||
+ ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_syscall_validation);
|
||||
ATF_TP_ADD_TC(tp, ptrace__reap_kill_stopped);
|
||||
|
||||
return (atf_no_error());
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKHgbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvlAMP/10MF70q2uwHdVYqJ8R8
|
||||
LNy+2BJDPiPerGbCnbjqtD8ciDAvMRMD6413kMyOrfpMQePSUwyz2y7ByxJPOeca
|
||||
xkzoCebhuwpf6iXZJQa86OyTR64hDBbGLl4SF9r8Kmd9icSm79AQXmYxRoXeqsJX
|
||||
x/DHY2q08M2nclIAggF6c10zLvtPdOmJNVTvMcFeEt+gsV6RwRIbvk+5nYLMIBlU
|
||||
+SQ9M/Q0mYuAlEUZAqtJOPC2iOoetyO6arBr76RhBOB6nxced60QrKZLY/sRdBaE
|
||||
TTpdkWV5O/E8lj8IbSwzZx8saHo/BS5mT9yJivbDrFSQ6oLds0SZEtGOkXWFLfCR
|
||||
/aLnp6vypCIWcJ/BkS5hfqP3sAw4nTuGBD9EtG4tdcqV+ys2NFT6vIOo2oJTKuys
|
||||
JcYmGs1lP0a9iT2DM3SOW1C6CIU/mDmpeZ1uJv11a9ZUo4KSQA7WJhm4NpSke5AP
|
||||
7+omM3heH+RWzgbysrPywHGIygzWFzhWi6lrE/ys8OC7mHizR+B3DAAhAmdAKa7k
|
||||
AQMeIIghg5NphPYO8/tBml1QJ3q6oHp4ohkPIppmiI3M3nUxJH3yb/S9klnM3CM4
|
||||
pwCYTQn/ph8519OFr4Hjn/RylZvjmdoIthwImZlX2xfyMhZoWFlFRAg+MzR784Yy
|
||||
FDCL4ifSXzPjx9xqeryZ61fk
|
||||
=vTiT
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,154 @@
|
||||
--- sys/kern/kern_sig.c.orig
|
||||
+++ sys/kern/kern_sig.c
|
||||
@@ -2692,23 +2692,26 @@
|
||||
struct sysentvec *sv;
|
||||
struct sysent *se;
|
||||
register_t rv_saved[2];
|
||||
+ unsigned int sc;
|
||||
int error, nerror;
|
||||
- int sc;
|
||||
bool audited, sy_thr_static;
|
||||
|
||||
- sv = p->p_sysent;
|
||||
- if (sv->sv_table == NULL || sv->sv_size < tsr->ts_sa.code) {
|
||||
- tsr->ts_ret.sr_error = ENOSYS;
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
sc = tsr->ts_sa.code;
|
||||
if (sc == SYS_syscall || sc == SYS___syscall) {
|
||||
+ if (tsr->ts_nargs == 0) {
|
||||
+ tsr->ts_ret.sr_error = EINVAL;
|
||||
+ return;
|
||||
+ }
|
||||
sc = tsr->ts_sa.args[0];
|
||||
memmove(&tsr->ts_sa.args[0], &tsr->ts_sa.args[1],
|
||||
sizeof(register_t) * (tsr->ts_nargs - 1));
|
||||
}
|
||||
|
||||
+ sv = p->p_sysent;
|
||||
+ if (sv->sv_table == NULL || sc >= sv->sv_size) {
|
||||
+ tsr->ts_ret.sr_error = ENOSYS;
|
||||
+ return;
|
||||
+ }
|
||||
tsr->ts_sa.callp = se = &sv->sv_table[sc];
|
||||
|
||||
VM_CNT_INC(v_syscall);
|
||||
--- tests/sys/kern/ptrace_test.c.orig
|
||||
+++ tests/sys/kern/ptrace_test.c
|
||||
@@ -4363,6 +4363,25 @@
|
||||
REQUIRE_EQ(close(pd), 0);
|
||||
}
|
||||
|
||||
+static void
|
||||
+pt_sc_remote(pid_t pid, struct ptrace_sc_remote *pscr, int error,
|
||||
+ syscallarg_t ret)
|
||||
+{
|
||||
+ pid_t wpid;
|
||||
+ int status;
|
||||
+
|
||||
+ ATF_REQUIRE(ptrace(PT_SC_REMOTE, pid, (caddr_t)pscr, sizeof(*pscr)) !=
|
||||
+ -1);
|
||||
+ ATF_REQUIRE_EQ(pscr->pscr_ret.sr_error, error);
|
||||
+ if (error == 0)
|
||||
+ ATF_REQUIRE_EQ(pscr->pscr_ret.sr_retval[0], ret);
|
||||
+
|
||||
+ wpid = waitpid(pid, &status, 0);
|
||||
+ REQUIRE_EQ(wpid, pid);
|
||||
+ ATF_REQUIRE(WIFSTOPPED(status));
|
||||
+ REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Try using PT_SC_REMOTE to get the PID of a traced child process.
|
||||
*/
|
||||
@@ -4387,35 +4406,62 @@
|
||||
pscr.pscr_syscall = SYS_getpid;
|
||||
pscr.pscr_nargs = 0;
|
||||
pscr.pscr_args = NULL;
|
||||
- ATF_REQUIRE(ptrace(PT_SC_REMOTE, fpid, (caddr_t)&pscr, sizeof(pscr)) !=
|
||||
- -1);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_error == 0,
|
||||
- "remote getpid failed with error %d", pscr.pscr_ret.sr_error);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_retval[0] == fpid,
|
||||
- "unexpected return value %jd instead of %d",
|
||||
- (intmax_t)pscr.pscr_ret.sr_retval[0], fpid);
|
||||
-
|
||||
- wpid = waitpid(fpid, &status, 0);
|
||||
- REQUIRE_EQ(wpid, fpid);
|
||||
- ATF_REQUIRE(WIFSTOPPED(status));
|
||||
- REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
|
||||
+ pt_sc_remote(fpid, &pscr, 0, fpid);
|
||||
|
||||
pscr.pscr_syscall = SYS_getppid;
|
||||
pscr.pscr_nargs = 0;
|
||||
pscr.pscr_args = NULL;
|
||||
- ATF_REQUIRE(ptrace(PT_SC_REMOTE, fpid, (caddr_t)&pscr, sizeof(pscr)) !=
|
||||
- -1);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_error == 0,
|
||||
- "remote getppid failed with error %d", pscr.pscr_ret.sr_error);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_retval[0] == getpid(),
|
||||
- "unexpected return value %jd instead of %d",
|
||||
- (intmax_t)pscr.pscr_ret.sr_retval[0], fpid);
|
||||
+ pt_sc_remote(fpid, &pscr, 0, getpid());
|
||||
+
|
||||
+ ATF_REQUIRE(ptrace(PT_DETACH, fpid, (caddr_t)1, 0) != -1);
|
||||
+}
|
||||
+
|
||||
+ATF_TC_WITHOUT_HEAD(ptrace__PT_SC_REMOTE_syscall_validation);
|
||||
+ATF_TC_BODY(ptrace__PT_SC_REMOTE_syscall_validation, tc)
|
||||
+{
|
||||
+ struct ptrace_sc_remote pscr;
|
||||
+ quad_t code;
|
||||
+ int status;
|
||||
+ pid_t fpid, wpid;
|
||||
+
|
||||
+ code = SYS_MAXSYSCALL;
|
||||
+
|
||||
+ ATF_REQUIRE((fpid = fork()) != -1);
|
||||
+ if (fpid == 0) {
|
||||
+ trace_me();
|
||||
+ exit(0);
|
||||
+ }
|
||||
|
||||
wpid = waitpid(fpid, &status, 0);
|
||||
REQUIRE_EQ(wpid, fpid);
|
||||
ATF_REQUIRE(WIFSTOPPED(status));
|
||||
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
|
||||
|
||||
+ pscr.pscr_syscall = SYS_MAXSYSCALL;
|
||||
+ pscr.pscr_nargs = 0;
|
||||
+ pscr.pscr_args = NULL;
|
||||
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS_syscall;
|
||||
+ pscr.pscr_nargs = 0;
|
||||
+ pscr.pscr_args = NULL;
|
||||
+ pt_sc_remote(fpid, &pscr, EINVAL, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS_syscall;
|
||||
+ pscr.pscr_nargs = 1;
|
||||
+ pscr.pscr_args = (syscallarg_t *)&code;
|
||||
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS___syscall;
|
||||
+ pscr.pscr_nargs = 0;
|
||||
+ pscr.pscr_args = NULL;
|
||||
+ pt_sc_remote(fpid, &pscr, EINVAL, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS___syscall;
|
||||
+ pscr.pscr_nargs = 1;
|
||||
+ pscr.pscr_args = (syscallarg_t *)&code;
|
||||
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
|
||||
+
|
||||
ATF_REQUIRE(ptrace(PT_DETACH, fpid, (caddr_t)1, 0) != -1);
|
||||
}
|
||||
|
||||
@@ -4658,6 +4704,7 @@
|
||||
ATF_TP_ADD_TC(tp, ptrace__procdesc_wait_child);
|
||||
ATF_TP_ADD_TC(tp, ptrace__procdesc_reparent_wait_child);
|
||||
ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_getpid);
|
||||
+ ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_syscall_validation);
|
||||
ATF_TP_ADD_TC(tp, ptrace__reap_kill_stopped);
|
||||
ATF_TP_ADD_TC(tp, ptrace__PT_ATTACH_no_EINTR);
|
||||
ATF_TP_ADD_TC(tp, ptrace__PT_DETACH_continued);
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKHkbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrviIQP/0J+7WsDP2sa3qN/bPca
|
||||
m6rVHn83Jo8wnPSaUwUHqiWWCsXZBKSWpMcUneQoknmqArC7l2SNPAhXv3EH01fi
|
||||
ot63ojivc6/Fi0LPhnLC0XSvOePelm9EAkIuYny106q4mWDO0AQIKLks8AMWyJF7
|
||||
nEqUzVkXegoasWYmcS+9s0ddS+mVZdNm9Ajd+7gohX2T1/SK3FgIdJMZaDLx4cUV
|
||||
3B+44iS557PZLTpEjBSESxVM9132HFY16Fz3HUI6i+Cohrnip9KmSAFbutqmKARa
|
||||
08xfFDGeuLgkxZJFoiBmF9o3QxiutRlTeGl3l2A2WIKkMuIf4UtEMMaD+9KrMIpP
|
||||
idi0Sa9utRVc1TKRg2hjb2121b7ZAM3SaCvBbunBmV8Kv051sVRcoElG4QsmZgxf
|
||||
4rwpSBLQdtIBTjvSwhzTwnPJLcb6Lehb2ntZ55NDelSru/3DODEX7oKqKfst3Bgv
|
||||
QM+L/UYmedbb9qCe58tCgXOE9GEXn8pL7URUT7zv0zf6nX+Tc4viS9TO8lG65wU6
|
||||
c8/QnDt9kxts6/Nzfe5JAnSMxPLExuc7Cka6n625nB0L/q81rCvWISwUpJFa49in
|
||||
mbeuih5Jggpn/kZ+ifFQIpK59rpHShzumTdIWMZubJOSALjpAXFynvC1si/k/W6/
|
||||
xxi7tyKq1Tb/SRsXWk4ChxNZ
|
||||
=c4Yi
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,154 @@
|
||||
--- sys/kern/kern_sig.c.orig
|
||||
+++ sys/kern/kern_sig.c
|
||||
@@ -2678,23 +2678,26 @@
|
||||
struct sysentvec *sv;
|
||||
struct sysent *se;
|
||||
register_t rv_saved[2];
|
||||
+ unsigned int sc;
|
||||
int error, nerror;
|
||||
- int sc;
|
||||
bool audited, sy_thr_static;
|
||||
|
||||
- sv = p->p_sysent;
|
||||
- if (sv->sv_table == NULL || sv->sv_size < tsr->ts_sa.code) {
|
||||
- tsr->ts_ret.sr_error = ENOSYS;
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
sc = tsr->ts_sa.code;
|
||||
if (sc == SYS_syscall || sc == SYS___syscall) {
|
||||
+ if (tsr->ts_nargs == 0) {
|
||||
+ tsr->ts_ret.sr_error = EINVAL;
|
||||
+ return;
|
||||
+ }
|
||||
sc = tsr->ts_sa.args[0];
|
||||
memmove(&tsr->ts_sa.args[0], &tsr->ts_sa.args[1],
|
||||
sizeof(register_t) * (tsr->ts_nargs - 1));
|
||||
}
|
||||
|
||||
+ sv = p->p_sysent;
|
||||
+ if (sv->sv_table == NULL || sc >= sv->sv_size) {
|
||||
+ tsr->ts_ret.sr_error = ENOSYS;
|
||||
+ return;
|
||||
+ }
|
||||
tsr->ts_sa.callp = se = &sv->sv_table[sc];
|
||||
|
||||
VM_CNT_INC(v_syscall);
|
||||
--- tests/sys/kern/ptrace_test.c.orig
|
||||
+++ tests/sys/kern/ptrace_test.c
|
||||
@@ -4362,6 +4362,25 @@
|
||||
REQUIRE_EQ(close(pd), 0);
|
||||
}
|
||||
|
||||
+static void
|
||||
+pt_sc_remote(pid_t pid, struct ptrace_sc_remote *pscr, int error,
|
||||
+ syscallarg_t ret)
|
||||
+{
|
||||
+ pid_t wpid;
|
||||
+ int status;
|
||||
+
|
||||
+ ATF_REQUIRE(ptrace(PT_SC_REMOTE, pid, (caddr_t)pscr, sizeof(*pscr)) !=
|
||||
+ -1);
|
||||
+ ATF_REQUIRE_EQ(pscr->pscr_ret.sr_error, error);
|
||||
+ if (error == 0)
|
||||
+ ATF_REQUIRE_EQ(pscr->pscr_ret.sr_retval[0], ret);
|
||||
+
|
||||
+ wpid = waitpid(pid, &status, 0);
|
||||
+ REQUIRE_EQ(wpid, pid);
|
||||
+ ATF_REQUIRE(WIFSTOPPED(status));
|
||||
+ REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Try using PT_SC_REMOTE to get the PID of a traced child process.
|
||||
*/
|
||||
@@ -4386,35 +4405,62 @@
|
||||
pscr.pscr_syscall = SYS_getpid;
|
||||
pscr.pscr_nargs = 0;
|
||||
pscr.pscr_args = NULL;
|
||||
- ATF_REQUIRE(ptrace(PT_SC_REMOTE, fpid, (caddr_t)&pscr, sizeof(pscr)) !=
|
||||
- -1);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_error == 0,
|
||||
- "remote getpid failed with error %d", pscr.pscr_ret.sr_error);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_retval[0] == fpid,
|
||||
- "unexpected return value %jd instead of %d",
|
||||
- (intmax_t)pscr.pscr_ret.sr_retval[0], fpid);
|
||||
-
|
||||
- wpid = waitpid(fpid, &status, 0);
|
||||
- REQUIRE_EQ(wpid, fpid);
|
||||
- ATF_REQUIRE(WIFSTOPPED(status));
|
||||
- REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
|
||||
+ pt_sc_remote(fpid, &pscr, 0, fpid);
|
||||
|
||||
pscr.pscr_syscall = SYS_getppid;
|
||||
pscr.pscr_nargs = 0;
|
||||
pscr.pscr_args = NULL;
|
||||
- ATF_REQUIRE(ptrace(PT_SC_REMOTE, fpid, (caddr_t)&pscr, sizeof(pscr)) !=
|
||||
- -1);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_error == 0,
|
||||
- "remote getppid failed with error %d", pscr.pscr_ret.sr_error);
|
||||
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_retval[0] == getpid(),
|
||||
- "unexpected return value %jd instead of %d",
|
||||
- (intmax_t)pscr.pscr_ret.sr_retval[0], fpid);
|
||||
+ pt_sc_remote(fpid, &pscr, 0, getpid());
|
||||
+
|
||||
+ ATF_REQUIRE(ptrace(PT_DETACH, fpid, (caddr_t)1, 0) != -1);
|
||||
+}
|
||||
+
|
||||
+ATF_TC_WITHOUT_HEAD(ptrace__PT_SC_REMOTE_syscall_validation);
|
||||
+ATF_TC_BODY(ptrace__PT_SC_REMOTE_syscall_validation, tc)
|
||||
+{
|
||||
+ struct ptrace_sc_remote pscr;
|
||||
+ quad_t code;
|
||||
+ int status;
|
||||
+ pid_t fpid, wpid;
|
||||
+
|
||||
+ code = SYS_MAXSYSCALL;
|
||||
+
|
||||
+ ATF_REQUIRE((fpid = fork()) != -1);
|
||||
+ if (fpid == 0) {
|
||||
+ trace_me();
|
||||
+ exit(0);
|
||||
+ }
|
||||
|
||||
wpid = waitpid(fpid, &status, 0);
|
||||
REQUIRE_EQ(wpid, fpid);
|
||||
ATF_REQUIRE(WIFSTOPPED(status));
|
||||
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
|
||||
|
||||
+ pscr.pscr_syscall = SYS_MAXSYSCALL;
|
||||
+ pscr.pscr_nargs = 0;
|
||||
+ pscr.pscr_args = NULL;
|
||||
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS_syscall;
|
||||
+ pscr.pscr_nargs = 0;
|
||||
+ pscr.pscr_args = NULL;
|
||||
+ pt_sc_remote(fpid, &pscr, EINVAL, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS_syscall;
|
||||
+ pscr.pscr_nargs = 1;
|
||||
+ pscr.pscr_args = (syscallarg_t *)&code;
|
||||
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS___syscall;
|
||||
+ pscr.pscr_nargs = 0;
|
||||
+ pscr.pscr_args = NULL;
|
||||
+ pt_sc_remote(fpid, &pscr, EINVAL, 0);
|
||||
+
|
||||
+ pscr.pscr_syscall = SYS___syscall;
|
||||
+ pscr.pscr_nargs = 1;
|
||||
+ pscr.pscr_args = (syscallarg_t *)&code;
|
||||
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
|
||||
+
|
||||
ATF_REQUIRE(ptrace(PT_DETACH, fpid, (caddr_t)1, 0) != -1);
|
||||
}
|
||||
|
||||
@@ -4657,6 +4703,7 @@
|
||||
ATF_TP_ADD_TC(tp, ptrace__procdesc_wait_child);
|
||||
ATF_TP_ADD_TC(tp, ptrace__procdesc_reparent_wait_child);
|
||||
ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_getpid);
|
||||
+ ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_syscall_validation);
|
||||
ATF_TP_ADD_TC(tp, ptrace__reap_kill_stopped);
|
||||
ATF_TP_ADD_TC(tp, ptrace__PT_ATTACH_no_EINTR);
|
||||
ATF_TP_ADD_TC(tp, ptrace__PT_DETACH_continued);
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKHobFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrv+mIP/jrd2IsNHPhHsbnSjg16
|
||||
fbLtDSzIBAA5NT8ELxD21EvUVrQlIIakjdxmBs9GyssUDQMWdhXJvVUg+Buk0WPo
|
||||
U6sLJU8KfA1r8R3BVvwQVUilIOZd3rbf2p8v+SnilKxLtHThm0N8N05og4k9J4wj
|
||||
sbN5cXapiaLeQlrGD9e7qDQRTrxO9XG4qxvipUtjgGqgOPxhfAvPxylieWrQwr80
|
||||
V+wpX/gbGLr8psmwYk/4XNkd4tHI4OguNzyOaCgMfcb16AueQBxzgkexlZ1GIxgY
|
||||
VF8LMr8w/Qfh2ukjTtgvpKJ8G7TDqoZTxqs+c3mxuW66AxX20x8i+WRlo4X0VTjm
|
||||
lTd77Fejoyff6DI8yIDmTaCblX2OLyZFsoi8cY3TRkK6BVDvW08bSE3ztZZwJO4e
|
||||
oFVZsONII8GBTRf2yjhOxLaJpheRsff75AqSwTpy8w9XkqQ70n7K8OUsWmHTN2VK
|
||||
ZpCMGIu6tX7ShxnigVrA3o0O30fg3VuvVqnsbyA7jDyjzUjpywwd12zcQ+0eZz8U
|
||||
1i2XH/hmZ+0dxArVB19QQ/I2vBSQvqYdRxwmitVOWpxZLWWr6FDLMS8BumHXn2IN
|
||||
oNbDdiClPyW7+CpJzfrxA5kcnZsBF/aBi/xRZtV/xof4M5LhYDYzbdDWJYgEmW4p
|
||||
JSVYiYuiRnJmeWi01UJYGWr6
|
||||
=I125
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,539 @@
|
||||
--- lib/libcasper/libcasper/libcasper_impl.h.orig
|
||||
+++ lib/libcasper/libcasper/libcasper_impl.h
|
||||
@@ -54,6 +54,8 @@
|
||||
void service_start(struct service *service, int sock, int procfd);
|
||||
const char *service_name(struct service *service);
|
||||
int service_get_channel_flags(struct service *service);
|
||||
+bool service_have_connections(void);
|
||||
+bool service_poll_dispatch(void);
|
||||
|
||||
/* Private service connection functions. */
|
||||
struct service_connection *service_connection_add(struct service *service,
|
||||
@@ -64,10 +66,6 @@
|
||||
int service_connection_clone(
|
||||
struct service *service,
|
||||
struct service_connection *sconn);
|
||||
-struct service_connection *service_connection_first(
|
||||
- struct service *service);
|
||||
-struct service_connection *service_connection_next(
|
||||
- struct service_connection *sconn);
|
||||
cap_channel_t *service_connection_get_chan(
|
||||
const struct service_connection *sconn);
|
||||
int service_connection_get_sock(
|
||||
--- lib/libcasper/libcasper/libcasper_service.c.orig
|
||||
+++ lib/libcasper/libcasper/libcasper_service.c
|
||||
@@ -223,10 +223,6 @@
|
||||
void
|
||||
casper_main_loop(int fd)
|
||||
{
|
||||
- fd_set fds;
|
||||
- struct casper_service *casserv;
|
||||
- struct service_connection *sconn, *sconntmp;
|
||||
- int sock, maxfd, ret;
|
||||
|
||||
if (zygote_init() < 0)
|
||||
_exit(1);
|
||||
@@ -236,55 +232,10 @@
|
||||
*/
|
||||
service_register_core(fd);
|
||||
|
||||
- for (;;) {
|
||||
- FD_ZERO(&fds);
|
||||
- FD_SET(fd, &fds);
|
||||
- maxfd = -1;
|
||||
- TAILQ_FOREACH(casserv, &casper_services, cs_next) {
|
||||
- /* We handle only core services. */
|
||||
- if (!CSERVICE_IS_CORE(casserv))
|
||||
- continue;
|
||||
- for (sconn = service_connection_first(casserv->cs_service);
|
||||
- sconn != NULL;
|
||||
- sconn = service_connection_next(sconn)) {
|
||||
- sock = service_connection_get_sock(sconn);
|
||||
- FD_SET(sock, &fds);
|
||||
- maxfd = sock > maxfd ? sock : maxfd;
|
||||
- }
|
||||
- }
|
||||
- if (maxfd == -1) {
|
||||
- /* Nothing to do. */
|
||||
- _exit(0);
|
||||
- }
|
||||
- maxfd++;
|
||||
-
|
||||
-
|
||||
- assert(maxfd <= (int)FD_SETSIZE);
|
||||
- ret = select(maxfd, &fds, NULL, NULL, NULL);
|
||||
- assert(ret == -1 || ret > 0); /* select() cannot timeout */
|
||||
- if (ret == -1) {
|
||||
- if (errno == EINTR)
|
||||
- continue;
|
||||
+ while (service_have_connections()) {
|
||||
+ if (!service_poll_dispatch())
|
||||
_exit(1);
|
||||
- }
|
||||
-
|
||||
- TAILQ_FOREACH(casserv, &casper_services, cs_next) {
|
||||
- /* We handle only core services. */
|
||||
- if (!CSERVICE_IS_CORE(casserv))
|
||||
- continue;
|
||||
- for (sconn = service_connection_first(casserv->cs_service);
|
||||
- sconn != NULL; sconn = sconntmp) {
|
||||
- /*
|
||||
- * Prepare for connection to be removed from
|
||||
- * the list on failure.
|
||||
- */
|
||||
- sconntmp = service_connection_next(sconn);
|
||||
- sock = service_connection_get_sock(sconn);
|
||||
- if (FD_ISSET(sock, &fds)) {
|
||||
- service_message(casserv->cs_service,
|
||||
- sconn);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
}
|
||||
+
|
||||
+ _exit(0);
|
||||
}
|
||||
--- lib/libcasper/libcasper/service.c.orig
|
||||
+++ lib/libcasper/libcasper/service.c
|
||||
@@ -30,8 +30,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
-#include <sys/cdefs.h>
|
||||
-#include <sys/types.h>
|
||||
+#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/nv.h>
|
||||
@@ -42,6 +41,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
+#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -72,7 +72,8 @@
|
||||
int sc_magic;
|
||||
cap_channel_t *sc_chan;
|
||||
nvlist_t *sc_limits;
|
||||
- TAILQ_ENTRY(service_connection) sc_next;
|
||||
+ struct service *sc_service;
|
||||
+ size_t sc_pollidx;
|
||||
};
|
||||
|
||||
#define SERVICE_MAGIC 0x5e91ce
|
||||
@@ -82,9 +83,90 @@
|
||||
uint64_t s_flags;
|
||||
service_limit_func_t *s_limit;
|
||||
service_command_func_t *s_command;
|
||||
- TAILQ_HEAD(, service_connection) s_connections;
|
||||
};
|
||||
|
||||
+#define POLLSET_CHUNK 8
|
||||
+static struct pollfd *pollset_pfds;
|
||||
+static struct service_connection **pollset_conns;
|
||||
+static size_t pollset_cap;
|
||||
+static size_t pollset_size;
|
||||
+
|
||||
+static int
|
||||
+pollset_add(struct service_connection *sconn, int sock)
|
||||
+{
|
||||
+ size_t i, newcap;
|
||||
+ void *p;
|
||||
+
|
||||
+ for (i = 0; i < pollset_size; i++) {
|
||||
+ if (pollset_pfds[i].fd < 0)
|
||||
+ break;
|
||||
+ }
|
||||
+ if (i == pollset_size) {
|
||||
+ newcap = roundup2(pollset_size + 1, POLLSET_CHUNK);
|
||||
+ if (newcap > pollset_cap) {
|
||||
+ p = reallocarray(pollset_pfds, newcap,
|
||||
+ sizeof(*pollset_pfds));
|
||||
+ if (p == NULL)
|
||||
+ return (-1);
|
||||
+ pollset_pfds = p;
|
||||
+ p = reallocarray(pollset_conns, newcap,
|
||||
+ sizeof(*pollset_conns));
|
||||
+ if (p == NULL)
|
||||
+ return (-1);
|
||||
+ pollset_conns = p;
|
||||
+ pollset_cap = newcap;
|
||||
+ }
|
||||
+ pollset_size++;
|
||||
+ }
|
||||
+ pollset_pfds[i].fd = sock;
|
||||
+ pollset_pfds[i].events = POLLIN;
|
||||
+ pollset_pfds[i].revents = 0;
|
||||
+ pollset_conns[i] = sconn;
|
||||
+ sconn->sc_pollidx = i;
|
||||
+ return (0);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+pollset_remove(struct service_connection *sconn)
|
||||
+{
|
||||
+
|
||||
+ pollset_pfds[sconn->sc_pollidx].fd = -1;
|
||||
+ pollset_conns[sconn->sc_pollidx] = NULL;
|
||||
+}
|
||||
+
|
||||
+bool
|
||||
+service_have_connections(void)
|
||||
+{
|
||||
+ size_t i;
|
||||
+
|
||||
+ for (i = 0; i < pollset_size; i++) {
|
||||
+ if (pollset_pfds[i].fd >= 0)
|
||||
+ return (true);
|
||||
+ }
|
||||
+ return (false);
|
||||
+}
|
||||
+
|
||||
+bool
|
||||
+service_poll_dispatch(void)
|
||||
+{
|
||||
+ size_t i;
|
||||
+ int ret;
|
||||
+
|
||||
+ do {
|
||||
+ ret = poll(pollset_pfds, pollset_size, -1);
|
||||
+ } while (ret == -1 && errno == EINTR);
|
||||
+ if (ret == -1)
|
||||
+ return (false);
|
||||
+
|
||||
+ for (i = 0; i < pollset_size; i++) {
|
||||
+ if (pollset_pfds[i].revents == 0)
|
||||
+ continue;
|
||||
+ service_message(pollset_conns[i]->sc_service,
|
||||
+ pollset_conns[i]);
|
||||
+ }
|
||||
+ return (true);
|
||||
+}
|
||||
+
|
||||
struct service *
|
||||
service_alloc(const char *name, service_limit_func_t *limitfunc,
|
||||
service_command_func_t *commandfunc, uint64_t flags)
|
||||
@@ -102,7 +184,6 @@
|
||||
service->s_limit = limitfunc;
|
||||
service->s_command = commandfunc;
|
||||
service->s_flags = flags;
|
||||
- TAILQ_INIT(&service->s_connections);
|
||||
service->s_magic = SERVICE_MAGIC;
|
||||
|
||||
return (service);
|
||||
@@ -111,13 +192,16 @@
|
||||
void
|
||||
service_free(struct service *service)
|
||||
{
|
||||
- struct service_connection *sconn;
|
||||
+ size_t i;
|
||||
|
||||
assert(service->s_magic == SERVICE_MAGIC);
|
||||
|
||||
service->s_magic = 0;
|
||||
- while ((sconn = service_connection_first(service)) != NULL)
|
||||
- service_connection_remove(service, sconn);
|
||||
+ for (i = 0; i < pollset_size; i++) {
|
||||
+ if (pollset_conns[i] != NULL &&
|
||||
+ pollset_conns[i]->sc_service == service)
|
||||
+ service_connection_remove(service, pollset_conns[i]);
|
||||
+ }
|
||||
free(service->s_name);
|
||||
free(service);
|
||||
}
|
||||
@@ -154,8 +238,16 @@
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
+ sconn->sc_service = service;
|
||||
+ if (pollset_add(sconn, sock) == -1) {
|
||||
+ serrno = errno;
|
||||
+ nvlist_destroy(sconn->sc_limits);
|
||||
+ (void)cap_unwrap(sconn->sc_chan, NULL);
|
||||
+ free(sconn);
|
||||
+ errno = serrno;
|
||||
+ return (NULL);
|
||||
+ }
|
||||
sconn->sc_magic = SERVICE_CONNECTION_MAGIC;
|
||||
- TAILQ_INSERT_TAIL(&service->s_connections, sconn, sc_next);
|
||||
return (sconn);
|
||||
}
|
||||
|
||||
@@ -167,7 +259,7 @@
|
||||
assert(service->s_magic == SERVICE_MAGIC);
|
||||
assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
|
||||
|
||||
- TAILQ_REMOVE(&service->s_connections, sconn, sc_next);
|
||||
+ pollset_remove(sconn);
|
||||
sconn->sc_magic = 0;
|
||||
nvlist_destroy(sconn->sc_limits);
|
||||
cap_close(sconn->sc_chan);
|
||||
@@ -197,31 +289,6 @@
|
||||
return (sock[1]);
|
||||
}
|
||||
|
||||
-struct service_connection *
|
||||
-service_connection_first(struct service *service)
|
||||
-{
|
||||
- struct service_connection *sconn;
|
||||
-
|
||||
- assert(service->s_magic == SERVICE_MAGIC);
|
||||
-
|
||||
- sconn = TAILQ_FIRST(&service->s_connections);
|
||||
- assert(sconn == NULL ||
|
||||
- sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
|
||||
- return (sconn);
|
||||
-}
|
||||
-
|
||||
-struct service_connection *
|
||||
-service_connection_next(struct service_connection *sconn)
|
||||
-{
|
||||
-
|
||||
- assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
|
||||
-
|
||||
- sconn = TAILQ_NEXT(sconn, sc_next);
|
||||
- assert(sconn == NULL ||
|
||||
- sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
|
||||
- return (sconn);
|
||||
-}
|
||||
-
|
||||
cap_channel_t *
|
||||
service_connection_get_chan(const struct service_connection *sconn)
|
||||
{
|
||||
@@ -330,14 +397,6 @@
|
||||
nvlist_destroy(nvlout);
|
||||
}
|
||||
|
||||
-static int
|
||||
-fd_add(fd_set *fdsp, int maxfd, int fd)
|
||||
-{
|
||||
-
|
||||
- FD_SET(fd, fdsp);
|
||||
- return (fd > maxfd ? fd : maxfd);
|
||||
-}
|
||||
-
|
||||
const char *
|
||||
service_name(struct service *service)
|
||||
{
|
||||
@@ -418,9 +477,6 @@
|
||||
void
|
||||
service_start(struct service *service, int sock, int procfd)
|
||||
{
|
||||
- struct service_connection *sconn, *sconntmp;
|
||||
- fd_set fds;
|
||||
- int maxfd, nfds;
|
||||
|
||||
assert(service != NULL);
|
||||
assert(service->s_magic == SERVICE_MAGIC);
|
||||
@@ -430,43 +486,9 @@
|
||||
if (service_connection_add(service, sock, NULL) == NULL)
|
||||
_exit(1);
|
||||
|
||||
- for (;;) {
|
||||
- FD_ZERO(&fds);
|
||||
- maxfd = -1;
|
||||
- for (sconn = service_connection_first(service); sconn != NULL;
|
||||
- sconn = service_connection_next(sconn)) {
|
||||
- maxfd = fd_add(&fds, maxfd,
|
||||
- service_connection_get_sock(sconn));
|
||||
- }
|
||||
-
|
||||
- assert(maxfd >= 0);
|
||||
- assert(maxfd + 1 <= (int)FD_SETSIZE);
|
||||
- nfds = select(maxfd + 1, &fds, NULL, NULL, NULL);
|
||||
- if (nfds < 0) {
|
||||
- if (errno != EINTR)
|
||||
- _exit(1);
|
||||
- continue;
|
||||
- } else if (nfds == 0) {
|
||||
- /* Timeout. */
|
||||
- abort();
|
||||
- }
|
||||
-
|
||||
- for (sconn = service_connection_first(service); sconn != NULL;
|
||||
- sconn = sconntmp) {
|
||||
- /*
|
||||
- * Prepare for connection to be removed from the list
|
||||
- * on failure.
|
||||
- */
|
||||
- sconntmp = service_connection_next(sconn);
|
||||
- if (FD_ISSET(service_connection_get_sock(sconn), &fds))
|
||||
- service_message(service, sconn);
|
||||
- }
|
||||
- if (service_connection_first(service) == NULL) {
|
||||
- /*
|
||||
- * No connections left, exiting.
|
||||
- */
|
||||
- break;
|
||||
- }
|
||||
+ while (service_have_connections()) {
|
||||
+ if (!service_poll_dispatch())
|
||||
+ _exit(1);
|
||||
}
|
||||
|
||||
_exit(0);
|
||||
--- lib/libcasper/tests/Makefile.orig
|
||||
+++ lib/libcasper/tests/Makefile
|
||||
@@ -1,5 +1,13 @@
|
||||
+.include <src.opts.mk>
|
||||
|
||||
-.PATH: ${SRCTOP}/tests
|
||||
-KYUAFILE= yes
|
||||
+PACKAGE= tests
|
||||
+
|
||||
+ATF_TESTS_C= cap_main_test
|
||||
+
|
||||
+.if ${MK_CASPER} != "no"
|
||||
+LIBADD+= casper
|
||||
+CFLAGS+= -DWITH_CASPER
|
||||
+.endif
|
||||
+LIBADD+= nv
|
||||
|
||||
.include <bsd.test.mk>
|
||||
--- /dev/null
|
||||
+++ lib/libcasper/tests/cap_main_test.c
|
||||
@@ -0,0 +1,142 @@
|
||||
+/*-
|
||||
+ * SPDX-License-Identifier: BSD-2-Clause
|
||||
+ *
|
||||
+ * Copyright (c) 2026 Mariusz Zaborski <oshogbo@FreeBSD.org>
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions
|
||||
+ * are met:
|
||||
+ * 1. Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ * 2. Redistributions in binary form must reproduce the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer in the
|
||||
+ * documentation and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
+ * SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+#include <sys/resource.h>
|
||||
+#include <sys/select.h>
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <inttypes.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <libcasper.h>
|
||||
+
|
||||
+#include <atf-c.h>
|
||||
+
|
||||
+#define NCONNECTIONS (FD_SETSIZE + 64)
|
||||
+#define FD_HEADROOM 64
|
||||
+
|
||||
+/* Test that file descriptors past FD_SETSIZE (1024) work. */
|
||||
+ATF_TC_WITHOUT_HEAD(many_connections);
|
||||
+ATF_TC_BODY(many_connections, tc)
|
||||
+{
|
||||
+ struct rlimit rl;
|
||||
+ cap_channel_t *chan;
|
||||
+ cap_channel_t **clones;
|
||||
+ size_t i;
|
||||
+
|
||||
+ if (getrlimit(RLIMIT_NOFILE, &rl) != 0)
|
||||
+ atf_tc_skip("getrlimit: %s", strerror(errno));
|
||||
+ if (rl.rlim_max < NCONNECTIONS + FD_HEADROOM)
|
||||
+ atf_tc_skip("RLIMIT_NOFILE hard cap %ju below required %d",
|
||||
+ (uintmax_t)rl.rlim_max, NCONNECTIONS + FD_HEADROOM);
|
||||
+ rl.rlim_cur = rl.rlim_max;
|
||||
+ ATF_REQUIRE_MSG(setrlimit(RLIMIT_NOFILE, &rl) == 0,
|
||||
+ "setrlimit: %s", strerror(errno));
|
||||
+
|
||||
+ chan = cap_init();
|
||||
+ ATF_REQUIRE_MSG(chan != NULL, "cap_init failed: %s", strerror(errno));
|
||||
+
|
||||
+ clones = calloc(NCONNECTIONS, sizeof(*clones));
|
||||
+ ATF_REQUIRE(clones != NULL);
|
||||
+
|
||||
+ /*
|
||||
+ * Every cap_clone(3) adds one more connection to the helper.
|
||||
+ * After this loop the helper is watching more fds than an
|
||||
+ * fd_set can hold.
|
||||
+ */
|
||||
+ for (i = 0; i < NCONNECTIONS; i++) {
|
||||
+ clones[i] = cap_clone(chan);
|
||||
+ ATF_REQUIRE_MSG(clones[i] != NULL,
|
||||
+ "cap_clone failed at %zu/%d: %s",
|
||||
+ i, NCONNECTIONS, strerror(errno));
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < NCONNECTIONS; i++)
|
||||
+ cap_close(clones[i]);
|
||||
+ free(clones);
|
||||
+ cap_close(chan);
|
||||
+}
|
||||
+
|
||||
+#define CHURN_CONNECTIONS 50
|
||||
+#define CHURN_CLOSE_STEP 5
|
||||
+
|
||||
+/* Test that gaps in the file descriptor list do not break casper. */
|
||||
+ATF_TC_WITHOUT_HEAD(connection_churn);
|
||||
+ATF_TC_BODY(connection_churn, tc)
|
||||
+{
|
||||
+ cap_channel_t *chan, *survivor, *extra;
|
||||
+ cap_channel_t *clones[CHURN_CONNECTIONS];
|
||||
+ size_t i, survivor_idx;
|
||||
+
|
||||
+ chan = cap_init();
|
||||
+ ATF_REQUIRE_MSG(chan != NULL, "cap_init failed: %s", strerror(errno));
|
||||
+
|
||||
+ for (i = 0; i < CHURN_CONNECTIONS; i++) {
|
||||
+ clones[i] = cap_clone(chan);
|
||||
+ ATF_REQUIRE_MSG(clones[i] != NULL,
|
||||
+ "cap_clone failed at %zu: %s", i, strerror(errno));
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Close every Nth clone.
|
||||
+ */
|
||||
+ for (i = 0; i < CHURN_CONNECTIONS; i += CHURN_CLOSE_STEP) {
|
||||
+ cap_close(clones[i]);
|
||||
+ clones[i] = NULL;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Force a poll() cycle: the helper handles POLLIN on chan and
|
||||
+ * POLLHUP on the closed clones in the same walk.
|
||||
+ */
|
||||
+ extra = cap_clone(chan);
|
||||
+ ATF_REQUIRE_MSG(extra != NULL, "cap_clone after churn failed: %s",
|
||||
+ strerror(errno));
|
||||
+
|
||||
+ /* A surviving clone must still round-trip. */
|
||||
+ survivor_idx = 1;
|
||||
+ survivor = cap_clone(clones[survivor_idx]);
|
||||
+ ATF_REQUIRE_MSG(survivor != NULL,
|
||||
+ "cap_clone on survivor failed: %s", strerror(errno));
|
||||
+
|
||||
+ cap_close(survivor);
|
||||
+ cap_close(extra);
|
||||
+ for (i = 0; i < CHURN_CONNECTIONS; i++) {
|
||||
+ if (clones[i] != NULL)
|
||||
+ cap_close(clones[i]);
|
||||
+ }
|
||||
+ cap_close(chan);
|
||||
+}
|
||||
+
|
||||
+ATF_TP_ADD_TCS(tp)
|
||||
+{
|
||||
+
|
||||
+ ATF_TP_ADD_TC(tp, many_connections);
|
||||
+ ATF_TP_ADD_TC(tp, connection_churn);
|
||||
+ return (atf_no_error());
|
||||
+}
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKH0bFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvE1wQAIFN2hAU+76Vf5P6J1w9
|
||||
ERxUl9XWB+9e+KCvpJzVprwpM6sLm3/04snX5J3dk3/GJ7ngYEmwO0K8fqF8pqTI
|
||||
N040UkRk0pIdNPmfzrGZO7vbPhdJeLgiCozzS4x8NLVY297S7pD7chLqw42noJlu
|
||||
qZ+RLbaBz+5jeyLnO5y4x40GYuUrQPkD3ksRMr9MXDrN/VJZp48mEBc5fpTe+dTG
|
||||
Ina5PB33C70V/Hu7KtPYCvEMhT139ZY/X6zBXJWkFac+yy5Iw5XpQGgtxmiU53ti
|
||||
Rfjg1h3lC/mQD1lIvdDBXxhwASqbiqKLBjtl2j+HJbXTw6F1STHr3fl2stPcRu5O
|
||||
e4cTEfULoraVKhvUa2/rVc3O9UiWT6ttJeqiLSFLMPje+EzsRRPv7BURIgjCX4ZO
|
||||
XbaAS0lPr49tqhDssSN8V4EUaRe4cJm1/bB+1xydpEKmm/5lbvQyA3GMyKau4jEH
|
||||
85/E6d6oi0LOK4o5V89tSo0kNiozWHe/uHcZqLCS0FNHtjAhrky+EynKlBD8aQED
|
||||
IA+O1RJnFENxG8R6aC290KCDupYG3LBxXavYxm8RA5fIStvQX2srpRoUuCAEh9Dr
|
||||
Nwv+nHZZK4yRssf04uwurf/3SUvuOt06fCkzkQxdFByxgjEVFw2LukYaIExtVYH8
|
||||
czK6p++bNvfTzQNAx+Mx/4zS
|
||||
=hxFw
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,538 @@
|
||||
--- lib/libcasper/libcasper/libcasper_impl.h.orig
|
||||
+++ lib/libcasper/libcasper/libcasper_impl.h
|
||||
@@ -54,6 +54,8 @@
|
||||
void service_start(struct service *service, int sock, int procfd);
|
||||
const char *service_name(struct service *service);
|
||||
int service_get_channel_flags(struct service *service);
|
||||
+bool service_have_connections(void);
|
||||
+bool service_poll_dispatch(void);
|
||||
|
||||
/* Private service connection functions. */
|
||||
struct service_connection *service_connection_add(struct service *service,
|
||||
@@ -64,10 +66,6 @@
|
||||
int service_connection_clone(
|
||||
struct service *service,
|
||||
struct service_connection *sconn);
|
||||
-struct service_connection *service_connection_first(
|
||||
- struct service *service);
|
||||
-struct service_connection *service_connection_next(
|
||||
- struct service_connection *sconn);
|
||||
cap_channel_t *service_connection_get_chan(
|
||||
const struct service_connection *sconn);
|
||||
int service_connection_get_sock(
|
||||
--- lib/libcasper/libcasper/libcasper_service.c.orig
|
||||
+++ lib/libcasper/libcasper/libcasper_service.c
|
||||
@@ -222,10 +222,6 @@
|
||||
void
|
||||
casper_main_loop(int fd)
|
||||
{
|
||||
- fd_set fds;
|
||||
- struct casper_service *casserv;
|
||||
- struct service_connection *sconn, *sconntmp;
|
||||
- int sock, maxfd, ret;
|
||||
|
||||
if (zygote_init() < 0)
|
||||
_exit(1);
|
||||
@@ -235,55 +231,10 @@
|
||||
*/
|
||||
service_register_core(fd);
|
||||
|
||||
- for (;;) {
|
||||
- FD_ZERO(&fds);
|
||||
- FD_SET(fd, &fds);
|
||||
- maxfd = -1;
|
||||
- TAILQ_FOREACH(casserv, &casper_services, cs_next) {
|
||||
- /* We handle only core services. */
|
||||
- if (!CSERVICE_IS_CORE(casserv))
|
||||
- continue;
|
||||
- for (sconn = service_connection_first(casserv->cs_service);
|
||||
- sconn != NULL;
|
||||
- sconn = service_connection_next(sconn)) {
|
||||
- sock = service_connection_get_sock(sconn);
|
||||
- FD_SET(sock, &fds);
|
||||
- maxfd = sock > maxfd ? sock : maxfd;
|
||||
- }
|
||||
- }
|
||||
- if (maxfd == -1) {
|
||||
- /* Nothing to do. */
|
||||
- _exit(0);
|
||||
- }
|
||||
- maxfd++;
|
||||
-
|
||||
-
|
||||
- assert(maxfd <= (int)FD_SETSIZE);
|
||||
- ret = select(maxfd, &fds, NULL, NULL, NULL);
|
||||
- assert(ret == -1 || ret > 0); /* select() cannot timeout */
|
||||
- if (ret == -1) {
|
||||
- if (errno == EINTR)
|
||||
- continue;
|
||||
+ while (service_have_connections()) {
|
||||
+ if (!service_poll_dispatch())
|
||||
_exit(1);
|
||||
- }
|
||||
-
|
||||
- TAILQ_FOREACH(casserv, &casper_services, cs_next) {
|
||||
- /* We handle only core services. */
|
||||
- if (!CSERVICE_IS_CORE(casserv))
|
||||
- continue;
|
||||
- for (sconn = service_connection_first(casserv->cs_service);
|
||||
- sconn != NULL; sconn = sconntmp) {
|
||||
- /*
|
||||
- * Prepare for connection to be removed from
|
||||
- * the list on failure.
|
||||
- */
|
||||
- sconntmp = service_connection_next(sconn);
|
||||
- sock = service_connection_get_sock(sconn);
|
||||
- if (FD_ISSET(sock, &fds)) {
|
||||
- service_message(casserv->cs_service,
|
||||
- sconn);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
}
|
||||
+
|
||||
+ _exit(0);
|
||||
}
|
||||
--- lib/libcasper/libcasper/service.c.orig
|
||||
+++ lib/libcasper/libcasper/service.c
|
||||
@@ -30,7 +30,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
-#include <sys/types.h>
|
||||
+#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/nv.h>
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
+#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -71,7 +72,8 @@
|
||||
int sc_magic;
|
||||
cap_channel_t *sc_chan;
|
||||
nvlist_t *sc_limits;
|
||||
- TAILQ_ENTRY(service_connection) sc_next;
|
||||
+ struct service *sc_service;
|
||||
+ size_t sc_pollidx;
|
||||
};
|
||||
|
||||
#define SERVICE_MAGIC 0x5e91ce
|
||||
@@ -81,9 +83,90 @@
|
||||
uint64_t s_flags;
|
||||
service_limit_func_t *s_limit;
|
||||
service_command_func_t *s_command;
|
||||
- TAILQ_HEAD(, service_connection) s_connections;
|
||||
};
|
||||
|
||||
+#define POLLSET_CHUNK 8
|
||||
+static struct pollfd *pollset_pfds;
|
||||
+static struct service_connection **pollset_conns;
|
||||
+static size_t pollset_cap;
|
||||
+static size_t pollset_size;
|
||||
+
|
||||
+static int
|
||||
+pollset_add(struct service_connection *sconn, int sock)
|
||||
+{
|
||||
+ size_t i, newcap;
|
||||
+ void *p;
|
||||
+
|
||||
+ for (i = 0; i < pollset_size; i++) {
|
||||
+ if (pollset_pfds[i].fd < 0)
|
||||
+ break;
|
||||
+ }
|
||||
+ if (i == pollset_size) {
|
||||
+ newcap = roundup2(pollset_size + 1, POLLSET_CHUNK);
|
||||
+ if (newcap > pollset_cap) {
|
||||
+ p = reallocarray(pollset_pfds, newcap,
|
||||
+ sizeof(*pollset_pfds));
|
||||
+ if (p == NULL)
|
||||
+ return (-1);
|
||||
+ pollset_pfds = p;
|
||||
+ p = reallocarray(pollset_conns, newcap,
|
||||
+ sizeof(*pollset_conns));
|
||||
+ if (p == NULL)
|
||||
+ return (-1);
|
||||
+ pollset_conns = p;
|
||||
+ pollset_cap = newcap;
|
||||
+ }
|
||||
+ pollset_size++;
|
||||
+ }
|
||||
+ pollset_pfds[i].fd = sock;
|
||||
+ pollset_pfds[i].events = POLLIN;
|
||||
+ pollset_pfds[i].revents = 0;
|
||||
+ pollset_conns[i] = sconn;
|
||||
+ sconn->sc_pollidx = i;
|
||||
+ return (0);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+pollset_remove(struct service_connection *sconn)
|
||||
+{
|
||||
+
|
||||
+ pollset_pfds[sconn->sc_pollidx].fd = -1;
|
||||
+ pollset_conns[sconn->sc_pollidx] = NULL;
|
||||
+}
|
||||
+
|
||||
+bool
|
||||
+service_have_connections(void)
|
||||
+{
|
||||
+ size_t i;
|
||||
+
|
||||
+ for (i = 0; i < pollset_size; i++) {
|
||||
+ if (pollset_pfds[i].fd >= 0)
|
||||
+ return (true);
|
||||
+ }
|
||||
+ return (false);
|
||||
+}
|
||||
+
|
||||
+bool
|
||||
+service_poll_dispatch(void)
|
||||
+{
|
||||
+ size_t i;
|
||||
+ int ret;
|
||||
+
|
||||
+ do {
|
||||
+ ret = poll(pollset_pfds, pollset_size, -1);
|
||||
+ } while (ret == -1 && errno == EINTR);
|
||||
+ if (ret == -1)
|
||||
+ return (false);
|
||||
+
|
||||
+ for (i = 0; i < pollset_size; i++) {
|
||||
+ if (pollset_pfds[i].revents == 0)
|
||||
+ continue;
|
||||
+ service_message(pollset_conns[i]->sc_service,
|
||||
+ pollset_conns[i]);
|
||||
+ }
|
||||
+ return (true);
|
||||
+}
|
||||
+
|
||||
struct service *
|
||||
service_alloc(const char *name, service_limit_func_t *limitfunc,
|
||||
service_command_func_t *commandfunc, uint64_t flags)
|
||||
@@ -101,7 +184,6 @@
|
||||
service->s_limit = limitfunc;
|
||||
service->s_command = commandfunc;
|
||||
service->s_flags = flags;
|
||||
- TAILQ_INIT(&service->s_connections);
|
||||
service->s_magic = SERVICE_MAGIC;
|
||||
|
||||
return (service);
|
||||
@@ -110,13 +192,16 @@
|
||||
void
|
||||
service_free(struct service *service)
|
||||
{
|
||||
- struct service_connection *sconn;
|
||||
+ size_t i;
|
||||
|
||||
assert(service->s_magic == SERVICE_MAGIC);
|
||||
|
||||
service->s_magic = 0;
|
||||
- while ((sconn = service_connection_first(service)) != NULL)
|
||||
- service_connection_remove(service, sconn);
|
||||
+ for (i = 0; i < pollset_size; i++) {
|
||||
+ if (pollset_conns[i] != NULL &&
|
||||
+ pollset_conns[i]->sc_service == service)
|
||||
+ service_connection_remove(service, pollset_conns[i]);
|
||||
+ }
|
||||
free(service->s_name);
|
||||
free(service);
|
||||
}
|
||||
@@ -153,8 +238,16 @@
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
+ sconn->sc_service = service;
|
||||
+ if (pollset_add(sconn, sock) == -1) {
|
||||
+ serrno = errno;
|
||||
+ nvlist_destroy(sconn->sc_limits);
|
||||
+ (void)cap_unwrap(sconn->sc_chan, NULL);
|
||||
+ free(sconn);
|
||||
+ errno = serrno;
|
||||
+ return (NULL);
|
||||
+ }
|
||||
sconn->sc_magic = SERVICE_CONNECTION_MAGIC;
|
||||
- TAILQ_INSERT_TAIL(&service->s_connections, sconn, sc_next);
|
||||
return (sconn);
|
||||
}
|
||||
|
||||
@@ -166,7 +259,7 @@
|
||||
assert(service->s_magic == SERVICE_MAGIC);
|
||||
assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
|
||||
|
||||
- TAILQ_REMOVE(&service->s_connections, sconn, sc_next);
|
||||
+ pollset_remove(sconn);
|
||||
sconn->sc_magic = 0;
|
||||
nvlist_destroy(sconn->sc_limits);
|
||||
cap_close(sconn->sc_chan);
|
||||
@@ -196,31 +289,6 @@
|
||||
return (sock[1]);
|
||||
}
|
||||
|
||||
-struct service_connection *
|
||||
-service_connection_first(struct service *service)
|
||||
-{
|
||||
- struct service_connection *sconn;
|
||||
-
|
||||
- assert(service->s_magic == SERVICE_MAGIC);
|
||||
-
|
||||
- sconn = TAILQ_FIRST(&service->s_connections);
|
||||
- assert(sconn == NULL ||
|
||||
- sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
|
||||
- return (sconn);
|
||||
-}
|
||||
-
|
||||
-struct service_connection *
|
||||
-service_connection_next(struct service_connection *sconn)
|
||||
-{
|
||||
-
|
||||
- assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
|
||||
-
|
||||
- sconn = TAILQ_NEXT(sconn, sc_next);
|
||||
- assert(sconn == NULL ||
|
||||
- sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
|
||||
- return (sconn);
|
||||
-}
|
||||
-
|
||||
cap_channel_t *
|
||||
service_connection_get_chan(const struct service_connection *sconn)
|
||||
{
|
||||
@@ -329,14 +397,6 @@
|
||||
nvlist_destroy(nvlout);
|
||||
}
|
||||
|
||||
-static int
|
||||
-fd_add(fd_set *fdsp, int maxfd, int fd)
|
||||
-{
|
||||
-
|
||||
- FD_SET(fd, fdsp);
|
||||
- return (fd > maxfd ? fd : maxfd);
|
||||
-}
|
||||
-
|
||||
const char *
|
||||
service_name(struct service *service)
|
||||
{
|
||||
@@ -417,9 +477,6 @@
|
||||
void
|
||||
service_start(struct service *service, int sock, int procfd)
|
||||
{
|
||||
- struct service_connection *sconn, *sconntmp;
|
||||
- fd_set fds;
|
||||
- int maxfd, nfds;
|
||||
|
||||
assert(service != NULL);
|
||||
assert(service->s_magic == SERVICE_MAGIC);
|
||||
@@ -429,43 +486,9 @@
|
||||
if (service_connection_add(service, sock, NULL) == NULL)
|
||||
_exit(1);
|
||||
|
||||
- for (;;) {
|
||||
- FD_ZERO(&fds);
|
||||
- maxfd = -1;
|
||||
- for (sconn = service_connection_first(service); sconn != NULL;
|
||||
- sconn = service_connection_next(sconn)) {
|
||||
- maxfd = fd_add(&fds, maxfd,
|
||||
- service_connection_get_sock(sconn));
|
||||
- }
|
||||
-
|
||||
- assert(maxfd >= 0);
|
||||
- assert(maxfd + 1 <= (int)FD_SETSIZE);
|
||||
- nfds = select(maxfd + 1, &fds, NULL, NULL, NULL);
|
||||
- if (nfds < 0) {
|
||||
- if (errno != EINTR)
|
||||
- _exit(1);
|
||||
- continue;
|
||||
- } else if (nfds == 0) {
|
||||
- /* Timeout. */
|
||||
- abort();
|
||||
- }
|
||||
-
|
||||
- for (sconn = service_connection_first(service); sconn != NULL;
|
||||
- sconn = sconntmp) {
|
||||
- /*
|
||||
- * Prepare for connection to be removed from the list
|
||||
- * on failure.
|
||||
- */
|
||||
- sconntmp = service_connection_next(sconn);
|
||||
- if (FD_ISSET(service_connection_get_sock(sconn), &fds))
|
||||
- service_message(service, sconn);
|
||||
- }
|
||||
- if (service_connection_first(service) == NULL) {
|
||||
- /*
|
||||
- * No connections left, exiting.
|
||||
- */
|
||||
- break;
|
||||
- }
|
||||
+ while (service_have_connections()) {
|
||||
+ if (!service_poll_dispatch())
|
||||
+ _exit(1);
|
||||
}
|
||||
|
||||
_exit(0);
|
||||
--- lib/libcasper/tests/Makefile.orig
|
||||
+++ lib/libcasper/tests/Makefile
|
||||
@@ -1,6 +1,13 @@
|
||||
-.PATH: ${SRCTOP}/tests
|
||||
+.include <src.opts.mk>
|
||||
|
||||
PACKAGE= tests
|
||||
-KYUAFILE= yes
|
||||
+
|
||||
+ATF_TESTS_C= cap_main_test
|
||||
+
|
||||
+.if ${MK_CASPER} != "no"
|
||||
+LIBADD+= casper
|
||||
+CFLAGS+= -DWITH_CASPER
|
||||
+.endif
|
||||
+LIBADD+= nv
|
||||
|
||||
.include <bsd.test.mk>
|
||||
--- /dev/null
|
||||
+++ lib/libcasper/tests/cap_main_test.c
|
||||
@@ -0,0 +1,142 @@
|
||||
+/*-
|
||||
+ * SPDX-License-Identifier: BSD-2-Clause
|
||||
+ *
|
||||
+ * Copyright (c) 2026 Mariusz Zaborski <oshogbo@FreeBSD.org>
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions
|
||||
+ * are met:
|
||||
+ * 1. Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ * 2. Redistributions in binary form must reproduce the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer in the
|
||||
+ * documentation and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
+ * SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+#include <sys/resource.h>
|
||||
+#include <sys/select.h>
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <inttypes.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <libcasper.h>
|
||||
+
|
||||
+#include <atf-c.h>
|
||||
+
|
||||
+#define NCONNECTIONS (FD_SETSIZE + 64)
|
||||
+#define FD_HEADROOM 64
|
||||
+
|
||||
+/* Test that file descriptors past FD_SETSIZE (1024) work. */
|
||||
+ATF_TC_WITHOUT_HEAD(many_connections);
|
||||
+ATF_TC_BODY(many_connections, tc)
|
||||
+{
|
||||
+ struct rlimit rl;
|
||||
+ cap_channel_t *chan;
|
||||
+ cap_channel_t **clones;
|
||||
+ size_t i;
|
||||
+
|
||||
+ if (getrlimit(RLIMIT_NOFILE, &rl) != 0)
|
||||
+ atf_tc_skip("getrlimit: %s", strerror(errno));
|
||||
+ if (rl.rlim_max < NCONNECTIONS + FD_HEADROOM)
|
||||
+ atf_tc_skip("RLIMIT_NOFILE hard cap %ju below required %d",
|
||||
+ (uintmax_t)rl.rlim_max, NCONNECTIONS + FD_HEADROOM);
|
||||
+ rl.rlim_cur = rl.rlim_max;
|
||||
+ ATF_REQUIRE_MSG(setrlimit(RLIMIT_NOFILE, &rl) == 0,
|
||||
+ "setrlimit: %s", strerror(errno));
|
||||
+
|
||||
+ chan = cap_init();
|
||||
+ ATF_REQUIRE_MSG(chan != NULL, "cap_init failed: %s", strerror(errno));
|
||||
+
|
||||
+ clones = calloc(NCONNECTIONS, sizeof(*clones));
|
||||
+ ATF_REQUIRE(clones != NULL);
|
||||
+
|
||||
+ /*
|
||||
+ * Every cap_clone(3) adds one more connection to the helper.
|
||||
+ * After this loop the helper is watching more fds than an
|
||||
+ * fd_set can hold.
|
||||
+ */
|
||||
+ for (i = 0; i < NCONNECTIONS; i++) {
|
||||
+ clones[i] = cap_clone(chan);
|
||||
+ ATF_REQUIRE_MSG(clones[i] != NULL,
|
||||
+ "cap_clone failed at %zu/%d: %s",
|
||||
+ i, NCONNECTIONS, strerror(errno));
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < NCONNECTIONS; i++)
|
||||
+ cap_close(clones[i]);
|
||||
+ free(clones);
|
||||
+ cap_close(chan);
|
||||
+}
|
||||
+
|
||||
+#define CHURN_CONNECTIONS 50
|
||||
+#define CHURN_CLOSE_STEP 5
|
||||
+
|
||||
+/* Test that gaps in the file descriptor list do not break casper. */
|
||||
+ATF_TC_WITHOUT_HEAD(connection_churn);
|
||||
+ATF_TC_BODY(connection_churn, tc)
|
||||
+{
|
||||
+ cap_channel_t *chan, *survivor, *extra;
|
||||
+ cap_channel_t *clones[CHURN_CONNECTIONS];
|
||||
+ size_t i, survivor_idx;
|
||||
+
|
||||
+ chan = cap_init();
|
||||
+ ATF_REQUIRE_MSG(chan != NULL, "cap_init failed: %s", strerror(errno));
|
||||
+
|
||||
+ for (i = 0; i < CHURN_CONNECTIONS; i++) {
|
||||
+ clones[i] = cap_clone(chan);
|
||||
+ ATF_REQUIRE_MSG(clones[i] != NULL,
|
||||
+ "cap_clone failed at %zu: %s", i, strerror(errno));
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Close every Nth clone.
|
||||
+ */
|
||||
+ for (i = 0; i < CHURN_CONNECTIONS; i += CHURN_CLOSE_STEP) {
|
||||
+ cap_close(clones[i]);
|
||||
+ clones[i] = NULL;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Force a poll() cycle: the helper handles POLLIN on chan and
|
||||
+ * POLLHUP on the closed clones in the same walk.
|
||||
+ */
|
||||
+ extra = cap_clone(chan);
|
||||
+ ATF_REQUIRE_MSG(extra != NULL, "cap_clone after churn failed: %s",
|
||||
+ strerror(errno));
|
||||
+
|
||||
+ /* A surviving clone must still round-trip. */
|
||||
+ survivor_idx = 1;
|
||||
+ survivor = cap_clone(clones[survivor_idx]);
|
||||
+ ATF_REQUIRE_MSG(survivor != NULL,
|
||||
+ "cap_clone on survivor failed: %s", strerror(errno));
|
||||
+
|
||||
+ cap_close(survivor);
|
||||
+ cap_close(extra);
|
||||
+ for (i = 0; i < CHURN_CONNECTIONS; i++) {
|
||||
+ if (clones[i] != NULL)
|
||||
+ cap_close(clones[i]);
|
||||
+ }
|
||||
+ cap_close(chan);
|
||||
+}
|
||||
+
|
||||
+ATF_TP_ADD_TCS(tp)
|
||||
+{
|
||||
+
|
||||
+ ATF_TP_ADD_TC(tp, many_connections);
|
||||
+ ATF_TP_ADD_TC(tp, connection_churn);
|
||||
+ return (atf_no_error());
|
||||
+}
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKH4bFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrv3kEQAMJU7f++QUOGUqTiANS4
|
||||
69poIhn4KaawwwzRRblcMRVYVhBZoT92YJUOauXILbNsqQZjQ5K4kdW/mgBk3ivw
|
||||
v7P8y3Bc9t/ZWX4Z9tBB5KmmDhMKdShWTHaHZiCYliJGW+Yzaki/zPBJ+R3vPETd
|
||||
Cm/X8rvxjMh4tM9HTqaNCrT+DfjAYxS/CCi+mUaNKiP6tLSPAUWYfc2WtBY85OvS
|
||||
sRVxFBpFPtVwxuVM0XhAIBrPq9fIxILdT3bLi7Q85epLjstoXirCzEjpqhnYE/6m
|
||||
huyAZCe54qWt+ZhdiRwsLUV/Asom3cLlkuBv0c4QK4tfpZaQqyysAB8+QrNLZ7L8
|
||||
V+SnBu8RwEWlsviIf0aWkVnM/YKyoTPs3Wqm7yuWgMz0DuiVuNUs99wLWwDmeAwX
|
||||
2XA86LsLpi5MPgd7oX2Py4XUKtkiVS7zuKRYW/i5DqSCarUm+wV3v/5EoYwNHVmD
|
||||
P+Idbe9XkwwYYT+MIHmxYAi2E/jmCvp2RA724K/Iy10Nv0vKz4bbf69P9RPfSnrM
|
||||
d+H1A6o4LEo5tGS+gcln9rTyg3PME1fXGri1vLT8JJauTQfn1OV0KX2LsZKHAq1i
|
||||
O4P6M6iUuqupwEAOiqZ39olo241exOzsyP7mXPIwYtS1xi/npWEHrwz2rHEPvD2X
|
||||
XoXsfguRWHH1Gu7LatZ+XlFm
|
||||
=B6VF
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,102 @@
|
||||
--- usr.sbin/bsdconfig/share/media/wlan.subr.orig
|
||||
+++ usr.sbin/bsdconfig/share/media/wlan.subr
|
||||
@@ -813,6 +813,7 @@
|
||||
[ $nmatches -le ${#DIALOG_MENU_TAGS} ] || break
|
||||
f_substr -v tag "$DIALOG_MENU_TAGS" $nmatches 1
|
||||
|
||||
+ f_shell_escape "$wssid" wssid
|
||||
f_wireless_describe WIRELESS_$n help
|
||||
menu_list1="$menu_list1
|
||||
'$tag $wssid' '$wbssid' '$help'
|
||||
@@ -1076,6 +1077,7 @@
|
||||
while [ $n -lt $nunique ]; do
|
||||
n=$(( $n + 1 ))
|
||||
menuitem_$n get ssid ssid
|
||||
+ f_shell_escape "$ssid" ssid
|
||||
|
||||
menuitem_$n get nconfigs nconfigs
|
||||
desc="$nconfigs $msg_configured_lc"
|
||||
@@ -1184,6 +1186,7 @@
|
||||
while [ $n -lt $nunique ]; do
|
||||
n=$(( $n + 1 ))
|
||||
menuitem_$n get ssid ssid
|
||||
+ f_shell_escape "$ssid" ssid
|
||||
|
||||
desc=
|
||||
if [ "$DIALOG_MENU_WLAN_SHOW_ALL" ]; then
|
||||
--- usr.sbin/bsdinstall/scripts/wlanconfig.orig
|
||||
+++ usr.sbin/bsdinstall/scripts/wlanconfig
|
||||
@@ -147,6 +147,34 @@
|
||||
country_set "$regdomain" "$country"
|
||||
}
|
||||
|
||||
+dialog_network_select()
|
||||
+{
|
||||
+ local ssid flags height width rows prompt
|
||||
+
|
||||
+ # Avoid using eval on untrusted data.
|
||||
+ set --
|
||||
+ while IFS=$'\t' read -r ssid flags; do
|
||||
+ [ -n "$ssid" ] || continue
|
||||
+ set -- "$@" "$ssid" "$flags"
|
||||
+ done <<EOF
|
||||
+$NETWORKS
|
||||
+EOF
|
||||
+
|
||||
+ f_dialog_title "Network Selection"
|
||||
+ prompt="Select a wireless network to connect to."
|
||||
+ f_dialog_menu_size height width rows \
|
||||
+ "$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$prompt" "" "$@"
|
||||
+ $DIALOG \
|
||||
+ --title "$DIALOG_TITLE" \
|
||||
+ --backtitle "$DIALOG_BACKTITLE" \
|
||||
+ --extra-button \
|
||||
+ --extra-label "Rescan" \
|
||||
+ --menu "$prompt" \
|
||||
+ $height $width $rows \
|
||||
+ "$@" \
|
||||
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
|
||||
+}
|
||||
+
|
||||
############################################################ MAIN
|
||||
|
||||
: > "$BSDINSTALL_TMPETC/wpa_supplicant.conf"
|
||||
@@ -213,27 +241,14 @@
|
||||
|
||||
f_eval_catch -dk SCAN_RESULTS wlanconfig wpa_cli "wpa_cli scan_results"
|
||||
NETWORKS=$( echo "$SCAN_RESULTS" | awk -F '\t' '
|
||||
- /..:..:..:..:..:../ && $5 { printf "\"%s\"\t\"%s\"\n", $5, $4 }
|
||||
+ /..:..:..:..:..:../ && $5 { print $5 "\t" $4 }
|
||||
' | sort | uniq )
|
||||
|
||||
if [ ! "$NETWORKS" ]; then
|
||||
f_dialog_title "$msg_error"
|
||||
f_yesno "No wireless networks were found. Rescan?" && continue
|
||||
else
|
||||
- f_dialog_title "Network Selection"
|
||||
- prompt="Select a wireless network to connect to."
|
||||
- f_dialog_menu_size height width rows "$DIALOG_TITLE" \
|
||||
- "$DIALOG_BACKTITLE" "$prompt" "" $menu_list
|
||||
- NETWORK=$( eval $DIALOG \
|
||||
- --title \"\$DIALOG_TITLE\" \
|
||||
- --backtitle \"\$DIALOG_BACKTITLE\" \
|
||||
- --extra-button \
|
||||
- --extra-label \"Rescan\" \
|
||||
- --menu \"\$prompt\" \
|
||||
- $height $width $rows \
|
||||
- $NETWORKS \
|
||||
- 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
|
||||
- )
|
||||
+ NETWORK=$( dialog_network_select )
|
||||
fi
|
||||
retval=$?
|
||||
f_dialog_data_sanitize NETWORK
|
||||
@@ -270,7 +285,7 @@
|
||||
done
|
||||
|
||||
[ "$ENCRYPTION" ] || ENCRYPTION=$( echo "$NETWORKS" |
|
||||
- awk -F '\t' "/^\"$NETWORK\"\t/ { print \$2 }" )
|
||||
+ awk -F '\t' "/^$NETWORK\t/ { print \$2 }" )
|
||||
|
||||
if echo "$ENCRYPTION" | grep -q PSK; then
|
||||
PASS=$( $DIALOG \
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKIAbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvVmgP/ikDqOYGMuEuPfDArmAt
|
||||
px7cSmVbijPdRRJLcYvboUfRsT/5PtYIJiVTRdr6kG/BH9xz28XNwzm6IfyUbsEO
|
||||
XwlgRkincO4zXJq6F6ZKJSiHJaM1Px6IkccIRLcZYILzVfULagoQ+OVxkMSntiCR
|
||||
KRSiqeoG5qBswUbU3jxtlfpKv3Ayk+H4+u7ELPi/zxLXLOuZWgjm8/oF/KJx4CmQ
|
||||
eqnBaWxd5zswLG+jZ7PZ3wc2s5qw0b2xbOHPdjxyikvkaqgc38cbjJQBKHzfCrpi
|
||||
4KBkqs9tZY9QotNzZDznfgnJS3skymRJs9uDrhQwO/StC+iu4WuscU/73OWt/x2Z
|
||||
QKJ3WKyJVfVvSeoQqF0h98ynWeUvA/7cqpBnaJCZXlQaRrMrlz8bV83HiE3968hP
|
||||
AUKdLGEdUWiaZI2sFsVvE/s7794UCQrpd4piODqhcr5VOX9Gp06h1ShCZREIpd0v
|
||||
lfgen3d8PNcH7sXFFAMerlvqZbL/YZuaWPk/izOHP0dNC04OCM4+3SMO3IFYBc3l
|
||||
VcTKTu5GcwmURn687E/YoL/2x6Edikz7xmm33lRqTAs5Qn8ohsTs0b4igpZuRQSo
|
||||
VTjOiwO78akyfYM8AiASwu0qLlgh6nO1n/wBHRIAmFztChWBGyBQTsRvYb1uTA8J
|
||||
67ktHpJ1y1tnRuCV0ar7RoJL
|
||||
=hjx8
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,102 @@
|
||||
--- usr.sbin/bsdconfig/share/media/wlan.subr.orig
|
||||
+++ usr.sbin/bsdconfig/share/media/wlan.subr
|
||||
@@ -813,6 +813,7 @@
|
||||
[ $nmatches -le ${#DIALOG_MENU_TAGS} ] || break
|
||||
f_substr -v tag "$DIALOG_MENU_TAGS" $nmatches 1
|
||||
|
||||
+ f_shell_escape "$wssid" wssid
|
||||
f_wireless_describe WIRELESS_$n help
|
||||
menu_list1="$menu_list1
|
||||
'$tag $wssid' '$wbssid' '$help'
|
||||
@@ -1076,6 +1077,7 @@
|
||||
while [ $n -lt $nunique ]; do
|
||||
n=$(( $n + 1 ))
|
||||
menuitem_$n get ssid ssid
|
||||
+ f_shell_escape "$ssid" ssid
|
||||
|
||||
menuitem_$n get nconfigs nconfigs
|
||||
desc="$nconfigs $msg_configured_lc"
|
||||
@@ -1184,6 +1186,7 @@
|
||||
while [ $n -lt $nunique ]; do
|
||||
n=$(( $n + 1 ))
|
||||
menuitem_$n get ssid ssid
|
||||
+ f_shell_escape "$ssid" ssid
|
||||
|
||||
desc=
|
||||
if [ "$DIALOG_MENU_WLAN_SHOW_ALL" ]; then
|
||||
--- usr.sbin/bsdinstall/scripts/wlanconfig.orig
|
||||
+++ usr.sbin/bsdinstall/scripts/wlanconfig
|
||||
@@ -147,6 +147,34 @@
|
||||
country_set "$regdomain" "$country"
|
||||
}
|
||||
|
||||
+dialog_network_select()
|
||||
+{
|
||||
+ local ssid flags height width rows prompt
|
||||
+
|
||||
+ # Avoid using eval on untrusted data.
|
||||
+ set --
|
||||
+ while IFS=$'\t' read -r ssid flags; do
|
||||
+ [ -n "$ssid" ] || continue
|
||||
+ set -- "$@" "$ssid" "$flags"
|
||||
+ done <<EOF
|
||||
+$NETWORKS
|
||||
+EOF
|
||||
+
|
||||
+ f_dialog_title "Network Selection"
|
||||
+ prompt="Select a wireless network to connect to."
|
||||
+ f_dialog_menu_size height width rows \
|
||||
+ "$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$prompt" "" "$@"
|
||||
+ $DIALOG \
|
||||
+ --title "$DIALOG_TITLE" \
|
||||
+ --backtitle "$DIALOG_BACKTITLE" \
|
||||
+ --extra-button \
|
||||
+ --extra-label "Rescan" \
|
||||
+ --menu "$prompt" \
|
||||
+ $height $width $rows \
|
||||
+ "$@" \
|
||||
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
|
||||
+}
|
||||
+
|
||||
############################################################ MAIN
|
||||
|
||||
: > "$BSDINSTALL_TMPETC/wpa_supplicant.conf"
|
||||
@@ -213,27 +241,14 @@
|
||||
|
||||
f_eval_catch -dk SCAN_RESULTS wlanconfig wpa_cli "wpa_cli scan_results"
|
||||
NETWORKS=$( echo "$SCAN_RESULTS" | awk -F '\t' '
|
||||
- /..:..:..:..:..:../ && $5 { printf "\"%s\"\t\"%s\"\n", $5, $4 }
|
||||
+ /..:..:..:..:..:../ && $5 { print $5 "\t" $4 }
|
||||
' | sort | uniq )
|
||||
|
||||
if [ ! "$NETWORKS" ]; then
|
||||
f_dialog_title "$msg_error"
|
||||
f_yesno "No wireless networks were found. Rescan?" && continue
|
||||
else
|
||||
- f_dialog_title "Network Selection"
|
||||
- prompt="Select a wireless network to connect to."
|
||||
- f_dialog_menu_size height width rows "$DIALOG_TITLE" \
|
||||
- "$DIALOG_BACKTITLE" "$prompt" "" $NETWORKS
|
||||
- NETWORK=$( eval $DIALOG \
|
||||
- --title \"\$DIALOG_TITLE\" \
|
||||
- --backtitle \"\$DIALOG_BACKTITLE\" \
|
||||
- --extra-button \
|
||||
- --extra-label \"Rescan\" \
|
||||
- --menu \"\$prompt\" \
|
||||
- $height $width $rows \
|
||||
- $NETWORKS \
|
||||
- 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
|
||||
- )
|
||||
+ NETWORK=$( dialog_network_select )
|
||||
fi
|
||||
retval=$?
|
||||
f_dialog_data_sanitize NETWORK
|
||||
@@ -270,7 +285,7 @@
|
||||
done
|
||||
|
||||
[ "$ENCRYPTION" ] || ENCRYPTION=$( echo "$NETWORKS" |
|
||||
- awk -F '\t' "/^\"$NETWORK\"\t/ { print \$2 }" )
|
||||
+ awk -F '\t' "/^$NETWORK\t/ { print \$2 }" )
|
||||
|
||||
if echo "$ENCRYPTION" | grep -q PSK; then
|
||||
PASS=$( $DIALOG \
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKIEbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrv1e0P/RqYWzbb1NdABp3BvIay
|
||||
D0WebRVJuItsRDdalt0cXumP76UGTa1KVKawVE6OSkzM3cQ0hktBHFd16uDlLH0n
|
||||
M3uO61BCz0hPJcalO4PAxT1QO1SOA5bVY1FWB0wvSL1mj9OS35YCbbaxFqlwcTrJ
|
||||
CDjBXyC4CAD4drbOMmfLKLHCkB7gb1TKgN4gpXsMEyhkeOrBBwKg94p6xdqYfxdI
|
||||
yn6kX54BKcDy0fgVnWgtVufpNLqz5wNlShw6TsNM07Mu91yFX5n9jv1jaQet1+Jd
|
||||
QGi1n0r9evuun5BbBzeX2GU6Hq7xwRUYueTEyzPJGn8TBzzjLacEUDGuDA4hDRhI
|
||||
Y9F/wQJdVJN2Pa5e3CtNXc8VQ1V/W92vAkPAzqPEJDsXWa/qp14bS4GpdXWlwFHj
|
||||
ucvI00hC/6kmlhTpa4RjtMUG22qkOeIABoy6ah23qTICVQr29E9nMgLS8wQWDR52
|
||||
rgM6iX6sQ3mOAleFIqT12kaiT8nE7IJnMTRTjoKBkG6iaePuIdFNkrrQAML04TzO
|
||||
TMdHsE4qjgFhI7in2LxVuJIlGLqGDt7uj6M36px2vYvVPu6s8758SpYeiIXGfHnR
|
||||
L7Ihv4P8M48tBIp4yGp10HwYwEBY+CON7NsRCk/gANTBAnPfiHWsjZaH4ZR6f8mg
|
||||
nQqftY90HhsoCa1C/SRm/HKa
|
||||
=mgO8
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -0,0 +1,60 @@
|
||||
--- lib/libcasper/services/cap_net/cap_net.c.orig
|
||||
+++ lib/libcasper/services/cap_net/cap_net.c
|
||||
@@ -1122,12 +1122,37 @@
|
||||
return (0);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * If the old sublimit restricted a subkey, the new one must too;
|
||||
+ * a missing subkey means "allow any" at request time.
|
||||
+ */
|
||||
+static bool
|
||||
+verify_subkeys_present(const nvlist_t *oldfunclimits,
|
||||
+ const nvlist_t *newfunclimit)
|
||||
+{
|
||||
+ void *cookie;
|
||||
+ const char *name;
|
||||
+
|
||||
+ if (oldfunclimits == NULL)
|
||||
+ return (true);
|
||||
+
|
||||
+ cookie = NULL;
|
||||
+ while ((name = nvlist_next(oldfunclimits, NULL, &cookie)) != NULL) {
|
||||
+ if (!nvlist_exists(newfunclimit, name))
|
||||
+ return (false);
|
||||
+ }
|
||||
+ return (true);
|
||||
+}
|
||||
+
|
||||
static bool
|
||||
verify_only_sa_newlimts(const nvlist_t *oldfunclimits,
|
||||
const nvlist_t *newfunclimit)
|
||||
{
|
||||
void *cookie;
|
||||
|
||||
+ if (!verify_subkeys_present(oldfunclimits, newfunclimit))
|
||||
+ return (false);
|
||||
+
|
||||
cookie = NULL;
|
||||
while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) {
|
||||
void *sacookie;
|
||||
@@ -1200,6 +1225,9 @@
|
||||
LIMIT_NV_ADDR2NAME, NULL);
|
||||
}
|
||||
|
||||
+ if (!verify_subkeys_present(oldfunclimits, newfunclimit))
|
||||
+ return (false);
|
||||
+
|
||||
cookie = NULL;
|
||||
while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) {
|
||||
if (strcmp(cnvlist_name(cookie), "sockaddr") == 0) {
|
||||
@@ -1258,6 +1286,9 @@
|
||||
LIMIT_NV_NAME2ADDR, NULL);
|
||||
}
|
||||
|
||||
+ if (!verify_subkeys_present(oldfunclimits, newfunclimit))
|
||||
+ return (false);
|
||||
+
|
||||
cookie = NULL;
|
||||
while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) {
|
||||
if (strcmp(cnvlist_name(cookie), "hosts") == 0) {
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJPBAABCgA5FiEEthUnfoEIffdcgYM7bljekB8AGu8FAmoOKIQbFIAAAAAABAAO
|
||||
bWFudTIsMi41KzEuMTIsMCwzAAoJEG5Y3pAfABrvlq4P/272F0oQ3tEr9MPfrErE
|
||||
L74yVBNk7EDAJqniPUlFL7sRqpnFem0K2TBSj55j/nGbONYDkBTppM0cN8zsrbyq
|
||||
iZkF1c6qPPZtq1brDxY5ZQQokUS3+XcOyW13d7ImT8cdh0o+WpfAtEPFYQa/yrM1
|
||||
IkQMmkiWMp+/XX6C3wYjYAFlbztx0aRrh7f54FUk6uQL58cdbWH2ZuH74cMkv6AW
|
||||
0fIBRkwpfqpjTN90BRZq/2ePIVw7e2rw6aqNqAyOURIQAIYY8sucEK5r2YosieMU
|
||||
SJIpB1ejW6S6egAvuHXx4OD6Xqw4TouCo9GnaPf+PQvER8eQvvUJAfHfJeAjj5+I
|
||||
5QmGDXz47Zn9fSLiSKrzk4rkGuHHcNGyCbwuYtRXoBlLoRrWousP59KYO1kR63gv
|
||||
1p7fPitzqHXCfdohN8xkv2RtSWTU9jUXb6h5rEyI5SdBB6kX0w4BbwW5qXwmGWtM
|
||||
282ey6jNVCIi+xeJ1xwSeHcSuHHj6AhtOANxM2I1xNMhmCMcAX65cGCg0EVYhO6X
|
||||
9BQXyVJXdojVUNOP3NV1OjbXvSFHHaIJ0iBJOJ38GUl377AXW+KW0cp5yggbZMhD
|
||||
J3dRdAqTZO9FObwJF86Zd1xyuqySIqVnnycBTboNwoKkRDvRib8vwwQCBCoWSMwj
|
||||
ge/Ki9+fl13Q/5uoW/dWyf4J
|
||||
=ci2w
|
||||
-----END PGP SIGNATURE-----
|
||||
Reference in New Issue
Block a user