[Libva] Weird behaviour when dup()'ing the file descriptor for /dev/dri/card0

Xiang, Haihao haihao.xiang at intel.com
Wed Jul 25 22:28:37 PDT 2012


On Wed, 2012-07-25 at 21:15 -0700, Jorge Lucangeli Obes wrote: 
> On Wed, Jul 25, 2012 at 8:50 PM, Xiang, Haihao <haihao.xiang at intel.com> wrote:
> > On Wed, 2012-07-25 at 15:21 -0700, Jorge Lucangeli Obes wrote:
> >> Hi all,
> >>
> >> My name is Jorge. I'm trying to get libva to work inside the syscall
> >> filtering sandbox (seccomp mode 2 [1], landed on Linux 3.5) in
> >> Chromium/Chromium OS. Syscall filtering in Chromium allows us to deny
> >> access to syscalls deemed "dangerous" (e.g. ptrace()), or syscalls
> >> that could be used by malicious code after compromising a Chromium
> >> process using a vulnerability in the code.
> >>
> >> More specifically, we would like to have Chromium's GPU process run
> >> without unlimited access to the open() system call. To do this, we
> >> have to warm up/preload some resources, including the
> >> i965_drv_video.so library and /dev/dri/card0 which are legitimately
> >> opened by libva. The issue I'm hitting is with /dev/dri/card0.
> >>
> >> The way we limit access to open() is by preopening the files needed by
> >> libva, and then hooking open() when the sandbox is enabled, and
> >> returning dup()'s of the original fd's opened before enabling the
> >> sandbox. One of the files libva opens is /dev/dri/card0:
> >>
> >> http://cgit.freedesktop.org/vaapi/libva/tree/va/x11/dri2_util.c#n198
> >> va/x11/dri2_util.c
> >>
> >> Bool
> >> isDRI2Connected(VADriverContextP ctx, char **driver_name)
> >> {
> >> /* snip */
> >>     dri_state->fd = open(device_name, O_RDWR); <--- device_name ==
> >> "/dev/dri/card0"
> >>     assert(dri_state->fd >= 0);
> >>
> >> /* snip */
> >>
> >>     if (drmGetMagic(dri_state->fd, &magic))
> >>         goto err_out;
> >>
> >>     if (!VA_DRI2Authenticate(ctx->native_dpy,
> >> RootWindow(ctx->native_dpy, ctx->x11_screen),
> >>                           magic)) <--- failing
> >>         goto err_out;
> >> /* snip */
> >>
> >> Now, the issue that I'm seeing is the following: the call to
> >> open(device_name) happens after our sandbox is on, so the call gets
> >> intercepted. Instead of letting it go through, we dup() a fd for
> >> |device_name| that we opened before enabling the sandbox. drmGetMagic
> >> succeeds when called on that dup()'ed fd (all it does is an ioctl),
> >> but for some reason the call to DRI2Authenticate fails. This makes
> >> va_getDriverName() fail as well, and Chromium falls back to not using
> >> libva. I've tried using the LIBVA_DRIVER_NAME env var to sidestep the
> >> call to va_getDriverName() but since va_getDriverName() does a whole
> >> bunch of things, sidestepping makes an assert trigger in the actual
> >> libva Intel driver code.
> >
> > Yes, because a client can't access /dev/dri/card0 without authentication
> >
> >>
> >> Stracing the behaviour with the open() restrictions disabled and
> >> enabled, the difference appears to be in what the driver reads from fd
> >> 5, which is a socket. My question would be, then, if anyone knows
> >> whether reopening /dev/dri/card0 clears or resets some state, which
> >> could be causing DRIAuthenticate to fail when called after calling
> >> drmGetMagic on a dup()'ed fd.
> >>
> >> *Open hook disabled:
> >> open("/dev/dri/card0", O_RDWR)          = 15
> >> ...
> >> dup(15)                                 = 38
> >> ioctl(38, 0x80046402, 0x7fff7ee87360)   = 0
> >> poll([{fd=5, events=POLLIN|POLLOUT}], 1, -1) = 1 ([{fd=5, revents=POLLOUT}])
> >> writev(5, [{"\204\2\3\0\255\0\0\0\n\0\0\0", 12}, {NULL, 0}, {"", 0}], 3) = 12
> >> poll([{fd=5, events=POLLIN}], 1, -1)    = 1 ([{fd=5, revents=POLLIN}])
> >> read(5, "\1\0a\1\0\0\0\0\1\0\0\0\t\0\0\0\0\0\0\0\0\0\0\0\260O\374\364y\177\0\0",
> >> 4096) = 32
> >> ...
> >> write(2, "libva: ", 7)                  = 7
> >> write(2, "va_getDriverName() returns 0\n", 29) = 29
> >>
> >> *Open hook enabled:
> >> open("/dev/dri/card0", O_RDWR)          = 15
> >> ...
> >> dup(15)                                 = 32
> >> ioctl(32, 0x80046402, 0x7fff7ee87360)   = 0
> >> poll([{fd=5, events=POLLIN|POLLOUT}], 1, -1) = 1 ([{fd=5, revents=POLLOUT}])
> >> writev(5, [{"\204\2\3\0\255\0\0\0\n\0\0\0", 12}, {NULL, 0}, {"", 0}], 3) = 12
> >> poll([{fd=5, events=POLLIN}], 1, -1)    = 1 ([{fd=5, revents=POLLIN}])
> >> read(5, "\1\0A\4\0\0\0\0\0\0\0\0\t\0\0\0
> >> \340\n\365y\177\0\0\260O\374\364y\177\0\0", 4096) = 32
> >> ...
> >> write(2, "DRI2Authenticate failed\n", 24) = 24
> >> close(32)                               = 0
> >> ...
> >> write(2, "libva: ", 7)                  = 7
> >> write(2, "va_getDriverName() returns -1\n", 30) = 30
> >
> > a fd and a dup()'ed fd share the same struct file and the magic number
> > will be removed from master after being authenticated (drmAuthMagic()).
> >
> > So one possible is it has been authenticated on the fd elsewhere.
> 
> Good, that's what we thought. It's definitely the case that the same
> magic number is being used to authenticate more than once, and all
> attempts after the first one predictably fail.
> 
> So, the next question would be: is there any way, besides reopening
> the card, to get a new magic number? Any other file operation that can
> be done on the card fd?

If you make sure it has been authenticated,  you can remove the
authentication code from isDRI2Connected(). It should work.

> Thanks for the help!
> Jorge
> 
> > f.g.
> >
> >     dri_state->fd = open(device_name, O_RDWR);
> >
> >     if (dri_state->fd < 0)
> >         goto err_out;
> >
> >     if (drmGetMagic(dri_state->fd, &magic)) <<=== success, return a magic number.
> >         goto err_out;
> >
> >     if (!VA_DRI2Authenticate(ctx->native_dpy, RootWindow(ctx->native_dpy, ctx->x11_screen),
> >                           magic))   <<=== success, and remove the magic number from master.
> >         goto err_out;
> >
> >     dri_state->fd =  dup(dri_state->fd);
> >     assert(dri_state->fd >= 0);
> >
> >     if (drmGetMagic(dri_state->fd, &magic)) <<=== success, return the same magic number because they are same the same struct file
> >         goto err_out;
> >
> >     if (!VA_DRI2Authenticate(ctx->native_dpy, RootWindow(ctx->native_dpy, ctx->x11_screen),
> >                           magic))  <<== fail, the magic number has been removed from master before this operation
> >         goto err_out;
> >
> > Regards
> > Haihao
> >
> >>
> >> Thanks!
> >> Jorge
> >>
> >> [1] http://lwn.net/Articles/475043/
> >> _______________________________________________
> >> Libva mailing list
> >> Libva at lists.freedesktop.org
> >> http://lists.freedesktop.org/mailman/listinfo/libva
> >
> >




More information about the Libva mailing list