程式 vs. 程序#

這是本章最基本也最重要的觀念:

  • 程式(Program):存放在磁碟上的二進位檔案,是靜態的
  • 程序(Process):程式被載入記憶體執行後的實體,是動態的。每個程序都有自己的 PID(Process ID)、記憶體空間、權限

同一個程式可以被多次執行,產生多個獨立的程序。每個程序都有其父程序(PPID),形成一棵程序樹。

Fork-and-exec:程序誕生的方式#

Linux 中新程序的產生遵循 fork-and-exec 模式:

  1. Fork:父程序複製一份自己,產生子程序。子程序繼承父程序的環境變數與權限
  2. Exec:子程序將自己替換為要執行的新程式

這個機制解釋了為什麼子程序會繼承父程序的環境變數——因為 fork 就是複製。也解釋了為什麼在 Shell 中設定的 export 變數能被子程式讀到——因為子程式是從 Shell fork 出來的。

工作管理(Job Control)#

在 Shell 中,你可以同時管理多個工作:

  • 前景(Foreground):佔用終端,可以互動
  • 背景(Background):不佔用終端,自行執行

關鍵操作:

  • &:將指令直接丟到背景執行
  • Ctrl + Z:暫停目前的前景工作
  • jobs:列出所有背景工作
  • fg:將背景工作拉到前景
  • bg:讓暫停的背景工作繼續執行

nohup:離線後繼續執行#

當你登出 Shell 時,所有的子程序都會收到 SIGHUP 訊號而終止。nohup 讓程序忽略這個訊號,即使登出後仍繼續執行。

在實務中,如果需要長時間執行的任務(如大量資料處理),除了 nohup,更建議使用 screentmux——它們提供完整的 session 管理,可以隨時重新連線查看進度。

訊號(Signal)#

訊號是程序間通訊的一種基本方式。核心或其他程序可以透過訊號來通知目標程序。

常用的訊號:

編號名稱意義
1SIGHUP重新讀取設定檔
2SIGINT中斷(等同 Ctrl+C)
9SIGKILL強制終止(無法被攔截)
15SIGTERM正常終止(程序可以做清理工作)
19SIGSTOP暫停程序

kill -9 是最後手段,不是首選。SIGKILL 會直接殺掉程序,不給它機會做清理(關閉檔案、釋放鎖、儲存狀態)。應該先嘗試 kill(預設送 SIGTERM),讓程序正常結束。

殭屍程序(Zombie Process)#

當子程序結束但父程序尚未讀取其結束狀態時,子程序就會變成殭屍程序(狀態顯示為 Z)。殭屍程序不佔用 CPU 和記憶體資源,但會佔用一個 PID。

少量的殭屍程序通常不是問題——它們只是在等待父程序回收。但如果大量累積,可能代表父程序有 bug(沒有正確 wait() 子程序)。解決方法是終止問題父程序,讓 init/systemd 接管並回收這些殭屍。

程序優先權:PRI 與 Nice#

Linux 是多工系統,CPU 需要在多個程序間分配時間。程序的執行優先順序由兩個值決定:

  • PRI(Priority):由核心動態計算,使用者無法直接修改
  • Nice 值:使用者可調整的「禮讓值」,範圍 -20(最高優先)~ 19(最低優先)

一般使用者只能調高 Nice 值(降低自己的優先權),不能調低。只有 root 可以設定負的 Nice 值。

/proc 虛擬檔案系統#

/proc 是一個虛擬檔案系統——它不存在於磁碟上,而是核心在記憶體中動態產生的。每個正在執行的程序都有一個 /proc/PID/ 目錄,裡面包含了程序的所有資訊。

重要的 /proc 檔案:

路徑內容
/proc/cpuinfoCPU 資訊
/proc/meminfo記憶體使用狀態
/proc/loadavg系統負載
/proc/PID/cmdline程序的啟動指令
/proc/PID/fd/程序開啟的檔案描述子

許多系統監控工具(tophtopps)的底層都是在讀取 /proc。直接讀取 /proc 可以取得最原始、最完整的資訊,在除錯時非常有用。

SELinux:強制存取控制#

DAC vs. MAC#

傳統的 Linux 權限是 DAC(Discretionary Access Control)——由檔案的擁有者決定誰能存取。問題在於:如果一個以 root 身份執行的程式被駭,攻擊者就擁有整個系統的控制權。

SELinux 實現了 MAC(Mandatory Access Control)——即使是 root 的程序,也必須遵守系統定義的安全政策。程序只能存取政策明確允許的資源。

安全本文(Security Context)#

SELinux 為每個程序和檔案都標上安全本文,由三個部分組成:

  • 身份識別(Identity)unconfined_u(使用者程序)、system_u(系統程序)
  • 角色(Role)object_r(檔案)、system_r(程序)
  • 類型(Type)最關鍵的部分。SELinux 的政策主要就是定義「哪種 type 的程序可以存取哪種 type 的檔案」

三種運作模式#

  • Enforcing:強制執行政策,違規操作會被阻擋
  • Permissive:只記錄違規但不阻擋,適合測試和除錯
  • Disabled:完全關閉

許多人遇到 SELinux 導致的權限問題時,第一反應是直接關閉 SELinux。這是不良實踐。正確做法是先切換到 Permissive 模式,查看 audit log 找出被擋的原因,然後調整對應的 boolean 或安全本文。

SELinux 的觀念在現代容器安全中也有對應:Docker 的 AppArmorseccomp profile、Kubernetes 的 PodSecurityPolicy 都是類似的思想——限制程序的能力,即使容器被突破也無法任意操作宿主系統。