[libc-commits] [libc] [libc] Add secure_getenv implementation for Linux (PR #225013)

Jeff Bailey via libc-commits libc-commits at lists.llvm.org
Sun Sep 20 23:36:41 PDT 2026


https://github.com/kaladron created https://github.com/llvm/llvm-project/pull/225013

Add implementation of POSIX.1-2024 secure_getenv for Linux.

* Fullbuild mode only
* Query AT_SECURE from the auxiliary vector, failing closed if missing or non-zero.
* Add integration test verifying normal operation and secure execution mode behavior.

Assisted-by: Automated tooling, human reviewed.

>From ff232d854cec1b1763d8d659710e026f5bccf526 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Wed, 16 Sep 2026 20:43:35 +0100
Subject: [PATCH] [libc] Add secure_getenv implementation for Linux

Add implementation of POSIX.1-2024 secure_getenv for Linux.

* Query AT_SECURE from the auxiliary vector, failing closed if
  missing or non-zero.
* Add integration test verifying normal operation and secure
  execution mode behavior.

Assisted-by: Automated tooling, human reviewed.
---
 libc/config/linux/aarch64/entrypoints.txt     |  1 +
 libc/config/linux/riscv/entrypoints.txt       |  1 +
 libc/config/linux/x86_64/entrypoints.txt      |  1 +
 libc/include/stdlib.yaml                      |  6 ++
 libc/src/stdlib/CMakeLists.txt                |  7 +++
 libc/src/stdlib/linux/CMakeLists.txt          | 14 +++++
 libc/src/stdlib/linux/secure_getenv.cpp       | 34 +++++++++++
 libc/src/stdlib/secure_getenv.h               | 25 ++++++++
 .../integration/src/stdlib/CMakeLists.txt     | 16 +++++
 .../src/stdlib/secure_getenv_test.cpp         | 61 +++++++++++++++++++
 10 files changed, 166 insertions(+)
 create mode 100644 libc/src/stdlib/linux/secure_getenv.cpp
 create mode 100644 libc/src/stdlib/secure_getenv.h
 create mode 100644 libc/test/integration/src/stdlib/secure_getenv_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index f7b2c3059df43..831b5f95f4761 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1286,6 +1286,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.stdlib.exit
     libc.src.stdlib.getenv
     libc.src.stdlib.putenv
+    libc.src.stdlib.secure_getenv
     libc.src.stdlib.setenv
     libc.src.stdlib.system
     libc.src.stdlib.unsetenv
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 2cabbc7031f22..1a5bdce3e5ae2 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1471,6 +1471,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.stdlib.exit
     libc.src.stdlib.getenv
     libc.src.stdlib.putenv
+    libc.src.stdlib.secure_getenv
     libc.src.stdlib.setenv
     libc.src.stdlib.system
     libc.src.stdlib.unsetenv
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index bba74cf8907f9..5d5b236f39283 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1486,6 +1486,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.stdlib.exit
     libc.src.stdlib.getenv
     libc.src.stdlib.putenv
+    libc.src.stdlib.secure_getenv
     libc.src.stdlib.setenv
     libc.src.stdlib.unsetenv
     libc.src.stdlib.mbstowcs
diff --git a/libc/include/stdlib.yaml b/libc/include/stdlib.yaml
index eb0ca6ce42eef..7f2c2f03b35ff 100644
--- a/libc/include/stdlib.yaml
+++ b/libc/include/stdlib.yaml
@@ -248,6 +248,12 @@ functions:
     return_type: void
     arguments:
       - type: unsigned int
+  - name: secure_getenv
+    standards:
+      - posix
+    return_type: char *
+    arguments:
+      - type: const char *
   - name: setenv
     standards:
       - posix
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 45f27c6da3619..bbab9e4f535b3 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -693,6 +693,13 @@ add_entrypoint_object(
     libc.src.__support.str_to_integer
 )
 
+add_entrypoint_object(
+  secure_getenv
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.secure_getenv
+)
+
 add_entrypoint_object(
   setenv
   ALIAS
diff --git a/libc/src/stdlib/linux/CMakeLists.txt b/libc/src/stdlib/linux/CMakeLists.txt
index a996d131fb580..5295d024216b8 100644
--- a/libc/src/stdlib/linux/CMakeLists.txt
+++ b/libc/src/stdlib/linux/CMakeLists.txt
@@ -37,6 +37,20 @@ add_entrypoint_object(
     libc.src.string.memory_utils.inline_memcpy
 )
 
+add_entrypoint_object(
+  secure_getenv
+  SRCS
+    secure_getenv.cpp
+  HDRS
+    ../secure_getenv.h
+  DEPENDS
+    libc.hdr.sys_auxv_macros
+    libc.src.__support.OSUtil.linux.auxv
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.stdlib.environ_internal
+)
+
 add_entrypoint_object(
   setenv
   SRCS
diff --git a/libc/src/stdlib/linux/secure_getenv.cpp b/libc/src/stdlib/linux/secure_getenv.cpp
new file mode 100644
index 0000000000000..d631b7f621625
--- /dev/null
+++ b/libc/src/stdlib/linux/secure_getenv.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of the POSIX secure_getenv function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/secure_getenv.h"
+#include "hdr/sys_auxv_macros.h"
+#include "src/__support/OSUtil/linux/auxv.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/stdlib/environ_internal.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(char *, secure_getenv, (const char *name)) {
+  if (name == nullptr || name[0] == '\0')
+    return nullptr;
+
+  // Fail closed if AT_SECURE is non-zero or missing from auxv.
+  if (auxv::get(AT_SECURE).value_or(1) != 0)
+    return nullptr;
+
+  return internal::EnvironmentManager::get_instance().get(name);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/secure_getenv.h b/libc/src/stdlib/secure_getenv.h
new file mode 100644
index 0000000000000..cf4365125e736
--- /dev/null
+++ b/libc/src/stdlib/secure_getenv.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for secure_getenv.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_SECURE_GETENV_H
+#define LLVM_LIBC_SRC_STDLIB_SECURE_GETENV_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+char *secure_getenv(const char *name);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDLIB_SECURE_GETENV_H
diff --git a/libc/test/integration/src/stdlib/CMakeLists.txt b/libc/test/integration/src/stdlib/CMakeLists.txt
index db04fd05e6a28..7976e3833e282 100644
--- a/libc/test/integration/src/stdlib/CMakeLists.txt
+++ b/libc/test/integration/src/stdlib/CMakeLists.txt
@@ -18,6 +18,22 @@ add_integration_test(
 )
 
 if(${LIBC_TARGET_OS} STREQUAL "linux")
+  add_integration_test(
+    secure_getenv_test
+    SUITE
+      stdlib-integration-tests
+    SRCS
+      secure_getenv_test.cpp
+    DEPENDS
+      libc.hdr.sys_auxv_macros
+      libc.src.__support.CPP.scope
+      libc.src.__support.OSUtil.linux.auxv
+      libc.src.stdlib.secure_getenv
+    ENV
+      FRANCE=Paris
+      GERMANY=Berlin
+  )
+
   add_integration_test(
     setenv_test
     SUITE
diff --git a/libc/test/integration/src/stdlib/secure_getenv_test.cpp b/libc/test/integration/src/stdlib/secure_getenv_test.cpp
new file mode 100644
index 0000000000000..18bf3a81da3c5
--- /dev/null
+++ b/libc/test/integration/src/stdlib/secure_getenv_test.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Integration test for secure_getenv.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_auxv_macros.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/OSUtil/linux/auxv.h"
+#include "src/stdlib/secure_getenv.h"
+
+#include "test/IntegrationTest/test.h"
+
+TEST_MAIN([[maybe_unused]] int argc, [[maybe_unused]] char **argv,
+          [[maybe_unused]] char **envp) {
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv(nullptr), nullptr);
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv(""), nullptr);
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv("="), nullptr);
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv("MISSING ENV VARIABLE"), nullptr);
+  EXPECT_NE(LIBC_NAMESPACE::secure_getenv("PATH"), nullptr);
+  EXPECT_STREQ(LIBC_NAMESPACE::secure_getenv("FRANCE"), "Paris");
+  EXPECT_STREQ(LIBC_NAMESPACE::secure_getenv("GERMANY"), "Berlin");
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv("FRANC"), nullptr);
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv("FRANCE1"), nullptr);
+
+  constexpr LIBC_NAMESPACE::auxv::Entry SECURE_AUXV[] = {
+      {AT_SECURE, 1},
+      {AT_NULL, AT_NULL},
+  };
+  constexpr LIBC_NAMESPACE::auxv::Entry NORMAL_AUXV[] = {
+      {AT_SECURE, 0},
+      {AT_NULL, AT_NULL},
+  };
+  constexpr LIBC_NAMESPACE::auxv::Entry EMPTY_AUXV[] = {
+      {AT_NULL, AT_NULL},
+  };
+
+  LIBC_NAMESPACE::auxv::Vector::initialize_unsafe(SECURE_AUXV);
+  LIBC_NAMESPACE::cpp::scope_exit restore_auxv(
+      [&] { LIBC_NAMESPACE::auxv::Vector::initialize_unsafe(NORMAL_AUXV); });
+
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv("FRANCE"), nullptr);
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv("GERMANY"), nullptr);
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv("PATH"), nullptr);
+
+  LIBC_NAMESPACE::auxv::Vector::initialize_unsafe(EMPTY_AUXV);
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv("FRANCE"), nullptr);
+  EXPECT_EQ(LIBC_NAMESPACE::secure_getenv("PATH"), nullptr);
+
+  LIBC_NAMESPACE::auxv::Vector::initialize_unsafe(NORMAL_AUXV);
+  EXPECT_STREQ(LIBC_NAMESPACE::secure_getenv("FRANCE"), "Paris");
+
+  return 0;
+}



More information about the libc-commits mailing list