Linux

如何讀取程序的環境變數

  • June 15, 2021

Linux/proc/<pid>/environ不會更新程序的環境。據我了解,該文件包含該過程的初始環境。

如何讀取程序的目前環境?

/proc/$pid/environ如果程序改變了自己的環境,它會更新。但是很多程序都懶得去改自己的環境,因為這有點沒意義:一個程序的環境通過普通的渠道是看不到的,只能通過/procand ps,甚至不是每個unix變種都有這種特性,所以應用程序不依賴在上面。

就核心而言,環境僅作為execve啟動程序的系統呼叫的參數出現。Linux 通過 暴露記憶體中的一個區域/proc,有些程序會更新這個區域,而有些程序則不會。特別是,我認為沒有任何 shell 更新這個區域。由於該區域具有固定大小,因此無法添加新變數或更改值的長度。

您可以從 中讀取程序的初始環境/proc/<pid>/environ

如果一個程序改變了它的環境,那麼為了讀取環境,你必須有程序的符號表並使用ptrace系統呼叫(例如使用gdb)從全域char **__environ變數中讀取環境。沒有任何其他方法可以從正在執行的 Linux 程序中獲取任何變數的值。

這就是答案。現在做一些筆記。

以上假設程序是 POSIX 兼容的,這意味著程序使用Ref Specchar **__environ中指定的全域變數來管理其環境。

程序的初始環境在程序堆棧上的固定長度緩衝區中傳遞給程序。(執行此操作的常用機制是linux//fs/exec.c:do_execve_common(...)。)由於緩衝區的大小被計算為不超過初始環境所需的大小,因此您不能在不刪除現有變數或破壞堆棧的情況下添加新變數。因此,任何允許更改程序環境的合理方案都將使用堆,其中可以分配和釋放任意大小的記憶體,這正是 GNU libc( glibc) 為您所做的。

如果程序使用glibc,那麼它是 POSIX 兼容的,__environglibc//posix/environ.cGlibc中聲明__environ它使用指向程序堆中的記憶體的指針進行初始化malloc,然後將初始環境從堆棧複製到該堆區域。每次程序使用該setenv函式時,都會調整指向的區域glibcrealloc大小__environ以適應新的值或變數。(您可以使用 下載 glibc 原始碼git clone git://sourceware.org/git/glibc.git glibc)。要真正理解該機制,您還必須閱讀hurd//init/init.c:frob_kernel_process()(git clone git://git.sv.gnu.org/hurd/hurd.git hurd) 中的 Hurd 程式碼。

現在,如果新程序只是forked,而沒有隨後exec覆蓋堆棧,那麼參數和環境複製魔術在 中完成linux//kernel/fork.c:do_fork(...)copy_process常式呼叫dup_task_struct通過呼叫分配新程序的堆棧,alloc_thread_info_node呼叫setup_thread_stack( linux//include/linux/sched.h) 為新程序使用alloc_thread_info_node.

最後,POSIX__environ約定是使用者空間約定。它與 Linux 核心中的任何東西都沒有關係。glibc您可以在不使用和不使用全域變數的情況下編寫使用者空間程序__environ,然後根據需要管理環境變數。沒有人會因為這樣做而逮捕您,但您必須編寫自己的環境管理函式 ( setenv/ getenv) 和自己的包裝器,sys_exec而且很可能沒有人能夠猜出您將更改放在環境中的位置。

引用自:https://unix.stackexchange.com/questions/29128