[llvm] [orc-rt] Add internal secureGetenv utility and use it in the printf b… (PR #209014)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 12 06:09:42 PDT 2026
https://github.com/lhames created https://github.com/llvm/llvm-project/pull/209014
…ackend
orc_rt::secureGetenv is like getenv, but returns null when the process is running with elevated privileges (e.g. a set-user-ID or set-group-ID program), so that a variable in an attacker-controlled environment cannot influence a privileged host. On libcs where privilege can't be checked (anything other than glibc or the BSDs/macOS), it fails secure and returns null, so those environment variables are ignored until a branch for the platform is added.
Switch the printf logging backend to read ORC_RT_LOG and ORC_RT_LOG_OUTPUT through secureGetenv, so a redirected log file or level can't be forced via the environment in a privileged process.
Note that running the ORC runtime in a process with elevated privileges is extremely risky (since the JIT'd code will typically inherit these elevated privileges), and expected to be rare. Exercise extreme caution with such setups.
>From 544562d282e4e6eddd40d58fe32ecd9ba3cbc6a2 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Sun, 12 Jul 2026 21:08:35 +1000
Subject: [PATCH] [orc-rt] Add internal secureGetenv utility and use it in the
printf backend
orc_rt::secureGetenv is like getenv, but returns null when the process
is running with elevated privileges (e.g. a set-user-ID or set-group-ID
program), so that a variable in an attacker-controlled environment
cannot influence a privileged host. On libcs where privilege can't be
checked (anything other than glibc or the BSDs/macOS), it fails secure
and returns null, so those environment variables are ignored until a
branch for the platform is added.
Switch the printf logging backend to read ORC_RT_LOG and
ORC_RT_LOG_OUTPUT through secureGetenv, so a redirected log file or level
can't be forced via the environment in a privileged process.
Note that running the ORC runtime in a process with elevated privileges
is extremely risky (since the JIT'd code will typically inherit these
elevated privileges), and expected to be rare. Exercise extreme caution
with such setups.
---
orc-rt/lib/executor/CMakeLists.txt | 1 +
orc-rt/lib/executor/Environment.cpp | 52 ++++++++++++++++++++++++++
orc-rt/lib/executor/Environment.h | 28 ++++++++++++++
orc-rt/lib/executor/Logging_printf.cpp | 9 ++---
4 files changed, 85 insertions(+), 5 deletions(-)
create mode 100644 orc-rt/lib/executor/Environment.cpp
create mode 100644 orc-rt/lib/executor/Environment.h
diff --git a/orc-rt/lib/executor/CMakeLists.txt b/orc-rt/lib/executor/CMakeLists.txt
index e01b9d0b56629..387ccd284c7ce 100644
--- a/orc-rt/lib/executor/CMakeLists.txt
+++ b/orc-rt/lib/executor/CMakeLists.txt
@@ -2,6 +2,7 @@ set(files
AllocAction.cpp
BootstrapInfo.cpp
SimpleSymbolTable.cpp
+ Environment.cpp
Error.cpp
ExecutorProcessInfo.cpp
InProcessControllerAccess.cpp
diff --git a/orc-rt/lib/executor/Environment.cpp b/orc-rt/lib/executor/Environment.cpp
new file mode 100644
index 0000000000000..28a240965d300
--- /dev/null
+++ b/orc-rt/lib/executor/Environment.cpp
@@ -0,0 +1,52 @@
+//===- Environment.cpp - ORC-RT executor environment access ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of the environment helpers declared in Environment.h.
+//
+//===----------------------------------------------------------------------===//
+
+// Must precede any include so <stdlib.h> exposes glibc's secure_getenv.
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "Environment.h"
+
+#include <stdlib.h>
+
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__NetBSD__) || defined(__DragonFly__)
+#include <unistd.h> // for issetugid
+#endif
+
+namespace orc_rt {
+
+const char *secureGetenv(const char *Name) {
+#if defined(__GLIBC__)
+ // secure_getenv returns null in "secure execution" mode, which the kernel
+ // sets for set-user-ID / set-group-ID programs (and other privilege
+ // transitions).
+ return ::secure_getenv(Name);
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__NetBSD__) || defined(__DragonFly__)
+ // No secure_getenv; issetugid() reports whether the process was made
+ // set-user-ID / set-group-ID (or otherwise had its ids changed).
+ return ::issetugid() ? nullptr : ::getenv(Name);
+#else
+ // We cannot verify here that the environment is trustworthy, so fail secure:
+ // refuse to read the variable rather than risk honoring an attacker-supplied
+ // value in a privileged process.
+ //
+ // TODO: Add branches for other libcs/platforms as needed (e.g. musl's
+ // secure_getenv, Windows), so their environment variables aren't ignored.
+ (void)Name;
+ return nullptr;
+#endif
+}
+
+} // namespace orc_rt
diff --git a/orc-rt/lib/executor/Environment.h b/orc-rt/lib/executor/Environment.h
new file mode 100644
index 0000000000000..cb2d8ca00120a
--- /dev/null
+++ b/orc-rt/lib/executor/Environment.h
@@ -0,0 +1,28 @@
+//===- Environment.h - ORC-RT executor environment access -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers for reading the process environment.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_LIB_EXECUTOR_ENVIRONMENT_H
+#define ORC_RT_LIB_EXECUTOR_ENVIRONMENT_H
+
+namespace orc_rt {
+
+/// Like getenv, but returns null when the process is running with elevated
+/// privileges (e.g. a set-user-ID or set-group-ID program), so that a variable
+/// in an attacker-controlled environment cannot influence a privileged host.
+///
+/// Use this for any environment variable whose value has security-relevant
+/// effects, e.g. choosing a file to open.
+const char *secureGetenv(const char *Name);
+
+} // namespace orc_rt
+
+#endif // ORC_RT_LIB_EXECUTOR_ENVIRONMENT_H
diff --git a/orc-rt/lib/executor/Logging_printf.cpp b/orc-rt/lib/executor/Logging_printf.cpp
index 91a38b0ebae83..8062a791b1853 100644
--- a/orc-rt/lib/executor/Logging_printf.cpp
+++ b/orc-rt/lib/executor/Logging_printf.cpp
@@ -12,11 +12,12 @@
#include "orc-rt-c/Logging.h"
+#include "Environment.h"
+
#include <algorithm>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
-#include <cstdlib>
namespace {
@@ -24,8 +25,7 @@ namespace {
// names a file that can be opened for appending.
FILE *sink() {
static FILE *Sink = []() -> FILE * {
- // TODO: Use a setuid/setgid-safe secure getenv (ORC runtime utility, TBD).
- const char *Path = std::getenv("ORC_RT_LOG_OUTPUT");
+ const char *Path = orc_rt::secureGetenv("ORC_RT_LOG_OUTPUT");
if (!Path || !*Path)
return stderr;
FILE *F = std::fopen(Path, "a");
@@ -52,8 +52,7 @@ FILE *sink() {
// but never more verbose than INFO.
orc_rt_log_Level runtimeLevel() {
static orc_rt_log_Level Level = []() -> orc_rt_log_Level {
- // TODO: Use a setuid/setgid-safe secure getenv (ORC runtime utility, TBD).
- const char *S = std::getenv("ORC_RT_LOG");
+ const char *S = orc_rt::secureGetenv("ORC_RT_LOG");
if (!S || !*S)
return ORC_RT_LOG_LEVEL_WARNING;
orc_rt_log_Level L = orc_rt_log_Level_parse(S);
More information about the llvm-commits
mailing list