web-dev-qa-db-ja.com

疑似端末(unlockpt / TIOCSPTLCK)はセキュリティ機能ですか?

疑似端末のマスター部分を開いた後

int fd_pseudo_term_master = open("/dev/ptmx",O_RDWR);

疑似端末のslave部分を表す、作成されたファイル_/dev/pts/[NUMBER]_があります。

私のような無知な人は、ptsname(fd_pseudo_term_master,filename_pseudo_term_slave,buflen);を実行した後、simplydo int fd_pseudo_term_slave = open(filename_pseudo_term_slave,O_RDWR);に設定して問題を解決する必要があると想像するかもしれません。

ただし、「ロックされた」疑似端末スレーブの非常に重要な使用例が必要です。単純にするために、open呼び出しを行う前に、 man 3unlockpt)を使用する必要があるためです。 、「ロックを解除」します。

このユースケースが何であるかを知ることができませんでしたか?疑似端末を最初にロックする必要はありますか?コードで達成されること(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カーネルソースを詳しく調べました。ただし、疑似端末の最初のロックダウンの場合から「抽出」できる1つの用途は、疑似端末マスタープロセスが_/dev/pts/[NUMBER]_にあるファイルへのアクセス権を設定するための時間を提供することです。そもそも一部のユーザーがファイルにアクセスできないようにするため。これは答えの一部になることができますか?しかし、ひどく、そのような「初期ロックダウン」状態は、少なくともここでアトミック性が保証されていると私が考える限り、とにかくスレーブファイルの複数のオープンを実際に防ぐことはできないようです。

3

疑似端末スレーブデバイス用の古いAT&T System 5メカニズムは、それらが/devの下の通常の永続的文字デバイスノードであったというものでした。 /dev/ptmxにマルチプレクサmasterデバイスがありました。疑似端末デバイス用の古い4.3BSDメカニズムには、/devの下に通常の永続的マスターデバイスノードとスレーブデバイスノードの並列ペアがありました。

どちらの場合も、これは、スレーブデバイスファイルが最後のファイル記述子のクローズ後も最後の所有権とアクセス許可を保持することを意味しました。したがって、(再利用された)疑似端末が(再)割り当てられた後、スレーブデバイスファイルの所有権とアクセス許可を修正するためのgrantpt()関数の進化。

これは、プログラムがopen()grantpt()の間に再利用された疑似端末をセットアップしているときに、事前にスレーブデバイスを所有していた人が侵入して侵入できるウィンドウがあったことを意味します。それも開いて、他の誰かの端末にアクセスできる可能性があります。したがって、疑似端末スレーブ文字デバイスは、unlockpt()が正常に実行された後、開くことができず、grantpt()によってロック解除されるロック状態で開始するという考えです。

何年にもわたって、これは不要であることが判明しました。

現在、カーネルは/dev自体で物事を作成および破棄するため、スレーブデバイスファイルは永続的ではありません。マスターデバイスを開く動作は、スレーブデバイスのアクセス許可と所有権をリセットするか、スレーブデバイスファイルを完全に作成します(後者の場合、開いているすべてのファイル記述子が閉じられるとスレーブデバイスファイルが再び消えます)。同じシステムコール。

  • OpenBSDでは、これは/dev/ptmデバイス上のPTMGET I/Oコントロールの機能の一部です。 /devはまだディスクボリュームであり、カーネルは内部で関連する呼び出しを発行して、そこに新しいデバイスノードを作成し、それらの所有権とアクセス許可をリセットします。
  • FreeBSDでは、これはposix_openpt()システムコールによって行われます。 /devはディスクボリュームではありません。これはdevfsファイルシステムです。 posix_openpt()は完全なシステムコールであり、開いているファイル記述子でラップされたioctl()ではないため、「マルチプレクサ」デバイスもマスターデバイスファイルも含まれていません。スレーブデバイスは、pts/ディレクトリの下のdevfsファイルシステムに表示されます。

したがって、カーネルは、最初から適切な権限と所有権を持っていることを保証し、古いものを持っている機会の窓はありません。したがって、grantpt()およびunlockpt()ライブラリ関数は基本的に操作なしであり、残りの機能は、渡されたファイル記述子をチェックし、疑似端末のマスター側でない場合はEINVALを設定することだけです。 、プログラムは、これらの関数に非疑似端末ファイル記述子を渡し、エラーを返すことを期待するなど、巧妙なことをしている可能性があるためです。

Linuxではしばらくの間、疑似端末スレーブデバイスは永続的なデバイスノードでした。 GNU Cライブラリのgrantpt()はシステムコールではありませんでした。むしろ、pt_chownという名前のset-UIDヘルパープログラムをフォークして実行しましたが、no set-UID実行可能ファイル群集。(grantpt()は、特権のないユーザーが特別なデバイスファイルの所有権とアクセス許可を変更できるようにする必要があります。必然的に所有していることを覚えておいてください。)したがって、まだチャンスの窓があり、Linuxはunlockpt()のロックを維持する必要がありました。

その「新しい」devptsファイルシステム(「新しい」はかなり数年前に導入されたことを意味します)ほぼはFreeBSDと同じ方法で物事を行うことができますただし、devfsを使用します。いくつかの違いがあります。

  • 「マルチプレクサ」デバイスはまだあります。
    • older "new" devptsシステムでは、これは別のptmxファイルシステムのdevtmpfsデバイスであり、devptsファイルシステムには自動的に作成/破棄されたスレーブのみが含まれていましたデバイスファイル。従来、セットアップは/dev/ptmxであり、それに付随するdevpts/dev/ptsにマウントされていました。
    • しかし、Linuxの人々は、コンテナなどのために、devptsファイルシステムの複数の完全に独立したインスタンスを持ちたいと考えていました。正しい)多くのdevtmpfsおよびdevptsファイルシステムがあった場合の2つのファイルシステム。したがって、newer "new" devptsシステムでは、マルチプレクサとスレーブのすべてのデバイスが1つのファイルシステムにあります。下位互換性のために、デフォルトでは、新しいptmxマウントオプションを設定しない限り、新しいptmxmodeノードにアクセスできませんでした。
    • さらに新しい「新しい」devptsでは、ptmxファイルシステムのdevptsデバイスファイルがプライマリマルチプレクサになり、ptmxdevtmpfsはいずれかです。シンボリックリンク、バインドマウント、またはpts/ptmxへのプレーンな古いactualシンボリックリンクを模倣しようとするカーネルによって提供されるshim。
  • カーネルは、grantpt()のように所有権と権限を常に設定するとは限りません。間違ったマウントオプションを設定すると、gidGID以外のttyまたは0620以外のmodeが、GNU Cライブラリでフォールバック動作をトリガーします。grantpt()をに減らすために必要に応じてGNU Cライブラリで操作を行わない場合、カーネルはnotオープニングプロセスのグループを割り当てる必要があります(つまり、明示的なgid設定が必要です)、割り当てられるグループはttyグループである必要があり、新しく作成されたスレーブデバイスのmodeは正確に0620である必要があります。

デフォルトで/dev/pts/ptmxをオンにせず、GNU Cライブラリがgrantpt()を完全にノーオペレーションに削減しないのは、カーネルとCライブラリがロックステップで維持されていないためです。 Linuxはまだ古い/dev/ptmxを提供する必要がありました。GNU Cライブラリは、正しいdevptsファイルシステムがない場合でもpt_chownの実行にフォールバックする必要があります。オプションを所定の位置にマウントします。

したがって、devptsマウントオプションが間違っていて、GNU Cライブラリが実際に何かを実行するようにフォールバックする必要がある場合、Linuxでunlockpt()が防御する機会はまだ存在しますgrantpt()で。

参考文献

5
JdeBP