@@ -964,6 +964,36 @@ bool gem_has_bsd2(int fd)
{
return gem_has_enable_ring(fd,LOCAL_I915_PARAM_HAS_BSD2);
}
+
+#define I915_PARAM_HAS_LEGACY_CONTEXT 35
+/**
+ * drm_has_legacy_context:
+ * @fd: open i915 drm file descriptor
+ *
+ * This helper function checks to see if the LEGACY CONTEXT functionality is
+ * supported by the driver. This feature is compiled in and cannot be changed
+ * at run time so only needs checking once.
+ *
+ * Returns: true if the legacy context is support, else false.
+ */
+bool drm_has_legacy_context(int fd)
+{
+ int tmp = 0;
+ drm_i915_getparam_t gp;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.value = &tmp;
+ gp.param = I915_PARAM_HAS_LEGACY_CONTEXT;
+
+ /*
+ * if legacy context param is not supported, then it's old and we
+ * can assume that the HW_LOCKS are supported.
+ */
+ if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) != 0)
+ return true;
+
+ return tmp == 1;
+}
/**
* gem_available_aperture_size:
* @fd: open i915 drm file descriptor
@@ -120,6 +120,7 @@ bool gem_has_bsd(int fd);
bool gem_has_blt(int fd);
bool gem_has_vebox(int fd);
bool gem_has_bsd2(int fd);
+bool drm_has_legacy_context(int fd);
bool gem_uses_aliasing_ppgtt(int fd);
int gem_available_fences(int fd);
uint64_t gem_available_aperture_size(int fd);
@@ -160,3 +160,4 @@ prime_udl
single-tests.txt
template
testdisplay
+drm_hw_lock
@@ -84,6 +84,7 @@ TESTS_progs_M = \
pm_sseu \
prime_self_import \
template \
+ drm_hw_lock \
$(NULL)
TESTS_progs = \
new file mode 100644
@@ -0,0 +1,193 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Peter Antoine <peter.antoine@intel.com>
+ */
+
+/*
+ * Testcase: Test the HW_LOCKs for correct support and non-crashing.
+ *
+ * This test will check that he hw_locks are only g_supported for drivers that
+ * require that support. If it is not g_supported then the functions all return
+ * the correct error code.
+ *
+ * If g_supported it will check that the functions do not crash when the crash
+ * tests are used, also that one of the tests is a security level escalation
+ * that should be rejected.
+ */
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <drm.h>
+#include "drmtest.h"
+#include "igt_core.h"
+#include "ioctl_wrappers.h"
+
+IGT_TEST_DESCRIPTION("Test the HW_LOCKs for correct support and non-crashing.");
+
+#ifndef DRM_KERNEL_CONTEXT
+# define DRM_KERNEL_CONTEXT (0)
+#endif
+
+#ifndef _DRM_LOCK_HELD
+# define _DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */
+#endif
+
+#ifndef _DRM_LOCK_CONT
+# define _DRM_LOCK_CONT 0x40000000U /**< Hardware lock is contended */
+#endif
+
+static bool g_sig_fired;
+static bool g_supported;
+static struct sigaction old_action;
+
+static void sig_term_handler(int value)
+{
+ g_sig_fired = true;
+}
+
+static bool set_term_handler(void)
+{
+ static struct sigaction new_action;
+
+ new_action.sa_handler = sig_term_handler;
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = 0;
+
+ igt_assert(sigaction(SIGTERM, &new_action, &old_action) == 0);
+
+ if (old_action.sa_handler != SIG_IGN)
+ return true;
+ else
+ return false;
+}
+
+static void restore_term_handler(void)
+{
+ sigaction(SIGTERM, &old_action, NULL);
+}
+
+static void does_lock_crash(int fd)
+{
+ struct drm_lock rubbish;
+ int ret;
+
+ memset(&rubbish, 'A', sizeof(struct drm_lock));
+
+ g_sig_fired = false;
+ ret = ioctl(fd, DRM_IOCTL_LOCK, &rubbish);
+
+ igt_assert(ret == -1 && (!g_supported || g_sig_fired));
+ igt_assert(ret == -1 && (g_supported || errno == EINVAL));
+}
+
+static void does_unlock_crash(int fd)
+{
+ struct drm_lock rubbish;
+ int ret;
+
+ memset(&rubbish, 'A', sizeof(struct drm_lock));
+
+ g_sig_fired = false;
+ ret = ioctl(fd, DRM_IOCTL_UNLOCK, &rubbish);
+
+ igt_assert(ret == -1 && (!g_supported || g_sig_fired));
+ igt_assert(ret == -1 && (g_supported || errno == EINVAL));
+}
+
+static void priority_escalation(int fd)
+{
+ struct drm_lock rubbish;
+ int ret;
+
+ /* this should be rejected */
+ rubbish.context = DRM_KERNEL_CONTEXT;
+ ret = ioctl(fd, DRM_IOCTL_LOCK, &rubbish);
+ igt_assert(ret == -1 && (!g_supported || errno == EPERM));
+ igt_assert(ret == -1 && (g_supported || errno == EINVAL));
+
+ /* this should also be rejected */
+ rubbish.context = _DRM_LOCK_HELD | DRM_KERNEL_CONTEXT;
+ ret = ioctl(fd, DRM_IOCTL_LOCK, &rubbish);
+ igt_assert(ret == -1 && (!g_supported || errno == EPERM));
+ igt_assert(ret == -1 && (g_supported || errno == EINVAL));
+
+ /* this should also be rejected */
+ rubbish.context = _DRM_LOCK_CONT | DRM_KERNEL_CONTEXT;
+ ret = ioctl(fd, DRM_IOCTL_LOCK, &rubbish);
+ igt_assert(ret == -1 && (!g_supported || errno == EPERM));
+ igt_assert(ret == -1 && (g_supported || errno == EINVAL));
+
+ /* this should be rejected */
+ rubbish.context = DRM_KERNEL_CONTEXT;
+ ret = ioctl(fd, DRM_IOCTL_UNLOCK, &rubbish);
+ igt_assert(ret == -1 && (!g_supported || errno == EPERM));
+ igt_assert(ret == -1 && (g_supported || errno == EINVAL));
+
+ /* this should also be rejected */
+ rubbish.context = _DRM_LOCK_HELD | DRM_KERNEL_CONTEXT;
+ ret = ioctl(fd, DRM_IOCTL_UNLOCK, &rubbish);
+ igt_assert(ret == -1 && (!g_supported || errno == EPERM));
+ igt_assert(ret == -1 && (g_supported || errno == EINVAL));
+
+ /* this should also be rejected */
+ rubbish.context = _DRM_LOCK_CONT | DRM_KERNEL_CONTEXT;
+ ret = ioctl(fd, DRM_IOCTL_UNLOCK, &rubbish);
+ igt_assert(ret == -1 && (!g_supported || errno == EPERM));
+ igt_assert(ret == -1 && (g_supported || errno == EINVAL));
+}
+
+igt_main
+{
+ int fd = -1;
+
+ g_sig_fired = false;
+ g_supported = false;
+
+ igt_fixture {
+ fd = drm_open_any();
+
+ igt_assert(set_term_handler());
+ g_supported = drm_has_legacy_context(fd);
+ }
+
+ igt_info("HW LOCK Supported: %s\n", g_supported?"Yes":"No");
+
+ igt_subtest("lock-crash") {
+ does_lock_crash(fd);
+ }
+
+ igt_subtest("unlock-crash") {
+ does_unlock_crash(fd);
+ }
+
+ igt_subtest("priority-escalation") {
+ priority_escalation(fd);
+ }
+
+ igt_fixture {
+ restore_term_handler();
+ close(fd);
+ }
+}
+
There are several issues with the hardware locks functions that stretch from kernel crashes to priority escalations. This new test will test the the fixes for these features. This test will cause a driver/kernel crash on un-patched kernels, the following patches should be applied to stop the crashes: drm: Kernel Crash in drm_unlock drm: Fixes unsafe deference in locks. v2: - add API documentation for drm_has_legacy_context (T.Wood) - update tests/.gitignore (T.Wood) - add IGT_TEST_DESCRIPTION (T.Wood) - changes to igt_fixtures (T.Wood) Issue: VIZ-5485 Signed-off-by: Peter Antoine <peter.antoine@intel.com> --- lib/ioctl_wrappers.c | 30 ++++++++ lib/ioctl_wrappers.h | 1 + tests/.gitignore | 1 + tests/Makefile.sources | 1 + tests/drm_hw_lock.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 226 insertions(+) create mode 100644 tests/drm_hw_lock.c