From e283e023ab42f7bcda6d7d31d5dd61336efaeccc Mon Sep 17 00:00:00 2001 From: Kathryn Baldauf Date: Mon, 13 Oct 2025 21:33:18 -0700 Subject: [PATCH] Use container's environment when starting the init process (#329) Fixes an issue first described in https://github.com/apple/container/issues/740. Previously the initial process of the container was using vminitd's environment variables to find the target executable. This PR updates the code to use the container's configured environment for the initial process instead. The behavior of an exec in a container should be the same as before. Signed-off-by: Kathryn Baldauf --- Sources/ContainerizationOS/Path.swift | 17 ++++++++++++----- vminitd/Sources/vmexec/RunCommand.swift | 2 +- vminitd/Sources/vmexec/vmexec.swift | 11 +++++++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Sources/ContainerizationOS/Path.swift b/Sources/ContainerizationOS/Path.swift index 0f7e2628..21a93a4f 100644 --- a/Sources/ContainerizationOS/Path.swift +++ b/Sources/ContainerizationOS/Path.swift @@ -21,14 +21,18 @@ import Foundation public struct Path { /// lookPath looks up an executable's path from $PATH public static func lookPath(_ name: String) -> URL? { - lookup(name, path: getPath()) + lookup(name, path: getCurrentPath()) + } + + public static func lookPath(_ name: String, path: String) -> URL? { + lookup(name, path: path) } // getEnv returns the default environment of the process // with the default $PATH added for the context of a macOS application bundle public static func getEnv() -> [String: String] { var env = ProcessInfo.processInfo.environment - env["PATH"] = getPath() + env["PATH"] = getCurrentPath() return env } @@ -58,14 +62,17 @@ public struct Path { } /// getPath returns $PATH for the current process - private static func getPath() -> String { + public static func getCurrentPath() -> String { let env = ProcessInfo.processInfo.environment return env["PATH"] ?? "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" } // findPath returns a string containing the 'PATH' environment variable - private static func findPath(_ env: [String]) -> String? { - env.first(where: { path in + public static func findPath(_ env: [String]?) -> String? { + guard let env = env else { + return nil + } + return env.first(where: { path in let split = path.split(separator: "=") return split.count == 2 && split[0] == "PATH" }) diff --git a/vminitd/Sources/vmexec/RunCommand.swift b/vminitd/Sources/vmexec/RunCommand.swift index 55010018..f4133ce5 100644 --- a/vminitd/Sources/vmexec/RunCommand.swift +++ b/vminitd/Sources/vmexec/RunCommand.swift @@ -138,7 +138,7 @@ struct RunCommand: ParsableCommand { try App.setPermissions(user: process.user) // Finally execve the container process. - try App.exec(process: process) + try App.exec(process: process, currentEnv: process.env) } private func execInNamespace(spec: ContainerizationOCI.Spec, log: Logger) throws { diff --git a/vminitd/Sources/vmexec/vmexec.swift b/vminitd/Sources/vmexec/vmexec.swift index 13e8e2a1..199a29ed 100644 --- a/vminitd/Sources/vmexec/vmexec.swift +++ b/vminitd/Sources/vmexec/vmexec.swift @@ -22,6 +22,7 @@ import ArgumentParser import ContainerizationError import ContainerizationOCI +import ContainerizationOS import Foundation import LCShim import Logging @@ -71,8 +72,14 @@ extension App { } } - static func exec(process: ContainerizationOCI.Process) throws { - let executable = strdup(process.args[0]) + static func exec(process: ContainerizationOCI.Process, currentEnv: [String]? = nil) throws { + // lookup executable + let path = Path.findPath(currentEnv) ?? Path.getCurrentPath() + guard let resolvedExecutable = Path.lookPath(process.args[0], path: path) else { + throw App.Failure(message: "Failed to find target executable \(process.args[0])") + } + + let executable = strdup(resolvedExecutable.path()) var argv = process.args.map { strdup($0) } argv += [nil]