Systemd-Journald

如何防止程序寫入 systemd 日誌?

  • November 15, 2018

我正在使用第三方 .NET Core 應用程序(VS Code 擴展使用的二進制分發版),不幸的是,它啟用了診斷日誌記錄,但沒有明顯的方法可以禁用它(我已經向作者報告了這一點)。理想的解決方案(除了能夠禁用它)是,如果我可以指定 systemd 它不應該為該特定程序記錄任何內容,但我一直無法找到任何方法來做到這一點。這是我到目前為止所嘗試的一切:

我嘗試的第一件事是重定向stdout到: 。這確實禁用了任何正常輸出,但診斷日誌仍被寫入 systemd 日誌。stderr``/dev/null``dotnet-app > /dev/null 2>&1

我希望應用程序有一個命令行參數,允許我禁用診斷日誌記錄。它確實有一個冗長的參數,但經過試驗,它似乎只對正常輸出產生影響,而不是診斷日誌記錄。

通過使用strace並查找對 的呼叫connect,我發現應用程序將診斷日誌直接寫入/dev/log.

該路徑/dev/log是指向的符號連結/run/systemd/journal/dev-log,因此為了驗證我的發現,我將符號連結更改為指向/dev/null。這確實阻止了診斷日誌顯示在 systemd 日誌中。

我被告知LD_PRELOAD並製作了一個庫,connect用我自己的版本替換了標準,當它嘗試連接到/dev/log. 這在我的測試程序中正常工作,但在 .NET Core 應用程序中失敗,在 .NET Core 應用程序中失敗connect ENOENT /tmp/CoreFxPipe_1ddf2df2725f40a68990c92cb4d1ff1e。我嘗試了我的庫,但即使我所做的只是直接將參數傳遞給標準connect函式,它仍然會失敗並出現同樣的錯誤。

然後我嘗試使用 Linux 命名空間來製作它,以便僅/dev/log指向/dev/null.NET Core 應用程序:unshare --map-root-user --mount sh -c "mount --bind /dev/null /dev/log; dotnet-app $@". 這也因同樣的錯誤而失敗,即使它再次適用於我的測試程序。即使只是使用unshare --map-root-user --mount dotnet-app "$@"也會因錯誤而失敗。

接下來,我嘗試在應用程序執行時gdb關閉文件描述符。/dev/log這有效,但經過一段時間後它會重新打開它。我還嘗試將文件描述符更改為指向,這也有效,但一段時間後/dev/null它也被重置為。/dev/log

我最後一次嘗試是編寫自己的 UNIX 套接字,它會過濾掉所有由 .NET Core 應用程序寫入的內容。這確實有效,但我了解到 PID 與寫入 UNIX 套接字的內容一起發送,因此傳遞給 systemd 日誌的所有內容都會報告來自支持我的 UNIX 套接字的程序的 PID。

現在這個解決方案對我來說是可以接受的,因為在我的系統上幾乎沒有使用/dev/log,但我歡迎更好的解決方案。例如,我讀到有可能將某些東西欺騙為 UNIX 套接字的 root,但我無法找到更多相關資訊。

或者,如果有人可能對為什麼兩者都有任何見解,LD_PRELOAD並且unshare.NET Core 應用程序可能會失敗,而他們對於寫入的簡單 C 測試程序工作正常/dev/log

簡而言之,通過LD_PRELOAD覆蓋syslog(3)而不是 connect(3) 載入您的庫。

Unix 套接字由 syslog(3) glibc 函式使用,該/dev/log函式連接到它並寫入它。覆蓋 connect(3) 可能不起作用,因為 glibc 中的 syslog(3) 實現將執行 connect(2)系統呼叫而不是庫函式,因此LD_PRELOAD掛鉤不會擷取來自 syslog(3) 中的呼叫。

之間有一個斷開連接strace,它顯示系統呼叫,和LD_PRELOAD,它可以覆蓋庫函式(在這種情況下,來自 glibc 的函式。)有一個connect(3) glibc 函式和一個connect(2)系統呼叫的事實也有助於這種混亂。(使用ltrace這裡可能會有所幫助,而是顯示對 syslog(3) 的呼叫。)

您可能可以LD_PRELOAD通過讓您的測試程序直接呼叫 syslog(3) 而不是顯式連接到,來確認您正在執行的覆蓋 connect(3) 不適用於 syslog(3) /dev/log,我懷疑這是 .NET 的方式核心應用程序正在執行。

掛鉤到 syslog(3) 也可能更有用,因為在堆棧中處於更高級別,您可以使用該掛鉤做出決策,例如選擇性地將一些消息轉發到 syslog。(您可以使用 載入 glibc 中的 syslog 函式dlsym(RTLD_NEXT, "syslog"),然後您可以使用該函式指針呼叫 syslog(3) 來獲取您想要從您的鉤子轉發的消息。)

/dev/log用符號連結替換的方法/dev/null是有缺陷的,它/dev/null不接受 connect(2) 操作(僅文件操作,如 open(2)),因此 syslog(3) 將嘗試連接並獲取錯誤並以某種方式嘗試處理它(或者可能將它返回給呼叫者),無論如何,這可能會產生副作用。

希望LD_PRELOAD在這裡您只需要使用 syslog(3) 的覆蓋。

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