偽終端( unlockpt / TIOCSPTLCK )是安全功能嗎?
打開偽終端的主控部分後
int fd_pseudo_term_master = open("/dev/ptmx",O_RDWR);
有
/dev/pts/[NUMBER]
創建的文件,代表slave
他的偽終端的一部分。像我這樣無知的人可能會認為,在完成之後,
ptsname(fd_pseudo_term_master,filename_pseudo_term_slave,buflen);
應該將其設置為簡單地 做好事int fd_pseudo_term_slave = open(filename_pseudo_term_slave,O_RDWR);
。然而,必須有一個非常重要的“鎖定”偽終端從機案例,因為為了簡單起見,在
open
呼叫之前,必須使用man 3 unlockpt來“解鎖”。我無法找出這個案例是什麼?最初鎖定偽終端需要什麼?用程式碼實現了什麼(取自 libc)
/* Unlock the slave pseudo terminal associated with the master pseudo terminal specified by FD. */ int unlockpt (int fd) { #ifdef TIOCSPTLCK int save_errno = errno; int unlock = 0; if (ioctl (fd, TIOCSPTLCK, &unlock)) { if (errno == EINVAL) { errno = save_errno; return 0; } else return -1; } #endif /* If we have no TIOCSPTLCK ioctl, all slave pseudo terminals are unlocked by default. */ return 0; }
如果可能,答案將詳細說明案例,歷史或目前。
問題的額外部分是:
目前的 linux 核心是否仍然依賴於“鎖定偽終端從站”的這種功能?
想法:這是避免比賽的低效嘗試嗎?
等待答案我已經更多地研究了 linux 核心原始碼,但自己沒有任何好的答案。然而,似乎可以從偽終端的初始鎖定情況中“提取”的一種用途是為偽終端主程序提供一些時間來設置對文件的一些訪問權限
/dev/pts/[NUMBER]
,以防止某些使用者首先訪問該文件。這可以作為答案的一部分嗎?奇怪的是,然而,這種“初始鎖定”狀態似乎並不能真正阻止從屬文件的多次打開,至少我認為在這裡可以保證原子性。
用於偽終端從設備的舊 AT&T System 5 機制是它們是
/dev
. 有一個多路復用器主設備/dev/ptmx
。用於偽終端設備的舊4.3BSD 機制在/dev
.在這兩種情況下,這意味著從設備文件在最後一個文件描述符關閉後保留了它們最後的所有權和權限。
grantpt()
因此,在(重用)偽終端已(重新)分配後修復從設備文件的所有權和權限的功能的演變。
open()
這反過來意味著,當程序在和之前擁有從設備的人之間設置一個重複使用的偽終端時,有一個視窗grantpt()
可以潛入並打開它,可能會訪問其他人的終端. 因此,偽終端從字元設備的想法開始於鎖定狀態,在該狀態下它們無法打開,並在成功執行unlockpt()
後解鎖。grantpt()
多年來,事實證明這是不必要的。
如今,從設備文件不是持久的,因為核心自己製造和銷毀東西
/dev
。打開主設備的行為要麼重置從設備權限和所有權,要麼直接重新創建從設備文件(在後一種情況下,當所有打開的文件描述符關閉時,從設備文件再次消失),在任何一種情況下都是原子的相同的系統呼叫。
- 在 OpenBSD 上,這是設備
PTMGET
上 I/O 控制項功能的一部分/dev/ptm
。/dev
仍然是一個磁碟捲,核心在內部發出相關呼叫以在那裡創建新的設備節點並重置它們的所有權和權限。- 在 FreeBSD 上,這是由
posix_openpt()
系統呼叫完成的。/dev
根本不是光碟捲。它是一個devfs
文件系統。它不包含“多路復用器”設備或主設備文件,因為posix_openpt()
是直接的系統呼叫,而不是包裝ioctl()
在打開的文件描述符上。從設備出現在devfs
其pts/
目錄下的文件系統中。因此,核心確保他們從頭開始擁有正確的權限和所有權,並且沒有機會之窗讓他們擁有陳舊的權限。因此,
grantpt()
和unlockpt()
庫函式本質上是無操作的,其唯一剩下的功能是檢查它們傳遞的文件描述符並設置EINVAL
它是否不是偽終端的主端,因為程序可能會做一些愚蠢的事情,比如傳遞非偽-這些函式的終端文件描述符並期望它們返回錯誤。有一段時間,在 Linux 上,偽終端從設備是持久設備節點。GNU C 庫
grantpt()
不是系統呼叫。相反,它派生並執行了一個名為 的 set-UID 幫助程序,這讓沒有 set-UID 執行檔的人群pt_chown
感到非常沮喪。(必須允許非特權使用者更改它不一定擁有的特殊設備文件的所有權和權限,記住。)所以仍然有機會之窗,Linux 仍然必須為.grantpt()``unlockpt()
然而,它的“新”
devpts
文件系統(其中“新”意味著幾年前引入,現在)幾乎允許使用與在 FreeBSD 上相同的方式做事devfs
。有一些差異。
還有一個“多路復用器”設備。
- 在舊的“新”
devpts
系統中,這是ptmx
不同devtmpfs
文件系統中的設備,devpts
文件系統僅包含自動創建/銷毀的從設備文件。傳統上,該設置是/dev/ptmx
和一個隨附的devpts
安裝在/dev/pts
.- 但是 Linux 人希望有多個完全獨立的文件系統實例
devpts
,用於容器等,當有很多devtmpfs
文件系統時,要同步(正確的)兩個文件系統是相當困難的devpts
。因此,在較新的“新”devpts
系統中,所有設備,多路復用器和從設備,都在一個文件系統中。為了向後兼容,預設設置ptmx
是無法訪問新節點,除非設置了新的ptmxmode
掛載選項。- 在甚至更新的仍然“新”
devpts
的文件系統ptmx
中的設備文件devpts
現在是主要的多路復用器,並且其中ptmx
要麼devtmpfs
是核心提供的一個 shim,它試圖模仿一個符號連結,一個綁定掛載,或者一個普通的舊的實際符號連結到pts/ptmx
.核心並不總是按
grantpt()
應有的方式設置所有權和權限。設置錯誤的掛載選項(gid
不是tty
GID 或mode
0620)會觸發 GNU C 庫中的回退行為。為了grantpt()
在 GNU C 庫中按照需要減少到無操作,核心必須不分配打開程序的組(即必須有明確的gid
設置),分配的組必須是tty
組,mode
新的創建的從設備必須正好是 0620。預設情況下不打開
/dev/pts/ptmx
和 GNU C 庫沒有完全減少grantpt()
到無操作都是因為核心和 C 庫沒有保持同步。每個都必須使用另一個舊版本。Linux 仍然必須提供較舊的/dev/ptmx
.pt_chown
如果沒有devpts
具有正確掛載選項的新文件系統,GNU C 庫仍然必須返回執行。因此
unlockpt()
,如果devpts
掛載選項錯誤並且 GNU C 庫因此不得不退回到實際在grantpt()
.進一步閱讀
- https://unix.stackexchange.com/a/470853/5132
- 解決這個 glibc 問題的最佳方法是什麼?
- https://unix.stackexchange.com/a/214685/5132
Documentation/filesystems/devpts.txt
. Linux 核心。- 丹尼爾·伯蘭奇 (2009-05-20)。
/dev/pts
必須使用“newinstance”掛載標誌來避免容器的安全問題。紅帽錯誤 #501718。- 喬納森·德博因·波拉德 (2018)。
open-controlling-tty
. 小吃指南。軟體。- 喬納森·德博因·波拉德 (2018)。
vc-get-tty
. 小吃指南。軟體。- 喬納森·德博因·波拉德 (2018)。
pty-get-tty
. 小吃指南。軟體。