Syscall User Dispatch

# TL;DR syscallのキャプチャをする新しい仕組みが、5.11から入ったよ

- Wineとかを動かすときに、kernel介さずに高速にsyscall切り替えるための仕組みっぽい。
    - DRM関係でできなかったゲームができるかも！と期待の声が。
- セキュリティのサンドボックスじゃないので、そこは気をつけましょう。

# はじめに
Linux Kernel 5.11で、Wineを効果的に動かすための新しい機能が入ったらしい(Wine側対応可否はまた別問題）

https://gihyo.jp/admin/clip/01/linux_dt/202102/17

> 「WINE」など非Linuxのシステムコールをリダイレクトするメカニズムを追加，ユーザスペースでのダイレクトなWindowsバイナリ実行が可能に

https://linuxreviews.org/Linux_5.11_Supports_Syscall_User_Dispatch_Which_Could_Allow_More_Windows_Games_With_DRM_To_Run_Under_Wine_In_The_Future


# 修正箇所とかはこのあたりかな？

https://lwn.net/Articles/838502/


# このドキュメントの内容を確認していく。

https://www.kernel.org/doc/html/latest/admin-guide/syscall-user-dispatch.html

.. SPDX-License-Identifier: GPL-2.0

Syscall User Dispatch
=====================

Background
----------

> Compatibility layers like Wine need a way to efficiently emulate system　calls of only a part of their process - the part that has the　incompatible code - while being able to execute native syscalls without　a high performance penalty on the native part of the process.  Seccomp　falls short on this task, since it has limited support to efficiently　filter syscalls based on memory regions, and it doesn't support removing　filters.  Therefore a new mechanism is necessary.

Wineのような互換レイヤーでは、処理のnativeな武運においては高い性能へのペナルティなくnativeのsyscallsが実行できるとともに、互換性が無いコードを持つ部分ではシステムコールを効果的にエミュレーションする方法が必要です。Seccompではメモリ領域に基づいてsyscallを効果的にフィルターするサポートには制限があります。そしてフィルターを除外することはできません。そこで、新しい仕組みが必要になりました。

> Syscall User Dispatch brings the filtering of the syscall dispatcher　address back to userspace.  The application is in control of a flip switch, indicating the current personality of the process.  A multiple-personality application can then flip the switch without invoking the kernel, when crossing the compatibility layer API boundaries, to enable/disable the syscall redirection and execute syscalls directly (disabled) or send them to be emulated in userspace through a SIGSYS.

**Syscall User Dispatch** は、ユーザー空間のアドレスを戻す、syscall dispatcherのフィルターを提供します。アプリケーションは、flip switchを制御することで、プロセスの現在のpersonalityを提示できます。multi personality アプリケーションでは、互換レイヤーAPI境界を越える際に、kernelを呼び出すことなくswitchをslipすることもできます。これによって、syscall redirectionやsyscallの直接実行を切り替えることができます。また、SIGSYSを介してuserspaceないでそれらを送ることをエミュレーションすることもできます。

> The goal of this design is to provide very quick compatibility layer boundary crosses, which is achieved by not executing a syscall to change personality every time the compatibility layer executes.  Instead, a userspace memory region exposed to the kernel indicates the current personality, and the application simply modifies that variable to configure the mechanism.

この設計の目的は、互換レイヤー境界の超越を高速にすることにあります。これは、互換レイヤーでの実行時において、毎回personalityが変化するべくsyacallを実行することを意味しません。その代わりに、userspace memory regionによって、kernelにこのpersonalityを提示します(exposed、暴露、あるいは開示)。そして、applicationは仕組みの設定をただ変更するだけです。

> There is a relatively high cost associated with handling signals on most architectures, like x86, but at least for Wine, syscalls issued by native Windows code are currently not known to be a performance problem, since they are quite rare, at least for modern gaming applications.

x86のような多くのアーキテクチャでは、signalのハンドリングに対して高い関連コストが発生します。しかし、少なくともWineでは、native windows codeによって実施されるsyscallは、現時点ではパフォーマンス問題にはなっていません。近年のゲームアプリケーションを実行する場合においては、それらは稀です。

> Since this mechanism is designed to capture syscalls issued by
non-native applications, it must function on syscalls whose invocation ABI is completely unexpected to Linux.  Syscall User Dispatch, therefore doesn't rely on any of the syscall ABI to make the filtering.  It uses only the syscall dispatcher address and the userspace key. 

この仕組みは、non-native applicationがsyscallを実行するのをキャプチャするように設計されているため、linuxが完全に予期していないAVIの呼び出しで、syscallによって動作することがあります。Syscall User Dispatchは、フィルタリングを行うために、何らかのsyscall ABIの実行も行いません。これはただ、syscall dispatcher addressとuserspace keyだけを使います。

> As the ABI of these intercepted syscalls is unknown to Linux, these syscalls are not instrumentable via ptrace or the syscall tracepoints.

これらの割り込まれたsyscallsのABIは、linuxによって認識されていません。これらのsyscallsはptraceやsyscall tracepointによって手助けにはなりません。

Interface
---------

>A thread can setup this mechanism on supported kernels by executing the following prctl:

threadでは、以下に示すprctlを実行することで、カーネルに対して、この仕組みのセットアップを支持できます。

```
  prctl(PR_SET_SYSCALL_USER_DISPATCH, <op>, 
        <offset>, <length>, [selector])
```

> \<op> is either PR_SYS_DISPATCH_ON or PR_SYS_DISPATCH_OFF, to enable and disable the mechanism globally for that thread.  When
PR_SYS_DISPATCH_OFF is used, the other fields must be zero.

**\<op>** は、PR_SYS_DISPATCH_ON or PR_SYS_DISPATCH_OFFのいずれかを指定してください。それらは、スレッドにおいて全体的にこの仕組みを有効化するか無効化するかを意味します。PR_SYS_DISPATCH_OFF を指定する場合には、残りのフィールドはzeroでなければなりません。

> [\<offset\>, \<offset>+\<length\>) delimit a memory region interval from which syscalls are always executed directly, regardless of the userspace selector.  This provides a fast path for the C library, which includes the most common syscall dispatchers in the native code applications, and also provides a way for the signal handler to return without triggering a nested SIGSYS on (rt\_)sigreturn.  Users of this interface should make sure that at least the signal trampoline code is included in this region. In addition, for syscalls that implement the trampoline code on the vDSO, that trampoline is never intercepted.

**[\<offset\>, \<offset>+\<length\>)** は、userspace selectorを無視して、syscallが常に直接実行されるメモリ領域範囲を区切るものです。これはC libraryに対するfast pathを提供します。これは、native code applicationで最も一般的なsyscall dispacheを含んでいます。また、 (rt\_)sigreturnにおけるnestedされたSIGSYSを契機とせずに、singal handlerへ戻る手段を提供します。このインタフェイスのユーザーは、少なくとも１つのsignal トランポリンコードをこの領域に含めなければならないです。更に、vDSOにおけるトランポリンコードの実装のためのsyscallsでは、トランポリンは割り込まれることはありません。

> [selector] is a pointer to a char-sized region in the process memory region, that provides a quick way to enable disable syscall redirection thread-wide, without the need to invoke the kernel directly.  selector can be set to SYSCALL_DISPATCH_FILTER_ALLOW or SYSCALL_DISPATCH_FILTER_BLOCK.
Any other value should terminate the program with a SIGSYS.

**[selector]** は、プロセスメモリ領域内におけるregionのchar sizeの示すポインタです。これは、カーネルを直接呼び出す事なしに、スレッド全体でsyscall redirectionを有効/無効にするための迅速な方法を提供します。selectorはまた、SYSCALL_DISPATCH_FILTER_ALLOW やSYSCALL_DISPATCH_FILTER_BLOCKを設定することもできます。その他の値は、SIGSYSを介してプログラムを終了する必要があります。

Security Notes
--------------

> Syscall User Dispatch provides functionality for compatibility layers to quickly capture system calls issued by a non-native part of the application, while not impacting the Linux native regions of the process.  It is not a mechanism for sandboxing system calls, and it should not be seen as a security mechanism, since it is trivial for a malicious application to subvert the mechanism by jumping to an allowed dispatcher region prior to executing the syscall, or to discover the address and modify the selector value.  If the use case requires any kind of security sandboxing, Seccomp should be used instead.

**Syscall User Dispatch**は、互換レイヤーに対して、アプリケーションの非native部分によって発行されたシステムコールをキャプチャする機能を、processのlinux native regionに影響を与えずに提供します。これは、syscal callのサンドボックスの仕組みではありません。これは、セキュリティの仕組みと見なすべきでもありません。悪意あるアプリケーションは、syscallを実行する前に許可されたdispatcher領域にジャンプして仕組みを破壊したり、アドレスを探索したり、selectorの値を変更したりすることができます。ユースケースとして何らかのセキュリティサンドボックスが必要な場合には、Seccompを代わりに用いる必要があります。

> Any fork or exec of the existing process resets the mechanism to PR_SYS_DISPATCH_OFF.

存在するプロセスのforkまたはexecは、PR_SYS_DISPATCH_OFFの仕組みによってリセットされます。

# まとめ

- Wineとかを動かすときに、kernel介さずに高速にsyscall切り替えるための仕組みっぽい。
    - DRM関係でできなかったゲームができるかも！と期待の声が。
- セキュリティのサンドボックスじゃないので、そこは気をつけましょう。