Lock

偽終端( unlockpt / TIOCSPTLCK )是安全功能嗎?

  • June 18, 2020

打開偽終端的主控部分後

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()在打開的文件描述符上。從設備出現在devfspts/目錄下的文件系統中。

因此,核心確保他們從頭開始擁有正確的權限和所有權,並且沒有機會之窗讓他們擁有陳舊的權限。因此,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不是ttyGID 或mode0620)會觸發 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/questions/477247