程式 vs. 程序#
這是本章最基本也最重要的觀念:
- 程式(Program):存放在磁碟上的二進位檔案,是靜態的
- 程序(Process):程式被載入記憶體執行後的實體,是動態的。每個程序都有自己的 PID(Process ID)、記憶體空間、權限
同一個程式可以被多次執行,產生多個獨立的程序。每個程序都有其父程序(PPID),形成一棵程序樹。
Fork-and-exec:程序誕生的方式#
Linux 中新程序的產生遵循 fork-and-exec 模式:
- Fork:父程序複製一份自己,產生子程序。子程序繼承父程序的環境變數與權限
- Exec:子程序將自己替換為要執行的新程式
這個機制解釋了為什麼子程序會繼承父程序的環境變數——因為 fork 就是複製。也解釋了為什麼在 Shell 中設定的
export變數能被子程式讀到——因為子程式是從 Shell fork 出來的。
工作管理(Job Control)#
在 Shell 中,你可以同時管理多個工作:
- 前景(Foreground):佔用終端,可以互動
- 背景(Background):不佔用終端,自行執行
關鍵操作:
&:將指令直接丟到背景執行Ctrl + Z:暫停目前的前景工作jobs:列出所有背景工作fg:將背景工作拉到前景bg:讓暫停的背景工作繼續執行
nohup:離線後繼續執行#
當你登出 Shell 時,所有的子程序都會收到 SIGHUP 訊號而終止。nohup 讓程序忽略這個訊號,即使登出後仍繼續執行。
在實務中,如果需要長時間執行的任務(如大量資料處理),除了
nohup,更建議使用screen或tmux——它們提供完整的 session 管理,可以隨時重新連線查看進度。
訊號(Signal)#
訊號是程序間通訊的一種基本方式。核心或其他程序可以透過訊號來通知目標程序。
常用的訊號:
| 編號 | 名稱 | 意義 |
|---|---|---|
| 1 | SIGHUP | 重新讀取設定檔 |
| 2 | SIGINT | 中斷(等同 Ctrl+C) |
| 9 | SIGKILL | 強制終止(無法被攔截) |
| 15 | SIGTERM | 正常終止(程序可以做清理工作) |
| 19 | SIGSTOP | 暫停程序 |
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/cpuinfo | CPU 資訊 |
/proc/meminfo | 記憶體使用狀態 |
/proc/loadavg | 系統負載 |
/proc/PID/cmdline | 程序的啟動指令 |
/proc/PID/fd/ | 程序開啟的檔案描述子 |
許多系統監控工具(
top、htop、ps)的底層都是在讀取/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 的 AppArmor、seccomp profile、Kubernetes 的 PodSecurityPolicy 都是類似的思想——限制程序的能力,即使容器被突破也無法任意操作宿主系統。