내 /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을 루트로 실행하지 않습니다. 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 시나리오에서는 장치가 루트로 읽히지만 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을 설정하고 제거하면 한 사용자의 프로그램이 단순히 파일 설명자를 열어두고 input 을 계속 읽을 수 있습니다). 다른 사용자의 세션이 포그라운드에 있는 경우).
시스템화되지 않은 배포판의 경우 Seatd는 기능적으로 유사한 API(libseat_open_device)를 제공하지만 Xorg는 아직 이를 지원하지 않으며 대신 setuid Xorg.wrap
래퍼에 의존합니다.
(해지 메커니즘은 입력 장치에 특정한 ioctl(EVIOCREVOKE)입니다. DRM 장치에도 비슷한 메커니즘이 있지만 지금까지 오디오나 카메라 장치에 해당하는 메커니즘은 없습니다. 파이프라인과 같은 사운드 서버는 로그인 "세션 스위치"를 수신합니다. ” 신호를 보내고 장치를 껐다가 다시 켜는 데 협조하십시오.)
답변2
Udev는 X11 입력 드라이버에 "권한을 부여"하지 않습니다. Udev는 여러분이 보여준 장치 노드를 생성했으며, 일단 완료되면 입력 장치에 대한 작업이 기본적으로 완료됩니다. 시스템의 나머지 부분은 할당된 장치 권한을 처리해야 합니다.
startx
/usr/bin/xinit
일반적으로 해당 작업을 수행하는 스크립트입니다.
최신 Xorg X 서버에서는 setuid 루트 권한을 작은 독립형 래퍼로 사용할 수 있는 것으로 나타났습니다 /usr/lib/xorg/Xorg.wrap
. 매뉴얼 Xwrapper.config(5)
페이지는 다음과 같습니다.
설명하다
Xorg X 서버가 제대로 작동하려면 루트 권한이 필요할 수 있습니다. 이러한 권한으로 Xorg X 서버를 시작하기 위해 시스템은 /usr/lib/xorg/Xorg.wrap으로 설치된 suid 루트 래퍼를 사용하며, 이는 로 설치된 실제 X 서버를 실행합니다
/usr/lib/xorg/Xorg
.기본적으로 Xorg.wrap은 루트 권한이 필요한지 여부를 자동으로 감지하고 그렇지 않은 경우 실제 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 루트또는물뿌리.
두 번째 위치에 있는 경우 s
프로세스는 다음 멤버십을 얻습니다.실행 파일을 소유한 그룹 런타임: 실행 파일이라고 합니다.설정또는시드그 그룹에. (setgid 권한 비트는 사용된 파일 시스템 유형에 따라 디렉터리나 실행 불가능한 파일에 대해 다른 의미를 가질 수 있습니다.)
파일을 복사할 때 setuid 및 setgid 권한 비트는 일반적으로 복사되지 않습니다. 복사하더라도 루트가 소유한 파일을 복사하면 새 복사본은 루트가 아닌 사용자의 소유가 됩니다. 다른 사용자가 복사된 실행 파일을 실행하도록 허용할 수 있습니다.너, 그러나 루트가 되는 데는 도움이 되지 않습니다. 복사하다setuid 루트파일은 또한 전체 권한을 유지하므로 직접 루트가 되어야 합니다.