Files
glibc/elf/tst-origin-secure-victim.c
T
Adhemerval Zanella 58927d6ca6 elf: Open the normalized $ORIGIN rpath in AT_SECURE programs (BZ 34360)
For AT_SECURE programs the loader honors $ORIGIN in DT_RPATH only when the
expansion is rooted in a trusted directory, but it validated the lexically
normalized path while opening the raw expansion.  As "a/b/../c" only names
"a/c" when "b" is not a symlink, an attacker who controls a component of
$ORIGIN -- e.g. by hard-linking the setuid binary into an attacker-owned
directory -- can make the opened path escape the trusted directory even
though the check passed, loading an attacker-controlled object.

Normalize the expansion in place and open that, so the path that is opened
is exactly the path that was validated.  _dl_normalize_path rewrites the
string in place without ever advancing its write cursor past its read
cursor or appending, so it stays within the original storage.

Add elf/tst-origin-secure as a regression test.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit ed0c137b97)
2026-10-02 22:36:50 +02:00

44 lines
1.7 KiB
C

/* Victim program for tst-origin-secure.
Copyright (C) 2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include "tst-origin-secure.h"
extern int __libc_enable_secure;
/* Report both which module was loaded and whether the loader ran in secure
mode, so the driver can tell a genuine trusted-path bypass apart from a run
that simply was not secure.
The exit status is the combination of the ORIGIN_SECURE_STATUS_* bits:
_NONE trusted copy, not secure
_ATTACKER attacker copy, not secure (the control run)
_SECURE trusted copy, secure (a fixed loader)
_SECURE | _ATTACKER attacker copy, secure (the bug: the raw
rpath was opened) */
int
main (void)
{
int status = ORIGIN_SECURE_STATUS_NONE;
if (origin_secure_id () == ORIGIN_SECURE_ID_ATTACKER)
status |= ORIGIN_SECURE_STATUS_ATTACKER;
if (__libc_enable_secure != 0)
status |= ORIGIN_SECURE_STATUS_SECURE;
return status;
}