On 31/10/2026 03:55, Collin Funk wrote:
if (specified_context == NULL)
{
- int status = (affect_symlink_referent
- ? getfileconat (fd, file, &file_context)
- : lgetfileconat (fd, file, &file_context));
-
- if (status < 0 && errno != ENODATA)
+ /* libselinux versions before 3.4 did not support O_PATH.
+ The O_PATH support works by opening the file descriptor under
+ /proc/self/fd. We could check if fsetfilecon returns EBADF and
+ do the same, but there is likely not much benefit over just
+ using O_RDONLY. */
+ fd = openat (dirfd, file,
+ (O_RDONLY | O_NOCTTY | O_NONBLOCK
+ | (affect_symlink_referent ? 0 : O_NOFOLLOW)));
I dislike the real open for a metadata update.
There may be side effects on devices etc.
or requiring read permissions where previously we did not,
and also symlinks could cause issues.
E.g. the following now fails with ELOOP:
d='testd'
mkdir -p $d
touch $d/file
ln -s file $d/link
se_type=$(stat -c %C $d/link | cut -d: -f3)
src/chcon -h -t $se_type $d/link
This is a tricky one due to the O_PATH limitation you commented on.
Though libselinux 3.4 was 2022, and missing /proc would be very
unusual on selinux systems, so it's probably fine to fall back
to the existing implementation in that case. Note I would not
fall back on any openat() failure as an attacker could be replacing
a file so you'd want to bail out to avoid that. I.e. only fall back
when fgetfilecon() returns EBADF.
Note we could fail rather than fall back if any partial option is used,
but that would be a bit too draconian for this I think.
cheers,
Padraig