[Mesa-dev] [PATCH v3 3/3] egl/android: Add DRM node probing and filtering

Amit Pundir amit.pundir at linaro.org
Wed Jun 13 18:19:46 UTC 2018


On 13 June 2018 at 20:45, Rob Herring <robh at kernel.org> wrote:
>
> +Amit and John
>
> On Sat, Jun 9, 2018 at 11:27 AM, Robert Foss <robert.foss at collabora.com> wrote:
> > This patch both adds support for probing & filtering DRM nodes
> > and switches away from using the GRALLOC_MODULE_PERFORM_GET_DRM_FD
> > gralloc call.
> >
> > Currently the filtering is based just on the driver name,
> > and the desired name is supplied using the "drm.gpu.vendor_name"
> > Android property.
>
> There's a potential issue with this whole approach and that is
> SELinux. With the way SELinux locks down accesses, getting probing
> thru device files to work can be a pain. It may be better now than the
> prior version because sysfs is not probed. I'll leave it to Amit or
> John to comment.

Right.. so ICYMI, this patch is already pulled into external/mesa3d
project of AOSP and I stumbled upon one such /dev/dri/ access denial
on db820c recently.

In AOSP, zygote spawned apps already have access to GPU device nodes
in the form of /dev/gpu_device file, but the missing part is the
open-read access to "/dev/dri/" which need to be allowed explicitly.
Rest of the denials related to sysfs access can be easily resolved
using audit2allow tool.

Regards,
Amit Pundir

>
> Rob
>
> >
> > Signed-off-by: Robert Foss <robert.foss at collabora.com>
> > ---
> >
> > Changes since v2:
> >  - Switch from drmGetDevices2 to manual renderD node iteration
> >  - Add probe_res enum to communicate probing results better
> >  - Avoid using _eglError() in internal static functions
> >  - Avoid actually loading the driver while probing, just verify
> >    that it exists.
> >  - Replace strlen call with the assumed length PROPERTY_VALUE_MAX
> >
> > Changes since v1:
> >  - Do not rely on libdrm for probing
> >  - Distinguish between errors and when no drm devices are found
> >
> > Changes since RFC:
> >  - Rebased on newer libdrm drmHandleMatch patch
> >  - Added support for driver probing
> >
> >
> >  src/egl/drivers/dri2/platform_android.c | 222 ++++++++++++++++++------
> >  1 file changed, 169 insertions(+), 53 deletions(-)
> >
> > diff --git a/src/egl/drivers/dri2/platform_android.c b/src/egl/drivers/dri2/platform_android.c
> > index 4ba96aad90..a2cbe92d93 100644
> > --- a/src/egl/drivers/dri2/platform_android.c
> > +++ b/src/egl/drivers/dri2/platform_android.c
> > @@ -27,12 +27,16 @@
> >   * DEALINGS IN THE SOFTWARE.
> >   */
> >
> > +#include <cutils/properties.h>
> >  #include <errno.h>
> > +#include <dirent.h>
> >  #include <dlfcn.h>
> >  #include <fcntl.h>
> >  #include <xf86drm.h>
> >  #include <stdbool.h>
> > +#include <stdio.h>
> >  #include <sync/sync.h>
> > +#include <sys/types.h>
> >
> >  #include "loader.h"
> >  #include "egl_dri2.h"
> > @@ -1130,31 +1134,6 @@ droid_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *dpy)
> >     return (config_count != 0);
> >  }
> >
> > -enum {
> > -        /* perform(const struct gralloc_module_t *mod,
> > -         *         int op,
> > -         *         int *fd);
> > -         */
> > -        GRALLOC_MODULE_PERFORM_GET_DRM_FD = 0x40000002,
> > -};
> > -
> > -static int
> > -droid_open_device(struct dri2_egl_display *dri2_dpy)
> > -{
> > -   int fd = -1, err = -EINVAL;
> > -
> > -   if (dri2_dpy->gralloc->perform)
> > -         err = dri2_dpy->gralloc->perform(dri2_dpy->gralloc,
> > -                                          GRALLOC_MODULE_PERFORM_GET_DRM_FD,
> > -                                          &fd);
> > -   if (err || fd < 0) {
> > -      _eglLog(_EGL_WARNING, "fail to get drm fd");
> > -      fd = -1;
> > -   }
> > -
> > -   return (fd >= 0) ? fcntl(fd, F_DUPFD_CLOEXEC, 3) : -1;
> > -}
> > -
> >  static const struct dri2_egl_display_vtbl droid_display_vtbl = {
> >     .authenticate = NULL,
> >     .create_window_surface = droid_create_window_surface,
> > @@ -1215,6 +1194,168 @@ static const __DRIextension *droid_image_loader_extensions[] = {
> >     NULL,
> >  };
> >
> > +EGLBoolean
> > +droid_load_driver(_EGLDisplay *disp)
> > +{
> > +   struct dri2_egl_display *dri2_dpy = disp->DriverData;
> > +   const char *err;
> > +
> > +   dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
> > +   if (dri2_dpy->driver_name == NULL)
> > +      return false;
> > +
> > +   dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
> > +
> > +   if (!dri2_dpy->is_render_node) {
> > +   #ifdef HAVE_DRM_GRALLOC
> > +       /* Handle control nodes using __DRI_DRI2_LOADER extension and GEM names
> > +        * for backwards compatibility with drm_gralloc. (Do not use on new
> > +        * systems.) */
> > +       dri2_dpy->loader_extensions = droid_dri2_loader_extensions;
> > +       if (!dri2_load_driver(disp)) {
> > +          err = "DRI2: failed to load driver";
> > +          goto error;
> > +       }
> > +   #else
> > +       err = "DRI2: handle is not for a render node";
> > +       goto error;
> > +   #endif
> > +   } else {
> > +       dri2_dpy->loader_extensions = droid_image_loader_extensions;
> > +       if (!dri2_load_driver_dri3(disp)) {
> > +          err = "DRI3: failed to load driver";
> > +          goto error;
> > +       }
> > +    }
> > +
> > +   return true;
> > +
> > +error:
> > +   free(dri2_dpy->driver_name);
> > +   dri2_dpy->driver_name = NULL;
> > +   return false;
> > +}
> > +
> > +static bool
> > +droid_probe_driver(int fd)
> > +{
> > +   char *driver_name;
> > +
> > +   driver_name = loader_get_driver_for_fd(fd);
> > +   if (driver_name == NULL)
> > +      return false;
> > +
> > +   free(driver_name);
> > +   return true;
> > +}
> > +
> > +typedef enum {
> > +   probe_error = -1,
> > +   probe_success = 0,
> > +   probe_filtered_out = 1,
> > +   probe_no_driver = 2
> > +} probe_ret_t;
> > +
> > +static probe_ret_t
> > +droid_probe_device(_EGLDisplay *disp, int fd, char *vendor)
> > +{
> > +   int ret;
> > +
> > +   drmVersionPtr ver = drmGetVersion(fd);
> > +   if (!ver)
> > +      return probe_error;
> > +
> > +   if (vendor != NULL && ver->name != NULL &&
> > +       strncmp(vendor, ver->name, PROPERTY_VALUE_MAX) != 0) {
> > +          ret = probe_filtered_out;
> > +          goto cleanup;
> > +       }
> > +
> > +
> > +   if (!droid_probe_driver(fd)) {
> > +      ret = probe_no_driver;
> > +      goto cleanup;
> > +   }
> > +
> > +   ret = probe_success;
> > +
> > +cleanup:
> > +   drmFreeVersion(ver);
> > +   return ret;
> > +}
> > +
> > +static int
> > +droid_open_device(_EGLDisplay *disp)
> > +{
> > +   const int MAX_DRM_DEVICES = 32;
> > +   int prop_set, num_devices;
> > +   int fd = -1, fallback_fd = -1;
> > +
> > +   char *vendor_name = NULL;
> > +   char vendor_buf[PROPERTY_VALUE_MAX];
> > +   if (property_get("drm.gpu.vendor_name", vendor_buf, NULL) > 0);
> > +      vendor_name = vendor_buf;
> > +
> > +   const char *drm_dir_name = "/dev/dri";
> > +   DIR *sysdir = opendir(drm_dir_name);
> > +   if (!sysdir)
> > +       return -errno;
> > +
> > +   struct dirent *dent;
> > +   while ((dent = readdir(sysdir))) {
> > +      char dev_path[128];
> > +      char *render_dev_prefix = "renderD";
> > +      size_t prefix_len = strlen(render_dev_prefix);
> > +
> > +      if (strncmp(render_dev_prefix, dent->d_name, prefix_len) != 0)
> > +         continue;
> > +
> > +      sprintf(dev_path, "%s/%s", drm_dir_name, dent->d_name);
> > +      fd = loader_open_device(dev_path);
> > +      if (fd == -1) {
> > +         _eglLog(_EGL_WARNING, "%s() Failed to open DRM device %s",
> > +                 __func__, dev_path);
> > +         continue;
> > +      }
> > +
> > +      int ret = droid_probe_device(disp, fd, vendor_name);
> > +      switch (ret) {
> > +      case probe_success:
> > +         goto success;
> > +      case probe_filtered_out:
> > +         goto allow_fallback;
> > +      case probe_error:
> > +      case probe_no_driver:
> > +         goto next;
> > +      }
> > +
> > +allow_fallback:
> > +      if (fallback_fd == -1)
> > +         fallback_fd = fd;
> > +next:
> > +      if (fallback_fd != fd)
> > +         close(fd);
> > +      fd = -1;
> > +      continue;
> > +   }
> > +
> > +success:
> > +   closedir(sysdir);
> > +
> > +   if (fallback_fd < 0 && fd < 0) {
> > +      _eglLog(_EGL_WARNING, "Failed to open any DRM device");
> > +      return -1;
> > +   }
> > +
> > +   if (fd < 0) {
> > +      _eglLog(_EGL_WARNING, "Failed to open desired DRM device, using fallback");
> > +      return fallback_fd;
> > +   }
> > +
> > +   close(fallback_fd);
> > +   return fd;
> > +}
> > +
> >  EGLBoolean
> >  dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *disp)
> >  {
> > @@ -1242,42 +1383,17 @@ dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *disp)
> >
> >     disp->DriverData = (void *) dri2_dpy;
> >
> > -   dri2_dpy->fd = droid_open_device(dri2_dpy);
> > +   dri2_dpy->fd = droid_open_device(disp);
> >     if (dri2_dpy->fd < 0) {
> >        err = "DRI2: failed to open device";
> >        goto cleanup;
> >     }
> >
> > -   dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
> > -   if (dri2_dpy->driver_name == NULL) {
> > -      err = "DRI2: failed to get driver name";
> > +   if (!droid_load_driver(disp)) {
> > +      err = "DRI2: failed to load driver";
> >        goto cleanup;
> >     }
> >
> > -   dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
> > -
> > -   if (!dri2_dpy->is_render_node) {
> > -   #ifdef HAVE_DRM_GRALLOC
> > -       /* Handle control nodes using __DRI_DRI2_LOADER extension and GEM names
> > -        * for backwards compatibility with drm_gralloc. (Do not use on new
> > -        * systems.) */
> > -       dri2_dpy->loader_extensions = droid_dri2_loader_extensions;
> > -       if (!dri2_load_driver(disp)) {
> > -          err = "DRI2: failed to load driver";
> > -          goto cleanup;
> > -       }
> > -   #else
> > -       err = "DRI2: handle is not for a render node";
> > -       goto cleanup;
> > -   #endif
> > -   } else {
> > -       dri2_dpy->loader_extensions = droid_image_loader_extensions;
> > -       if (!dri2_load_driver_dri3(disp)) {
> > -          err = "DRI3: failed to load driver";
> > -          goto cleanup;
> > -       }
> > -   }
> > -
> >     if (!dri2_create_screen(disp)) {
> >        err = "DRI2: failed to create screen";
> >        goto cleanup;
> > --
> > 2.17.1
> >


More information about the mesa-dev mailing list