#include "stdbool.h"
#include "ckb_dlfcn.h"
#include "ckb_syscalls.h"
#ifdef DEBUG
#include <stdio.h>
char message[2048];
#else
#define ckb_debug(...)
#define sprintf(...)
#endif
#define EXEC_ARGC 9
#define BUFFER_SIZE 32768
typedef uint64_t(arithmetic_func_t) (uint64_t);
uint8_t CODE_BUFFER[BUFFER_SIZE] __attribute__((aligned(RISCV_PGSIZE)));
void try_pause() {
syscall(2178, 0, 0, 0, 0, 0, 0);
}
void from_hex (uint8_t* dst, char* src, size_t len) {
for (size_t i=0; i<len; i++) {
uint8_t hi = src[i*2];
uint8_t lo = src[i*2+1];
dst[i] = (((hi & 0xf) + (hi >> 6) * 9) << 4) | (((lo & 0xf) + (lo >> 6) * 9));
}
}
void to_hex(char* dst, uint8_t* src, size_t len) {
for (size_t i = 0; i<len; i++) {
char hi = src[i] >> 4;
char lo = src[i] & 0xf;
dst[i*2] = hi + (hi < 10 ? '0' : ('a' - 10));
dst[i*2+1] = lo + (lo < 10 ? '0' : ('a' - 10));
}
dst[len*2] = '\0';
}
volatile uint64_t read_u64_le_from_hex (char* src) {
uint8_t bytes[8];
from_hex(bytes, src, 8);
return *(const uint64_t *)bytes;
}
void write_u64_le_to_hex (char* dst, uint64_t number) {
uint8_t* bytes = (uint8_t *)(&number);
to_hex(dst, bytes, 8);
}
int try_exec(char*argv[], uint64_t recursion, uint64_t number) {
sprintf(message, "argv[4] = %s", argv[4]); ckb_debug(message);
if (strlen(argv[4]) != 8*2) {
return -21;
}
uint64_t index = read_u64_le_from_hex(argv[4]);
sprintf(message, "argv[5] = %s", argv[5]); ckb_debug(message);
if (strlen(argv[5]) != 8*2) {
return -22;
}
uint64_t source = read_u64_le_from_hex(argv[5]);
sprintf(message, "argv[6] = %s", argv[6]); ckb_debug(message);
if (strlen(argv[6]) != 8*2) {
return -23;
}
uint64_t place = read_u64_le_from_hex(argv[6]);
sprintf(message, "argv[7] = %s", argv[7]); ckb_debug(message);
if (strlen(argv[7]) != 8*2) {
return -24;
}
uint64_t bounds = read_u64_le_from_hex(argv[7]);
char recursion_str[8*2+1];
char number_str[8*2+1];
char *argv_new[EXEC_ARGC] = {
argv[0], recursion_str, number_str, argv[3],
argv[4], argv[5], argv[6], argv[7], argv[8] };
write_u64_le_to_hex(recursion_str, recursion);
write_u64_le_to_hex(number_str, number);
try_pause();
syscall(2043, index, source, place, bounds, EXEC_ARGC, argv_new);
return CKB_SUCCESS;
}
int try_load_code(uint64_t* number, uint8_t* code_hash) {
void *handle = NULL;
uint64_t consumed_size = 0;
uint8_t hash_type = 0;
int ret = ckb_dlopen2(code_hash, hash_type, CODE_BUFFER, BUFFER_SIZE, &handle, &consumed_size);
if (ret != CKB_SUCCESS) {
return -31;
}
try_pause();
arithmetic_func_t* func = (arithmetic_func_t*) ckb_dlsym(handle, "apply");
if (func == NULL) {
return -32;
}
try_pause();
*number = func(*number);
return CKB_SUCCESS;
}
int main (int argc, char *argv[]) {
sprintf(message, "argc = %d", argc); ckb_debug(message);
if (argc != EXEC_ARGC) {
return -11;
}
sprintf(message, "argv[0] = %s", argv[0]); ckb_debug(message);
if (strlen(argv[0]) != 1*2) {
return -12;
}
uint8_t flag;
from_hex(&flag, argv[0], 1);
bool if_write_stack = (flag & 0b0010) == 0b0010;
if (if_write_stack) {
sprintf(message, "(try update the stack)"); ckb_debug(message);
sprintf(message, "W in [%p, %p)", CODE_BUFFER, CODE_BUFFER+BUFFER_SIZE); ckb_debug(message);
for (int i=0; i<BUFFER_SIZE; i++) {
CODE_BUFFER[i] += 1;
}
}
sprintf(message, "argv[1] = %s", argv[1]); ckb_debug(message);
if (strlen(argv[1]) != 8*2) {
return -13;
}
uint64_t recursion = read_u64_le_from_hex(argv[1]);
sprintf(message, "argv[2] = %s", argv[2]); ckb_debug(message);
if (strlen(argv[2]) != 8*2) {
return -14;
}
uint64_t number = read_u64_le_from_hex(argv[2]);
if (recursion > 0) {
try_exec(argv, recursion-1, number-1);
}
sprintf(message, "argv[3] = %s", argv[3]); ckb_debug(message);
if (strlen(argv[3]) != 8*2) {
return -15;
}
uint64_t expected = read_u64_le_from_hex(argv[3]);
bool if_load_after_exec = (flag & 0b0100) == 0b0100;
if (if_load_after_exec) {
sprintf(message, "argv[8] = %s", argv[8]); ckb_debug(message);
if (strlen(argv[8]) != 32*2) {
return -16;
}
uint8_t code_hash[32];
from_hex(code_hash, argv[8], 32);
int ret = try_load_code(&number, code_hash);
if (ret != CKB_SUCCESS) {
return ret;
}
sprintf(message, "(apply after exec) number = %ld", number); ckb_debug(message);
}
if (number == expected) {
return CKB_SUCCESS;
} else {
return -17;
}
}