Add vulnerability checker for cve-2019-0155 v2: sync, bailout early if no parser (Chris) Cc: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> Cc: Jon Bloomfield <jon.bloomfield@xxxxxxxxx> Cc: Joonas Lahtinen <joonas.lahtinen@xxxxxxxxx> References: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-0155 References: https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00242.html Signed-off-by: Mika Kuoppala <mika.kuoppala@xxxxxxxxxxxxxxx> --- Makefile.am | 2 +- configure.ac | 1 + cve/Makefile.am | 14 ++ cve/Makefile.sources | 5 + cve/cve-2019-0155.c | 470 +++++++++++++++++++++++++++++++++++++++++++ cve/meson.build | 12 ++ meson.build | 1 + 7 files changed, 504 insertions(+), 1 deletion(-) create mode 100644 cve/Makefile.am create mode 100644 cve/Makefile.sources create mode 100644 cve/cve-2019-0155.c create mode 100644 cve/meson.build diff --git a/Makefile.am b/Makefile.am index 94250964..e139bb44 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,7 @@ ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 -SUBDIRS = lib tools scripts benchmarks +SUBDIRS = lib tools scripts benchmarks cve if BUILD_TESTS SUBDIRS += tests diff --git a/configure.ac b/configure.ac index f9e4942e..23fd9f30 100644 --- a/configure.ac +++ b/configure.ac @@ -311,6 +311,7 @@ AC_CONFIG_FILES([ tools/null_state_gen/Makefile tools/registers/Makefile overlay/Makefile + cve/Makefile ]) AC_CONFIG_FILES([tools/intel_aubdump], [chmod +x tools/intel_aubdump]) diff --git a/cve/Makefile.am b/cve/Makefile.am new file mode 100644 index 00000000..b8419ecd --- /dev/null +++ b/cve/Makefile.am @@ -0,0 +1,14 @@ +include Makefile.sources + +cve_PROGRAMS = $(cve_prog_list) + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/include/drm-uapi \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/stubs/syscalls + +AM_CFLAGS = -I$(top_srcdir)/include/drm-uapi \ + $(DRM_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) $(LIBUNWIND_CFLAGS) \ + $(WERROR_CFLAGS) -D_GNU_SOURCE +LDADD = $(top_builddir)/lib/libintel_tools.la diff --git a/cve/Makefile.sources b/cve/Makefile.sources new file mode 100644 index 00000000..2b02f958 --- /dev/null +++ b/cve/Makefile.sources @@ -0,0 +1,5 @@ +cvedir=$(libexecdir)/igt-gpu-tools/cve + +cve_prog_list = \ + cve-2019-0155 + $(NULL) diff --git a/cve/cve-2019-0155.c b/cve/cve-2019-0155.c new file mode 100644 index 00000000..5f6ca60a --- /dev/null +++ b/cve/cve-2019-0155.c @@ -0,0 +1,470 @@ +/* + * Copyright © 2019 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. + * + */ + +/* + * Can be compiled with: + * gcc -Wall -static -o cve-2019-0155 cve-2019-0155.c +*/ + +#define VERSION 1 +#define CHECK_WRITE_BLOCK_WITHOUT_PARSER 0 + +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> + +#define ASSERT(x, s) do { \ + if (!(x)) { \ + printf("Failed to %s, %s (%d)\n", (s), \ + strerror(errno), errno); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +static int do_ioctl(const int fd, const unsigned long nr, void *arg) +{ + int ret; + + do + ret = ioctl(fd, nr, arg); + while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + + return ret; +} + +static int is_driver_i915(const int fd) +{ + struct _drm_version { + int version_major; + int version_minor; + int version_patchlevel; + + size_t name_len; + char *name; + size_t date_len; + char *date; + size_t desc_len; + char *desc; + } v = { 0, }; + char name[256] = { 0, }; + int ret; + + v.name_len = sizeof(name) - 1; + v.name = name; + + ret = do_ioctl(fd, _IOWR(0x40, 0x00, struct _drm_version), &v); + ASSERT(ret == 0, "get name"); + + name[v.name_len] = 0; + + return !strcmp(name, "i915"); +} + +static int cmd_parser_version(const int fd) +{ + int ret, version = 0; + struct _drm_i915_getparam_t { + int32_t param; + uint64_t value; + } q = { 28, + (uint64_t)&version }; + + ret = do_ioctl(fd, _IOWR(0x40, 0x40 + 0x06, struct _drm_i915_getparam_t), &q); + ASSERT(ret == 0, "get param"); + + return version; +} + +#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags)) +#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) +#define MI_LOAD_REGISTER_IMM MI_INSTR(0x22, (3-2)) + +static int is_write_blocked(const int fd) +{ + int ret; + uint32_t handle; + + struct _drm_i915_gem_execbuffer2 { + uint64_t buffers_ptr; + uint32_t buffer_count; + uint32_t batch_start_offset; + uint32_t batch_len; + uint32_t DR1; + uint32_t DR4; + uint32_t num_cliprects; + uint64_t cliprects_ptr; + uint64_t flags; + uint64_t rsvd1; + uint64_t rsvd2; + } execbuf = { 0, }; + + struct _drm_i915_gem_exec_object2 { + uint32_t handle; + uint32_t relocation_count; + uint64_t relocs_ptr; + uint64_t alignment; + uint64_t offset; + uint64_t flags; + uint64_t rsvd1; + uint64_t rsvd2; + } execobj[1] = { { 0, } }; + + struct _drm_i915_gem_create { + uint64_t size; + uint32_t handle; + uint32_t pad; + } createobj = { 0, }; + + struct _drm_i915_gem_pwrite { + uint32_t handle; + uint32_t pad; + uint64_t offset; + uint64_t size; + uint64_t data_ptr; + } pwrite = { 0, }; + + const uint32_t batch[] = { + MI_LOAD_REGISTER_IMM, + 0x2221c, + 0x0, + 0, + MI_BATCH_BUFFER_END, + }; + + createobj.handle = 0; + createobj.size = 4096; + + ret = do_ioctl(fd, _IOWR(0x40, 0x40+0x1b, struct _drm_i915_gem_create), &createobj); + ASSERT(ret == 0, "create object"); + + handle = createobj.handle; + + pwrite.handle = handle; + pwrite.size = sizeof(batch); + pwrite.data_ptr = (uintptr_t)batch; + + ret = do_ioctl(fd, _IOWR(0x40, 0x40+0x1d, struct _drm_i915_gem_pwrite), &pwrite); + ASSERT(ret == 0, "write object"); + + execobj[0].handle = handle; + + execbuf.buffers_ptr = (uintptr_t)execobj; + execbuf.buffer_count = 1; + execbuf.flags = 3; /* select blitter engine (bcs0) */ + + ret = do_ioctl(fd, _IOWR(0x40, 0x40+0x29, struct _drm_i915_gem_execbuffer2), &execbuf); + if (ret) { + if (errno == EACCES || errno == EINVAL) + return 1; + } + + return 0; +} + +#define INTEL_VGA_DEVICE(x, y) (x) + +static const uint32_t gen9_ids[] = { + + INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */ + + INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */ + + INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ + INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ + INTEL_VGA_DEVICE(0x190A, info), /* SRV GT1 */ + + INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ + INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ + + INTEL_VGA_DEVICE(0x191E, info), /* ULX GT2 */ + + INTEL_VGA_DEVICE(0x1912, info), /* DT GT2 */ + INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */ + INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */ + INTEL_VGA_DEVICE(0x191D, info), /* WKS GT2 */ + + INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ + + INTEL_VGA_DEVICE(0x1923, info), /* ULT GT3 */ + INTEL_VGA_DEVICE(0x1927, info), /* ULT GT3 */ + INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ + INTEL_VGA_DEVICE(0x192D, info), /* SRV GT3 */ + + INTEL_VGA_DEVICE(0x1932, info), /* DT GT4 */ + INTEL_VGA_DEVICE(0x193B, info), /* Halo GT4 */ + INTEL_VGA_DEVICE(0x193D, info), /* WKS GT4 */ + INTEL_VGA_DEVICE(0x192A, info), /* SRV GT4 */ + INTEL_VGA_DEVICE(0x193A, info), /* SRV GT4e */ + + INTEL_VGA_DEVICE(0x0A84, info), + INTEL_VGA_DEVICE(0x1A84, info), + INTEL_VGA_DEVICE(0x1A85, info), + INTEL_VGA_DEVICE(0x5A84, info), /* APL HD Graphics 505 */ + INTEL_VGA_DEVICE(0x5A85, info), /* APL HD Graphics 500 */ + + INTEL_VGA_DEVICE(0x3184, info), + INTEL_VGA_DEVICE(0x3185, info), + + INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ + INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ + + INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ + INTEL_VGA_DEVICE(0x5915, info), /* ULX GT1.5 */ + + INTEL_VGA_DEVICE(0x5902, info), /* DT GT1 */ + INTEL_VGA_DEVICE(0x5908, info), /* Halo GT1 */ + INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */ + INTEL_VGA_DEVICE(0x590A, info), /* SRV GT1 */ + + INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ + INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ + + INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ + + INTEL_VGA_DEVICE(0x5917, info), /* Mobile GT2 */ + INTEL_VGA_DEVICE(0x5912, info), /* DT GT2 */ + INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ + INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ + INTEL_VGA_DEVICE(0x591D, info), /* WKS GT2 */ + + INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */ + + INTEL_VGA_DEVICE(0x5923, info), /* ULT GT3 */ + INTEL_VGA_DEVICE(0x5927, info), /* ULT GT3 */ + + INTEL_VGA_DEVICE(0x593B, info), /* Halo GT4 */ + + INTEL_VGA_DEVICE(0x591C, info), /* ULX GT2 */ + INTEL_VGA_DEVICE(0x87C0, info), /* ULX GT2 */ + + INTEL_VGA_DEVICE(0x87CA, info), + + INTEL_VGA_DEVICE(0x9B21, info), + INTEL_VGA_DEVICE(0x9BAA, info), + INTEL_VGA_DEVICE(0x9BAB, info), + INTEL_VGA_DEVICE(0x9BAC, info), + INTEL_VGA_DEVICE(0x9BA0, info), + INTEL_VGA_DEVICE(0x9BA5, info), + INTEL_VGA_DEVICE(0x9BA8, info), + INTEL_VGA_DEVICE(0x9BA4, info), + INTEL_VGA_DEVICE(0x9BA2, info), + + INTEL_VGA_DEVICE(0x9B41, info), + INTEL_VGA_DEVICE(0x9BCA, info), + INTEL_VGA_DEVICE(0x9BCB, info), + INTEL_VGA_DEVICE(0x9BCC, info), + INTEL_VGA_DEVICE(0x9BC0, info), + INTEL_VGA_DEVICE(0x9BC5, info), + INTEL_VGA_DEVICE(0x9BC8, info), + INTEL_VGA_DEVICE(0x9BC4, info), + INTEL_VGA_DEVICE(0x9BC2, info), + INTEL_VGA_DEVICE(0x9BC6, info), + INTEL_VGA_DEVICE(0x9BE6, info), + INTEL_VGA_DEVICE(0x9BF6, info), + + INTEL_VGA_DEVICE(0x3E90, info), /* SRV GT1 */ + INTEL_VGA_DEVICE(0x3E93, info), /* SRV GT1 */ + INTEL_VGA_DEVICE(0x3E99, info), /* SRV GT1 */ + + INTEL_VGA_DEVICE(0x3E91, info), /* SRV GT2 */ + INTEL_VGA_DEVICE(0x3E92, info), /* SRV GT2 */ + INTEL_VGA_DEVICE(0x3E96, info), /* SRV GT2 */ + INTEL_VGA_DEVICE(0x3E98, info), /* SRV GT2 */ + INTEL_VGA_DEVICE(0x3E9A, info), /* SRV GT2 */ + + INTEL_VGA_DEVICE(0x3E9C, info), + + INTEL_VGA_DEVICE(0x3E9B, info), /* Halo GT2 */ + INTEL_VGA_DEVICE(0x3E94, info), /* Halo GT2 */ + + INTEL_VGA_DEVICE(0x3EA9, info), + + INTEL_VGA_DEVICE(0x3EA5, info), /* ULT GT3 */ + INTEL_VGA_DEVICE(0x3EA6, info), /* ULT GT3 */ + INTEL_VGA_DEVICE(0x3EA7, info), /* ULT GT3 */ + INTEL_VGA_DEVICE(0x3EA8, info), /* ULT GT3 */ + + INTEL_VGA_DEVICE(0x3EA1, info), + INTEL_VGA_DEVICE(0x3EA4, info), + + INTEL_VGA_DEVICE(0x3EA0, info), + INTEL_VGA_DEVICE(0x3EA3, info), + + INTEL_VGA_DEVICE(0x3EA2, info), +}; + +static int is_platform_gen9(void) +{ + const char * const id_file = + "/sys/bus/pci/drivers/i915/0000:00:02.0/device"; + char idstr[32] = {0, }; + uint32_t id = 0; + int fd, ret, i; + + fd = open(id_file, O_RDONLY); + if (fd == -1) + return -1; + + ret = read(fd, idstr, 6); + if (ret != 6) + return -1; + + close(fd); + + idstr[6] = 0; + + id = strtol(idstr, NULL, 16); + + for (i = 0; i < sizeof(gen9_ids)/sizeof(uint32_t); i++) + if (id == gen9_ids[i]) + return 1; + + return 0; +} + +static int is_fd_safe(const int fd) +{ + int parser_version = -1; + int write_block = 0; + + parser_version = cmd_parser_version(fd); + printf(" Command parser version: %d\n", parser_version); + if (parser_version >= 10) { + printf(" Command parsing for blt engine supported\n"); + } else if (!CHECK_WRITE_BLOCK_WITHOUT_PARSER) { + printf(" There is no blitter command parser\n"); + return 0; + } + + write_block = is_write_blocked(fd); + + printf(" Unsafe write %s\n", write_block ? "blocked" : "possible!"); + + return write_block; +} + +struct stats { + int checked; + int safe; + int failed; +}; + +static void check_path(const char *path, struct stats *stats) +{ + int fd; + int is_safe; + + fd = open(path, O_RDWR); + if (fd == -1) { + if (errno != ENOENT) { + printf("Opening %s failed with %s (%d)\n", + path, strerror(errno), errno); + stats->failed++; + } + + return; + } + + if (!is_driver_i915(fd)) { + close(fd); + return; + } + + printf("Checking %s:\n", path); + + is_safe = is_fd_safe(fd); + printf(" Device %s : %s\n\n", path, is_safe ? "SAFE" : "VULNERABLE"); + if (is_safe) + stats->safe++; + + stats->checked++; + + close (fd); +} + +static int check_devices(void) +{ + const char * const cardbase = "/dev/dri/card"; + const char * const renderbase = "/dev/dri/renderD"; + char path[256]; + int i; + struct stats s = { 0, 0, 0 }; + + for (i = 0; i < 16; i++) { + sprintf(path, "%s%d", cardbase, i); + check_path(path, &s); + + sprintf(path, "%s%d", renderbase, i + 128); + check_path(path, &s); + } + + if (s.failed && !s.checked) { + printf("Failed to open devices, need root?\n"); + return -1; + } + + if (!s.checked) { + printf ("Didn't find anything to check\n"); + return -1; + } + + return s.checked == s.safe; +} + +int main(int argc, char *argv[]) +{ + int safe = 0; + int ret; + + printf("Intel cve-2019-0155 (blt mmio vulnerability) checker version %d\n\n", VERSION); + + sync(); + + ret = is_platform_gen9(); + if (ret == 0) { + safe = 1; + printf("Your platform is not affected\n"); + } else if (ret == -1) { + printf("Unable to determine platform type\n"); + } + + if (safe != 1) + safe = check_devices(); + + if (safe < 0) { + printf("Unable to determine system state due to errors\n"); + return EXIT_FAILURE; + } + + printf("\nYour system is %s against cve-2019-0155\n", safe ? "SAFE" : "VULNERABLE"); + + return safe ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/cve/meson.build b/cve/meson.build new file mode 100644 index 00000000..990181c6 --- /dev/null +++ b/cve/meson.build @@ -0,0 +1,12 @@ +cve_progs = [ + 'cve-2019-0155', +] + +cvedir = join_paths(libexecdir, 'cve') + +foreach prog : cve_progs + executable(prog, prog + '.c', + install : true, + install_dir : cvedir, + dependencies : igt_deps) +endforeach diff --git a/meson.build b/meson.build index 4d5003ba..27ad9567 100644 --- a/meson.build +++ b/meson.build @@ -302,6 +302,7 @@ if libdrm_intel.found() endif subdir('overlay') subdir('man') +subdir('cve') gtk_doc = dependency('gtk-doc', required : build_docs) python3 = find_program('python3', required : build_docs) -- 2.17.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx