Proc

/proc/<pid>/cmdline 的意外非空編碼

  • March 22, 2018

我正在解析/proc/pid/cmdline我的 Linux 系統(Ubuntu 16.04)上的多個程序的值,並發現雖然大多數條目都是空編碼的,正如預期的那樣,但至少有一個使用空格作為分隔符,這是我發現的意外。

proc(5) 的文件中,我沒有看到任何跡象表明這應該發生。在任何情況下,我應該將空格作為分隔符而不是空值?如果是這樣,我在哪裡可以找到描述該行為的文件?


行為

這是我在嘗試為 chromium-browser 程序之一設置 cmdline 時看到的(注意空格字元用於分隔值):

user@host:~$ cat /proc/2721/cmdline
/usr/lib/chromium-browser/chromium-browser --type=gpu-process --field-trial-handle=2073283832741738928,4790986738309707242,131072 --gpu-preferences=GAAAAAAAAAAAAQAAAQAAAAAAAAAAAGAA --gpu-vendor-id=0x15ad --gpu-device-id=0x0405 --gpu-driver-vendor=Mesa --gpu-driver-version=17.2.8 --gpu-driver-date --service-request-channel-token=3778166CAD6E96F44A7268DF1AB1DD53

我希望看到這樣的東西(空值作為分隔符),這是我系統上的其他程序中看到的:

~$ cat /proc/354/cmdline
vmware-vmblock-fuse/run/vmblock-fuse-orw,subtype=vmware-vmblock,default_permissions,allow_other,dev,suid

至少一個使用空格作為分隔符

不正確。

如果您查看 FreeBSD/TrueOS 上偽文件的末尾,您會遇到與 Chromium 完全相同的行為,您會發現. 這␀ 終止的。這都是一個單一的論點

Chromium 在 a 之後覆蓋其參數fork(),以便在ps. 它正在使用setproctitle()庫函式。這是 BSD C 庫的一部分。它不是 GNU C 庫的一部分。在 GNU C 平台上,Chromium 使用自己的asetproctitle()直接覆蓋argv數據。

setproctitle()事實上,這不是這項工作的正確工具,因為它不允許設置多個參數字元串。它將格式化的“標題”設置為第 0 個參數,並將參數計數設置為 1。所有內容都通過庫函式作為一個參數進行編組。

這不是唯一的問題setproctitle()。FreeBSD/OpenBSD/NetBSD C 庫版本也有任意 2KiB 的限制,直接繼承自舊的 BSDsendmail程序(在 FreeBSD 案例中庫函式最初是從該程序中提取的),這對於 Chromium 經常設置的命令行來說太短了到。而且 Chromium 自己的和 FreeBSD/OpenBSD/NetBSD C 庫版本都有額外的功能,格式字元串是一個空指針,Chromium 不使用這些功能(但具有諷刺意味的是,setproctitle()儘管如此,它必須在自己的實現中處理)。

用更少的程式碼可以做得更好。FreeBSD/TrueOS 上的底層系統呼叫是庫函式在構造參數數據後呼叫以完成工作的sysctl()函式,以CTL_KERNKERN_PROCKERN_PROC_ARGS和程序 ID 作為地址。這可以接受多個以 ␀ 結尾的字元串。我為使用它的工具集編寫了一個相當簡單的setprocargv()函式。

外部
空白
setprocargv (
size_t argc,
常量字元 * argv[]
) {
#if 定義(__FreeBSD__) || 定義(__DragonFly__)
std::string s;
for (size_t c(0); c &lt; argc; ++c) {
if (!argv[c]) 中斷;
s += argv[c];
s += '\0';
}
常量 int oid[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, getpid() };
sysctl(oid, sizeof oid/sizeof *oid, 0, 0, s.data(), s.length());
#elif 定義(__OpenBSD__) ...

(OpenBSD/NetBSD 以 FreeBSD/TrueOS 過去的舊方式做事,ps_strings在應用程序記憶體中有一個結構,但它仍然sysctl()是使用的底層系統呼叫,用於查找該結構的位置。)

% /package/admin/nosh/command/exec 前台暫停 \; 真的 &
[1] 30318
% hexdump -C /proc/30318/cmdline
00000000 66 6f 72 65 67 72 6f 75 6e 64 00 70 61 75 73 65 |foreground.pause|
00000010 00 3b 00 74 72 75 65 00 |.;. 真。
00000018
% hexdump -C /proc/30319/cmdline
00000000 70 61 75 73 65 00 |暫停。|
00000006
%

因為setproctitle()是錯誤的工作工具,Chromium 正在獲取新argv成員並構造一個由 ␠ 分隔的長字元串,作為單個參數傳遞給setproctitle().

for (size_t i = 1; i &lt; command_line-&gt;argv().size(); ++i) {
if (!title.empty())
標題+=“”;
標題 += 命令行-&gt;argv()[i];
}
// 如果我們自己在上面添加了 argv[0],則禁用在 argv[0] 前添加 '-'。
setproctitle(have_argv0 ? "-%s" : "%s", title.c_str());

如您所見,Chromium本身已經將新的參數向量作為一系列以 ␀ 結尾的字元串。它通過一個中間庫層傳遞它,該層需要將它們全部打包成一個字元串,其中實際的系統呼叫級別仍然根據 ␀ 終止的字元串的參數向量進行操作。

因此,您正在目睹的行為,其中 Chromium 將其更改的參數向量作為一個單一參數呈現給系統。

也許您可以說服 Chromium 的作者採用類似setprocargv(). ☺

進一步閱讀

  • 彼得·韋姆 (1995-12-16)。setproctitle. FreeBSD 庫函式手冊。自由BSD。

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