簡體   English   中英

通過argv操作進程名稱和參數

[英]Manipulating process name and arguments by way of argv

我有一個用C語言編寫的程序,它只能在Linux上運行。 我希望能夠更改ps命令中顯示的進程名稱。 為此,我直接更改argv[0]的字符串,並使用主線程中的prctl(PR_SET_NAME, argv[0])調用。 我還想從動態加載的共享庫中訪問/proc/self/cmdline ,以后甚至可能從其他程序訪問。

我讀到為了這個工作,我必須使用從argv[0]開始的原始內存空間。 所述ELF標准規定該空間\\0從分離environ空間。 從Postgres代碼中查看ps_status.c ,可以看到他們正在將所有這些空間用於argv字符串。 真的,當我memset這個空間,以'a' ,我可以看到超過3000個字符在ps和讀取它/proc文件系統兩種。 當我嘗試使用此空間動態(在運行時)在此空間中創建新參數時,問題就開始了。 (我已經閱讀並從基本測試中了解到Chrome / Chromium做了類似的事情 - 通過命令行參數在ps導出它的fork進程的狀態。)任何包含空間中的NULL分隔符到達原始環境的東西都被視為結束。 (我最初在cmdline參數中有105個字符,我能夠獲得130個字符但是其他參數直到這個3000個字符標記都沒有被讀取。)從此我收集到系統記住原始大小並且只讓我“讀完“直到弦樂結束。 (更改char ** argv指針沒有幫助。)

但Chrome在某種程度上是這樣做的。 查看command_line.cc源代碼,我發現沒有直接的方法。

甚至可以這樣做嗎? 如果是這樣,怎么樣? 告訴Linux內核argv內存和argc的大小是否改變了?

謝謝。

PR_SET_MM_ARG_STARTPR_SET_MM_ARG_END允許您執行此操作,如果您是root用戶(更具體地說,如果進程具有CAP_SYS_RESOURCE功能)。

用法:

prctl(PR_SET_NAME, constructed_argv[0]);
prctl(PR_SET_MM, PR_SET_MM_ARG_START, constructed_argv, 0, 0);
prctl(PR_SET_MM, PR_SET_MM_ARG_END, end_of_constructed_argv, 0, 0);

以下是systemd中有充分記錄的用法示例:

            /* Now, let's tell the kernel about this new memory */
            if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
                    /* HACK: prctl() API is kind of dumb on this point.  The existing end address may already be
                     * below the desired start address, in which case the kernel may have kicked this back due
                     * to a range-check failure (see linux/kernel/sys.c:validate_prctl_map() to see this in
                     * action).  The proper solution would be to have a prctl() API that could set both start+end
                     * simultaneously, or at least let us query the existing address to anticipate this condition
                     * and respond accordingly.  For now, we can only guess at the cause of this failure and try
                     * a workaround--which will briefly expand the arg space to something potentially huge before
                     * resizing it to what we want. */
                    log_debug_errno(errno, "PR_SET_MM_ARG_START failed, attempting PR_SET_MM_ARG_END hack: %m");

                    if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0) {
                            log_debug_errno(errno, "PR_SET_MM_ARG_END hack failed, proceeding without: %m");
                            (void) munmap(nn, nn_size);
                            goto use_saved_argv;
                    }

                    if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
                            log_debug_errno(errno, "PR_SET_MM_ARG_START still failed, proceeding without: %m");
                            goto use_saved_argv;
                    }
            } else {
                    /* And update the end pointer to the new end, too. If this fails, we don't really know what
                     * to do, it's pretty unlikely that we can rollback, hence we'll just accept the failure,
                     * and continue. */
                    if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0)
                            log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
            }

Chrome沒有特別的技巧; 相反,它是作弊。 它覆蓋到environ區域,但它使用空格而不是空字節來分隔參數。 這在ps看起來完全相同,但是如果用xxd或類似的方法檢查/proc/PID/environ文件,你會看到它正在做什么。 這使得它基本上忽略了你發現的“任何包含空間中的NULL分隔符到達最初環境的東西被視為結束”的約束。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM