[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