20

この一連のコマンドは機能します。

unshare --fork --pid --mount 
umount /proc
mount -t proc proc /proc
umount /dev/pts
mount -t devpts devpts /dev/pts

ただし、対応する C プログラムは期待どおりに動作しません (以前の /proc をアンマウントしないようであり、devpts をアンマウントしようとする EBUSY も提供します):

unshare(CLONE_NEWPID | CLONE_NEWNS );
int pid = fork();
if (pid != 0) {
    int status;
    waitpid(-1, &status, 0);
    return status;
}

printf("My pid: %i\n", getpid()); // It prints 1 as expected

umount("/proc"); // Returns 0

system("mount"); // Should print error on mtab, but it prints the previous mounted filesystems

mount("proc", "/proc", "proc",
      MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV,
      NULL));  // Returns 0

umount("/dev/pts");  // Returns -1 errno = 0 (??)

mount("devpts", "/dev/pts", "devpts", 
      MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV,
      NULL) ); // Returns -1 errno = EBUSY

ここでは読みやすさのためにエラーチェックを省略しました

unshare または unmount は期待どおりに機能しないと思います: ゼロが返されたとしても、/proc をアンマウントしていないようです (system("mount")その後で a を実行しようとすると、マウントされたファイルシステムが出力されます)。

4

4 に答える 4

2

というご意見にも関わらず

「ときどき」は 0 を返します 「ときどき」-1 を返しますが、結局まったくアンマウントしumountません/proc

、あなたのペーストビンからのコードの10000回の試行で、umount() 常に失敗し、戻っ-1てアンマウントしませんでし/procた。要求されたアンマウントの実行に失敗したにもかかわらず、 がumount()戻ってくるとは信じたくありませんが、もしそうなら、それは のバグになります。実際にそのようなバグを実証できる場合、コミュニティ志向の対応は、glibc に対してバグ レポートを提出することです。0umount()


bash問題は、スクリプトの動作が異なる理由と方法になります。しかし、実際にはそうではないようです。

そもそも、unshare(1)コマンドに対する期待が間違っています。unshare(2)関数とは異なり、unshareコマンドはそれが実行されるシェルには影響しません。代わりに、指定された名前空間の独自のプライベート コピーを持つ別のプロセスを起動します。通常、unshareコマンド ラインでそのプロセスを起動するコマンドを指定します。実際、プログラムのマニュアル ページでは、そのようにすることが必須であることが示されています。

経験的に、私がそのようなコマンドを指定し損ねた場合 (あなたのようunshareに)、ターゲット プロセスとして新しいシェルを起動することがわかりました。特に、スクリプトを (を使用するのに十分な特権でunshare) 実行すると、すぐに新しいプロンプトが表示されますが、これはフォアグラウンドで実行されている新しいシェルのプロンプトです。プロンプトが異なるため、これはすぐにわかります(ただし、これらの状況ではプロンプトが変わらない場合があります)。まだ実行していないumountため、その時点からエラー メッセージなどはありません。( d) サブシェルで手動でproc を実行しようとすると、「デバイスがビジー状態です」というメッセージが表示されて失敗します。これは、C プログラムが試みていることと似ています。umountunshare

サブシェルを終了すると、残りのスクリプトが実行され、両方umountの s と両方mountの s が失敗します。メイン スクリプトはそのマウント名前空間を共有しているため、これは当然のことです。


/procマウント名前空間のプライベート コピーを持っているプロセスであっても、実際にビジーであり、したがってアンマウントできないというのは完全にもっともらしいことです。そのようなプロセス自体が のマウントのプライベート コピーを使用している可能性があり/procます。対照的に、共有されていないマウント名前空間を持つプロセスでは正常にアンマウントできますが、システムのその名前空間のコピーを共有するプロセスではアンマウントできません。/dev/pts

于 2016-01-27T19:24:06.717 に答える
1

unshare コマンドのソースコードをチェックすると問題が見つかりました。これは基本的に、マウントが現在の (新しい) 名前空間でのみ有効になるようにするためです/procMS_PRIVATE | MS_REC2 番目の問題は/dev/pts、グローバル名前空間に影響を与えずにアンマウントできないことです (これは devpts ドライバーの内部ルーチンが原因です)。/dev/pts を非公開にする唯一の方法は、専用-o newinstanceオプションでマウントすることです。最後/dev/ptmxに、バインド再マウントも行う必要があります。

したがって、これは期待どおりの C 作業コードです。

unshare(CLONE_NEWPID | CLONE_NEWNS );
int pid = fork();
if (pid != 0) {
    int status;
    waitpid(-1, &status, 0);
    return status;
}

printf("New PID after unshare is %i", getpid());

if (mount("none", "/proc", NULL, MS_PRIVATE|MS_REC, NULL)) {
    printf("Cannot umount proc! errno=%i", errno);
    exit(1);
}

if (mount("proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL)) {
    printf("Cannot mount proc! errno=%i", errno);
    exit(1);
}


if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC, "newinstance") ) {
    printf("Cannot mount pts! errno=%i", errno);
    exit(1);
}

if (mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_BIND, NULL) ) {
    printf("Cannot mount ptmx! errno=%i", errno);
    exit(1);
}
于 2016-01-30T21:48:27.543 に答える