私の/dev/input/event*ファイルの権限は次のとおりです。
crw-rw---- 1 root input 13, 64 Mar 21 09:02 /dev/input/event0
crw-rw---- 1 root input 13, 65 Mar 21 09:02 /dev/input/event1
crw-rw---- 1 root input 13, 66 Mar 21 09:02 /dev/input/event2
crw-rw---- 1 root input 13, 67 Mar 21 09:02 /dev/input/event3
crw-rw---- 1 root input 13, 68 Mar 21 09:02 /dev/input/event4
...
+
ご覧のとおり、権限の後には何もありません。これは特別なACL権限がないことを意味します。私も確認しましたgetfacl
。私もこのグループのメンバーではなく、input
X11をrootとして実行しません。startx
ユーザーとしてログインしたら、コンソールに手動で入力してxorgを起動しました。
だから私の質問はどのようにそしてどこudevは、ACLなしでこれらのファイルを開くためのX11入力ドライバ(xf86-input-libinputなど)権限を付与しますか?
/dev/input/eventファイルを開くには、グループを使用するかsudo
グループの一部にする必要がありますinput
が、ルートレスX11は問題なくそれを行うことができるようです!
これは権限の問題を示す最小限のCプログラムです。 keybit_limitが578未満の値に設定されている場合、X11ドライバは対応する/ dev / input / eventを読み取る権限を持ち、ユーザーが指定した名前のデバイスがxinput出力に表示されます。 KEY_CNT より高い値は Xorg ログに権限エラーを引き起こし、xinput は新しいデバイスを表示しません。それでもsudo evtest
。 / dev / input / eventの権限とグループはどちらの場合もまったく同じですが、KEY_CNTシナリオでは、X11はそれを読み取ることができず、1 2 3キーはXorgに登録されません。
#include <stdio.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/uinput.h>
#define ERROR(format, ...) { \
fprintf(stderr, "\x1b[31merror: " format "\x1b[0m\n", ##__VA_ARGS__); \
return 1; \
}
#define SEND_EVENT(ev_type, ev_code, ev_value) { \
uev.type = ev_type; \
uev.code = ev_code; \
uev.value = ev_value; \
write(ufd, &uev, sizeof(uev)); \
}
int main(int argc, char *argv[]) {
if (argc < 2) ERROR("needs uinput device name!");
int ufd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (ufd < 0) ERROR("could not open '/dev/uinput'");
ioctl(ufd, UI_SET_EVBIT, EV_KEY);
int keybit_limit;
/* X11 will recognize this device for me */
// keybit_limit = 577;
/* but anything above that will cause permission denied errors in xorg log and xinput will not show the device */
keybit_limit = KEY_CNT;
for (int i = 0; i < keybit_limit; i++) {
if (ioctl(ufd, UI_SET_KEYBIT, i) < 0) ERROR("cannot set uinput keybit: %d", i);
}
struct uinput_setup usetup;
memset(&usetup, 0, sizeof(usetup));
usetup.id.bustype = BUS_USB;
strcpy(usetup.name, argv[1]);
if (ioctl(ufd, UI_DEV_SETUP, &usetup) < 0) ERROR("cannot set up uinput device");
if (ioctl(ufd, UI_DEV_CREATE) < 0) ERROR("cannot create uinput device");
struct input_event uev;
uev.time.tv_sec = 0;
uev.time.tv_usec = 0;
sleep(1);
/* press 1 2 3 */
SEND_EVENT(EV_KEY, KEY_1, 1);
SEND_EVENT(EV_KEY, KEY_2, 1);
SEND_EVENT(EV_KEY, KEY_3, 1);
SEND_EVENT(EV_SYN, SYN_REPORT, 0);
/* release 1 2 3 */
SEND_EVENT(EV_KEY, KEY_1, 0);
SEND_EVENT(EV_KEY, KEY_2, 0);
SEND_EVENT(EV_KEY, KEY_3, 0);
SEND_EVENT(EV_SYN, SYN_REPORT, 0);
/* give you time to check xinput */
sleep(300);
ioctl(ufd, UI_DEV_DESTROY);
close(ufd);
return 0;
}
keybit_limit = KEY_CNT
以下は、プログラムに渡されたuinputデバイス名が「MYDEVICE」の場合、~/.local/share/xorg/Xorg.0.logファイルに表示される許可エラーです。
[ 28717.931] (II) config/udev: Adding input device MYDEVICE (/dev/input/event24)
[ 28717.931] (**) MYDEVICE: Applying InputClass "libinput pointer catchall"
[ 28717.931] (**) MYDEVICE: Applying InputClass "libinput keyboard catchall"
[ 28717.931] (**) MYDEVICE: Applying InputClass "system-keyboard"
[ 28717.931] (II) Using input driver 'libinput' for 'MYDEVICE'
[ 28717.933] (EE) systemd-logind: failed to take device /dev/input/event24: No such device
[ 28717.933] (**) MYDEVICE: always reports core events
[ 28717.933] (**) Option "Device" "/dev/input/event24"
[ 28717.933] (EE) xf86OpenSerial: Cannot open device /dev/input/event24
Permission denied.
[ 28717.933] (II) event24: opening input device '/dev/input/event24' failed (Permission denied).
[ 28717.933] (II) event24 - failed to create input device '/dev/input/event24'.
[ 28717.933] (EE) libinput: MYDEVICE: Failed to create a device for /dev/input/event24
[ 28717.933] (EE) PreInit returned 2 for "MYDEVICE"
[ 28717.933] (II) UnloadModule: "libinput"
xorg.conf.dファイルを使用してX11用のevdevドライバとlibinputドライバをテストしましたが、どちらも同じように動作します。自分自身をinput
グループに入れるか、デバイスのudevルールでuaccessタグを使用すると、X11ドライバがそれを読み取ることができます。これは、<578 シナリオではデバイスが root として読み取られるが、KEY_CNT シナリオではデバイスがユーザとして読み取られることを示しています。
なぜそんなことですか?どのプロセスがこれを実行していますか?
答え1
Xorgはデバイスノードを直接開けません。デバイスにD-Bus IPC呼び出しを行います。システムログイン呼び出し元に代わってデバイスノードを開き(フォアグラウンドttyでどのユーザーが「ログイン」したかなどを確認した後)、D-Busのfdパス機能SCM_CREDENTIALSを使用してファイル記述子をXorg(Unixソケットベース)に渡すサービス)の機能。
バラよりorg.freedesktop.login1(5)関連するTakeDevice()
D-Bus APIの場合。
この方法を使用すると、フロント tty が別のユーザーのセッションに切り替えられたときに systemd-logind が入力デバイスへのアクセスを積極的に取り消すことができます (逆に ACL を設定および削除すると、1 人のプログラムが単にファイル記述子を開く残してinputを読み続けることができます)。他のユーザーのセッションが前景にある場合)。
システム化されていないディストリビューションの場合、Seatdは機能的に似たAPI(libseat_open_device)を提供しますが、Xorgはまだそれをサポートしておらず、代わりにsetuidXorg.wrap
ラッパーに依存しています。
(終了メカニズムは入力デバイス固有のioctl(EVIOCREVOKE)です。DRMデバイスにも同様のメカニズムがありますが、これまでオーディオやカメラデバイスに対応するメカニズムはありません。パイプラインなどのサウンドサーバーはログイン「セッションスイッチ」を受信します。 (信号を送信し、デバイスの電源を切ってから再びオンにすることに協力してください。)
答え2
UdevはX11入力ドライバに「権限を付与」しません。 Udevはあなたが示したデバイスノードを作成し、完了したら入力デバイスの操作はデフォルトで完了します。システムの残りの部分は、割り当てられたデバイス権限を処理する必要があります。
startx
/usr/bin/xinit
通常、そのタスクを実行するスクリプトです。
最新のXorg Xサーバーでは、setuid root権限を小さなスタンドアロンラッパーとして使用できることがわかりました/usr/lib/xorg/Xorg.wrap
。マニュアルXwrapper.config(5)
ページは次のとおりです。
説明する
Xorg X サーバーが正常に動作するには、root 権限が必要な場合があります。これらの権限でXorg Xサーバーを起動するには、システムは/usr/lib/xorg/Xorg.wrapとしてインストールされたsuidルートラッパーを使用します。これにより、インストールされている物理Xサーバーを実行します
/usr/lib/xorg/Xorg
。デフォルトでは、Xorg.wrap は root 権限が必要かどうかを自動的に検出し、そうでない場合は実際の X サーバーを起動する前に高い権限を放棄します。デフォルトでは、Xorg.wrap は物理コンソールのログインセッションでのみ物理 X サーバーの実行を許可します。
これはDebian 11にあります。ディストリビューションが少し異なるパスを使用できます。
ランニングls -l /usr/bin/xinit /usr/bin/Xorg /usr/lib/xorg/Xorg.wrap
。報告された権限にs
一般的な権限の代わりに含まれる場合、x
答えは次のようになります。s
最初のx
場所(-rws......
)にある場合、実行可能ファイルはその権限の権限で実行されます。ファイル所有者(これはしばしばそのような状況の原因です)。しばしば実行可能ファイルと呼ばれます。setuid ルートまたは水の根。
2番目の場所にいる場合、s
プロセスは次のメンバーシップを取得します。実行可能ファイルを所有するグループ ランタイム:実行可能ファイルと呼ばれます。設定またはシードそのグループに。 (setgid許可ビットは、使用されているファイルシステムの種類によっては、ディレクトリまたは実行不可能なファイルに対して異なる意味を持つことができます。)
ファイルをコピーするとき、setuidおよびsetgid権限ビットは通常コピーされません。コピーしてもrootが所有するファイルをコピーすると、新しいコピーはrootではなくユーザーの所有になります。他のユーザーがコピーされた実行可能ファイルを実行できるようにすることができます。あなたしかし、ルートになるのには役立ちません。コピーするsetuid ルートファイルは完全な権限を維持するため、直接ルートにする必要があります。