diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..1cc2920 --- /dev/null +++ b/.clang-format @@ -0,0 +1,8 @@ +BasedOnStyle: LLVM +BreakBeforeBraces: Custom +BraceWrapping: + AfterFunction: true +IndentWidth: 4 +UseTab: Never +ColumnLimit: 80 +AllowShortFunctionsOnASingleLine: None diff --git a/init/init.c b/init/init.c index 8721aad..5a75a46 100644 --- a/init/init.c +++ b/init/init.c @@ -1,14 +1,14 @@ -#include +#include #include #include -#include -#include +#include #include +#include #include #include -#include -#include #include +#include +#include #include #include @@ -19,7 +19,7 @@ #include #include #include -#include + #include #include "jsmn.h" @@ -47,36 +47,36 @@ char DEFAULT_KRUN_INIT[] = "/bin/sh"; static void set_rlimits(const char *rlimits) { - unsigned long long int lim_id, lim_cur, lim_max; - struct rlimit rlim; - char *item = (char *) rlimits; - - while (1) { - lim_id = lim_cur = lim_max = ULLONG_MAX; - - lim_id = strtoull(item, &item, 10); - if (lim_id == ULLONG_MAX) { - printf("Invalid rlimit ID\n"); - break; - } - - item++; - lim_cur = strtoull(item, &item, 10); - item++; - lim_max = strtoull(item, &item, 10); - - rlim.rlim_cur = lim_cur; - rlim.rlim_max = lim_max; - if (setrlimit(lim_id, &rlim) != 0) { - printf("Error setting rlimit for ID=%lld\n", lim_id); - } - - if (*item != '\0') { - item++; - } else { - break; - } - } + unsigned long long int lim_id, lim_cur, lim_max; + struct rlimit rlim; + char *item = (char *)rlimits; + + while (1) { + lim_id = lim_cur = lim_max = ULLONG_MAX; + + lim_id = strtoull(item, &item, 10); + if (lim_id == ULLONG_MAX) { + printf("Invalid rlimit ID\n"); + break; + } + + item++; + lim_cur = strtoull(item, &item, 10); + item++; + lim_max = strtoull(item, &item, 10); + + rlim.rlim_cur = lim_cur; + rlim.rlim_max = lim_max; + if (setrlimit(lim_id, &rlim) != 0) { + printf("Error setting rlimit for ID=%lld\n", lim_id); + } + + if (*item != '\0') { + item++; + } else { + break; + } + } } #ifdef SEV @@ -84,371 +84,370 @@ static void set_rlimits(const char *rlimits) * The LUKS passphrase is obtained from a KBS attestation server, complete an * SNP attestation to get the passphrase. */ -static char * -get_luks_passphrase(int *pass_len) +static char *get_luks_passphrase(int *pass_len) { - int fd, ret, num_tokens, wid_found, url_found, tee_found, tee_data_found; - uint64_t dev_size, tc_size; - char wid[256], url[256], *tc_json, *tok_start, *tok_end; - char footer[KRUN_FOOTER_LEN], tee[256], tee_data[256], *return_str; - jsmn_parser parser; - jsmntok_t *tokens; - size_t tok_size; - - return_str = NULL; - - /* - * If a user registered the TEE config data disk with - * krun_set_data_disk(), it would appear as /dev/vdb in the guest. - * Mount this device and read the config. - */ - if (mkdir("/dev", 0755) < 0 && errno != EEXIST) { - perror("mkdir(/dev)"); - goto finish; - } + int fd, ret, num_tokens, wid_found, url_found, tee_found, tee_data_found; + uint64_t dev_size, tc_size; + char wid[256], url[256], *tc_json, *tok_start, *tok_end; + char footer[KRUN_FOOTER_LEN], tee[256], tee_data[256], *return_str; + jsmn_parser parser; + jsmntok_t *tokens; + size_t tok_size; + + return_str = NULL; + + /* + * If a user registered the TEE config data disk with + * krun_set_data_disk(), it would appear as /dev/vdb in the guest. + * Mount this device and read the config. + */ + if (mkdir("/dev", 0755) < 0 && errno != EEXIST) { + perror("mkdir(/dev)"); + goto finish; + } - if (mount("devtmpfs", "/dev", "devtmpfs", MS_RELATIME, NULL) < 0 && - errno != EBUSY) { - perror("mount(devtmpfs)"); + if (mount("devtmpfs", "/dev", "devtmpfs", MS_RELATIME, NULL) < 0 && + errno != EBUSY) { + perror("mount(devtmpfs)"); - goto rmdir_dev; - } + goto rmdir_dev; + } - fd = open("/dev/vda", O_RDONLY); - if (fd < 0) { - perror("open(/dev/vda)"); + fd = open("/dev/vda", O_RDONLY); + if (fd < 0) { + perror("open(/dev/vda)"); - goto umount_dev; - } + goto umount_dev; + } - ret = ioctl(fd, BLKGETSIZE64, &dev_size); - if (ret != 0) { - perror("ioctl(BLKGETSIZE64)"); + ret = ioctl(fd, BLKGETSIZE64, &dev_size); + if (ret != 0) { + perror("ioctl(BLKGETSIZE64)"); - goto close_dev; - } + goto close_dev; + } - if (lseek(fd, dev_size - KRUN_FOOTER_LEN, SEEK_SET) == -1) { - perror("lseek(END - KRUN_FOOTER_LEN)"); + if (lseek(fd, dev_size - KRUN_FOOTER_LEN, SEEK_SET) == -1) { + perror("lseek(END - KRUN_FOOTER_LEN)"); - goto close_dev; - } + goto close_dev; + } - ret = read(fd, &footer[0], KRUN_FOOTER_LEN); - if (ret != KRUN_FOOTER_LEN) { - perror("read(KRUN_FOOTER_LEN)"); + ret = read(fd, &footer[0], KRUN_FOOTER_LEN); + if (ret != KRUN_FOOTER_LEN) { + perror("read(KRUN_FOOTER_LEN)"); - goto close_dev; - } + goto close_dev; + } - if (memcmp(&footer[0], KRUN_MAGIC, 4) != 0) { - printf("Couldn't find KRUN footer signature, falling back to SEV\n"); - return_str = sev_get_luks_passphrase(pass_len); + if (memcmp(&footer[0], KRUN_MAGIC, 4) != 0) { + printf("Couldn't find KRUN footer signature, falling back to SEV\n"); + return_str = sev_get_luks_passphrase(pass_len); - goto close_dev; - } + goto close_dev; + } - tc_size = *(uint64_t *) &footer[4]; + tc_size = *(uint64_t *)&footer[4]; - if (lseek(fd, dev_size - tc_size - KRUN_FOOTER_LEN, SEEK_SET) == -1) { - perror("lseek(END - tc_size - KRUN_FOOTER_LEN)"); + if (lseek(fd, dev_size - tc_size - KRUN_FOOTER_LEN, SEEK_SET) == -1) { + perror("lseek(END - tc_size - KRUN_FOOTER_LEN)"); - goto close_dev; - } + goto close_dev; + } - tc_json = malloc(tc_size + 1); - if (tc_json == NULL) { - perror("malloc(tc_size)"); + tc_json = malloc(tc_size + 1); + if (tc_json == NULL) { + perror("malloc(tc_size)"); - goto close_dev; - } + goto close_dev; + } - ret = read(fd, tc_json, tc_size); - if (ret != tc_size) { - perror("read(tc_size)"); + ret = read(fd, tc_json, tc_size); + if (ret != tc_size) { + perror("read(tc_size)"); - goto free_mem; - } - tc_json[tc_size] = '\0'; + goto free_mem; + } + tc_json[tc_size] = '\0'; - /* - * Parse the TEE config's workload_id and attestation_url field. - */ - jsmn_init(&parser); + /* + * Parse the TEE config's workload_id and attestation_url field. + */ + jsmn_init(&parser); - tokens = (jsmntok_t *) malloc(sizeof(jsmntok_t) * MAX_TOKENS);\ - if (tokens == NULL) { - perror("malloc(jsmntok_t)"); + tokens = (jsmntok_t *)malloc(sizeof(jsmntok_t) * MAX_TOKENS); + if (tokens == NULL) { + perror("malloc(jsmntok_t)"); - goto free_mem; - } + goto free_mem; + } - num_tokens = jsmn_parse(&parser, tc_json, strlen(tc_json), tokens, - MAX_TOKENS); - if (num_tokens < 0) { - printf("Unable to allocate JSON tokens\n"); + num_tokens = + jsmn_parse(&parser, tc_json, strlen(tc_json), tokens, MAX_TOKENS); + if (num_tokens < 0) { + printf("Unable to allocate JSON tokens\n"); - goto free_mem; - } else if (num_tokens < 1 || tokens[0].type != JSMN_OBJECT) { - printf("Unable to find object in TEE configuration file\n"); + goto free_mem; + } else if (num_tokens < 1 || tokens[0].type != JSMN_OBJECT) { + printf("Unable to find object in TEE configuration file\n"); - goto free_mem; - } + goto free_mem; + } - wid_found = url_found = tee_found = tee_data_found = 0; - - for (int i = 1; i < num_tokens - 1; ++i) { - tok_start = tc_json + tokens[i + 1].start; - tok_end = tc_json + tokens[i + 1].end; - tok_size = tok_end - tok_start; - if (!jsoneq(tc_json, &tokens[i], "workload_id")) { - strncpy(wid, tok_start, tok_size); - wid_found = 1; - } else if (!jsoneq(tc_json, &tokens[i], "attestation_url")) { - strncpy(url, tok_start, tok_size); - url_found = 1; - } else if (!jsoneq(tc_json, &tokens[i], "tee")) { - strncpy(tee, tok_start, tok_size); - tee_found = 1; - } else if (!jsoneq(tc_json, &tokens[i], "tee_data")) { - strncpy(tee_data, tok_start, tok_size); - tee_data_found = 1; - } + wid_found = url_found = tee_found = tee_data_found = 0; + + for (int i = 1; i < num_tokens - 1; ++i) { + tok_start = tc_json + tokens[i + 1].start; + tok_end = tc_json + tokens[i + 1].end; + tok_size = tok_end - tok_start; + if (!jsoneq(tc_json, &tokens[i], "workload_id")) { + strncpy(wid, tok_start, tok_size); + wid_found = 1; + } else if (!jsoneq(tc_json, &tokens[i], "attestation_url")) { + strncpy(url, tok_start, tok_size); + url_found = 1; + } else if (!jsoneq(tc_json, &tokens[i], "tee")) { + strncpy(tee, tok_start, tok_size); + tee_found = 1; + } else if (!jsoneq(tc_json, &tokens[i], "tee_data")) { + strncpy(tee_data, tok_start, tok_size); + tee_data_found = 1; } + } - if (!wid_found) { - printf("Unable to find attestation workload ID\n"); - - goto free_mem; - } else if (!url_found) { - printf("Unable to find attestation server URL\n"); + if (!wid_found) { + printf("Unable to find attestation workload ID\n"); - goto free_mem; - } else if (!tee_found) { - printf("Unable to find TEE generation server URL\n"); + goto free_mem; + } else if (!url_found) { + printf("Unable to find attestation server URL\n"); - goto free_mem; - } + goto free_mem; + } else if (!tee_found) { + printf("Unable to find TEE generation server URL\n"); - if (strcmp(tee, "snp") == 0) { - if (tee_data_found == 0) { - printf("Unable to find SNP generation\n"); - goto free_mem; - } + goto free_mem; + } - return_str = snp_get_luks_passphrase(url, wid, tee_data, pass_len); - } else if (strcmp(tee, "sev") == 0) { - return_str = sev_get_luks_passphrase(pass_len); + if (strcmp(tee, "snp") == 0) { + if (tee_data_found == 0) { + printf("Unable to find SNP generation\n"); + goto free_mem; } + return_str = snp_get_luks_passphrase(url, wid, tee_data, pass_len); + } else if (strcmp(tee, "sev") == 0) { + return_str = sev_get_luks_passphrase(pass_len); + } + free_mem: - free(tc_json); + free(tc_json); close_dev: - close(fd); + close(fd); umount_dev: - umount("/dev"); + umount("/dev"); rmdir_dev: - rmdir("/dev"); + rmdir("/dev"); finish: - return return_str; + return return_str; } -static char * -snp_get_luks_passphrase(char *url, char *wid, char *tee_data, int *pass_len) +static char *snp_get_luks_passphrase(char *url, char *wid, char *tee_data, + int *pass_len) { - char *pass; + char *pass; - pass = (char *) malloc(MAX_PASS_SIZE); - if (pass == NULL) { - return NULL; - } + pass = (char *)malloc(MAX_PASS_SIZE); + if (pass == NULL) { + return NULL; + } - if (snp_attest(pass, url, wid, tee_data) == 0) { - *pass_len = strlen(pass); - return pass; - } + if (snp_attest(pass, url, wid, tee_data) == 0) { + *pass_len = strlen(pass); + return pass; + } - free(pass); + free(pass); - return NULL; + return NULL; } -static char * -sev_get_luks_passphrase(int *pass_len) +static char *sev_get_luks_passphrase(int *pass_len) { - char *pass = NULL; - int len; - int fd; - - pass = getenv("KRUN_PASS"); - if (pass) { - *pass_len = strnlen(pass, MAX_PASS_SIZE); - return pass; - } - if (mkdir("/sfs", 0755) < 0 && errno != EEXIST) { - perror("mkdir(/sfs)"); - return NULL; - } - - if (mount("securityfs", "/sfs", "securityfs", - MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { - perror("mount(/sfs)"); - goto cleanup_dir; - } - - fd = open(CMDLINE_SECRET_PATH, O_RDONLY); - if (fd < 0) { - goto cleanup_sfs; - } - - pass = malloc(MAX_PASS_SIZE); - if (!pass) { - goto cleanup_fd; - } - - if ((len = read(fd, pass, MAX_PASS_SIZE)) < 0) { - free(pass); - pass = NULL; - } else { - *pass_len = len; - unlink(CMDLINE_SECRET_PATH); - } + char *pass = NULL; + int len; + int fd; + + pass = getenv("KRUN_PASS"); + if (pass) { + *pass_len = strnlen(pass, MAX_PASS_SIZE); + return pass; + } + if (mkdir("/sfs", 0755) < 0 && errno != EEXIST) { + perror("mkdir(/sfs)"); + return NULL; + } + + if (mount("securityfs", "/sfs", "securityfs", + MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { + perror("mount(/sfs)"); + goto cleanup_dir; + } + + fd = open(CMDLINE_SECRET_PATH, O_RDONLY); + if (fd < 0) { + goto cleanup_sfs; + } + + pass = malloc(MAX_PASS_SIZE); + if (!pass) { + goto cleanup_fd; + } + + if ((len = read(fd, pass, MAX_PASS_SIZE)) < 0) { + free(pass); + pass = NULL; + } else { + *pass_len = len; + unlink(CMDLINE_SECRET_PATH); + } cleanup_fd: - close(fd); + close(fd); cleanup_sfs: - umount("/sfs"); + umount("/sfs"); cleanup_dir: - rmdir("/sfs"); + rmdir("/sfs"); - return pass; + return pass; } static int chroot_luks() { - char *pass; - int pass_len; - int pid; - int pipefd[2]; - int wstatus; - - pass = get_luks_passphrase(&pass_len); - if (!pass) { - printf("Couldn't find LUKS passphrase\n"); - return -1; - } - - printf("Unlocking LUKS root filesystem\n"); - - if (mount("proc", "/proc", "proc", - MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { - perror("mount(/proc)"); - return -1; - } - - pipe(pipefd); - - pid = fork(); - if (pid == 0) { - close(pipefd[1]); - dup2(pipefd[0], 0); - close(pipefd[0]); - - if (execl("/sbin/cryptsetup", "cryptsetup", "open", "/dev/vda", "luksroot", "-", NULL) < 0) { - perror("execl"); - return -1; - } - } else { - write(pipefd[1], pass, strnlen(pass, pass_len)); - close(pipefd[1]); - waitpid(pid, &wstatus, 0); - } - - memset(pass, 0, pass_len); - - printf("Mounting LUKS root filesystem\n"); - - if (mount("/dev/mapper/luksroot", "/luksroot", "ext4", 0, NULL) < 0) { - perror("mount(/luksroot)"); - return -1; - } - - chdir("/luksroot"); - - if (mount(".", "/", NULL, MS_MOVE, NULL)) { - perror("remount root"); - return -1; - } - chroot("."); - - return 0; + char *pass; + int pass_len; + int pid; + int pipefd[2]; + int wstatus; + + pass = get_luks_passphrase(&pass_len); + if (!pass) { + printf("Couldn't find LUKS passphrase\n"); + return -1; + } + + printf("Unlocking LUKS root filesystem\n"); + + if (mount("proc", "/proc", "proc", + MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { + perror("mount(/proc)"); + return -1; + } + + pipe(pipefd); + + pid = fork(); + if (pid == 0) { + close(pipefd[1]); + dup2(pipefd[0], 0); + close(pipefd[0]); + + if (execl("/sbin/cryptsetup", "cryptsetup", "open", "/dev/vda", + "luksroot", "-", NULL) < 0) { + perror("execl"); + return -1; + } + } else { + write(pipefd[1], pass, strnlen(pass, pass_len)); + close(pipefd[1]); + waitpid(pid, &wstatus, 0); + } + + memset(pass, 0, pass_len); + + printf("Mounting LUKS root filesystem\n"); + + if (mount("/dev/mapper/luksroot", "/luksroot", "ext4", 0, NULL) < 0) { + perror("mount(/luksroot)"); + return -1; + } + + chdir("/luksroot"); + + if (mount(".", "/", NULL, MS_MOVE, NULL)) { + perror("remount root"); + return -1; + } + chroot("."); + + return 0; } #endif static int mount_filesystems() { - char *const DIRS_LEVEL1[] = {"/dev", "/proc", "/sys"}; - char *const DIRS_LEVEL2[] = {"/dev/pts", "/dev/shm"}; - int i; - - for (i = 0; i < 3; ++i) { - if (mkdir(DIRS_LEVEL1[i], 0755) < 0 && errno != EEXIST) { - printf("Error creating directory (%s)\n", DIRS_LEVEL1[i]); - return -1; - } - } - - if (mount("devtmpfs", "/dev", "devtmpfs", - MS_RELATIME, NULL) < 0 && errno != EBUSY ) { - perror("mount(/dev)"); - return -1; - } - - if (mount("proc", "/proc", "proc", - MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { - perror("mount(/proc)"); - return -1; - } - - if (mount("sysfs", "/sys", "sysfs", - MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { - perror("mount(/sys)"); - return -1; - } - - if (mount("cgroup2", "/sys/fs/cgroup", "cgroup2", - MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { - perror("mount(/sys/fs/cgroup)"); - return -1; - } - - for (i = 0; i < 2; ++i) { - if (mkdir(DIRS_LEVEL2[i], 0755) < 0 && errno != EEXIST) { - printf("Error creating directory (%s)\n", DIRS_LEVEL2[i]); - return -1; - } - } - - if (mount("devpts", "/dev/pts", "devpts", - MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { - perror("mount(/dev/pts)"); - return -1; - } - - if (mount("tmpfs", "/dev/shm", "tmpfs", - MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { - perror("mount(/dev/shm)"); - return -1; - } - - /* May fail if already exists and that's fine. */ - symlink("/proc/self/fd", "/dev/fd"); - - return 0; + char *const DIRS_LEVEL1[] = {"/dev", "/proc", "/sys"}; + char *const DIRS_LEVEL2[] = {"/dev/pts", "/dev/shm"}; + int i; + + for (i = 0; i < 3; ++i) { + if (mkdir(DIRS_LEVEL1[i], 0755) < 0 && errno != EEXIST) { + printf("Error creating directory (%s)\n", DIRS_LEVEL1[i]); + return -1; + } + } + + if (mount("devtmpfs", "/dev", "devtmpfs", MS_RELATIME, NULL) < 0 && + errno != EBUSY) { + perror("mount(/dev)"); + return -1; + } + + if (mount("proc", "/proc", "proc", + MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { + perror("mount(/proc)"); + return -1; + } + + if (mount("sysfs", "/sys", "sysfs", + MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { + perror("mount(/sys)"); + return -1; + } + + if (mount("cgroup2", "/sys/fs/cgroup", "cgroup2", + MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { + perror("mount(/sys/fs/cgroup)"); + return -1; + } + + for (i = 0; i < 2; ++i) { + if (mkdir(DIRS_LEVEL2[i], 0755) < 0 && errno != EEXIST) { + printf("Error creating directory (%s)\n", DIRS_LEVEL2[i]); + return -1; + } + } + + if (mount("devpts", "/dev/pts", "devpts", + MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { + perror("mount(/dev/pts)"); + return -1; + } + + if (mount("tmpfs", "/dev/shm", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_RELATIME, + NULL) < 0) { + perror("mount(/dev/shm)"); + return -1; + } + + /* May fail if already exists and that's fine. */ + symlink("/proc/self/fd", "/dev/fd"); + + return 0; } /* @@ -468,361 +467,361 @@ static int mount_filesystems() * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -static void hexToDigit(unsigned int * val, const unsigned char * hex) +static void hexToDigit(unsigned int *val, const unsigned char *hex) { - unsigned int i; - for (i=0;i<4;i++) { - unsigned char c = hex[i]; - if (c >= 'A') c = (c & ~0x20) - 7; - c -= '0'; - *val = (*val << 4) | c; - } + unsigned int i; + for (i = 0; i < 4; i++) { + unsigned char c = hex[i]; + if (c >= 'A') + c = (c & ~0x20) - 7; + c -= '0'; + *val = (*val << 4) | c; + } } -static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf) +static void Utf32toUtf8(unsigned int codepoint, char *utf8Buf) { - if (codepoint < 0x80) { - utf8Buf[0] = (char) codepoint; - utf8Buf[1] = 0; - } else if (codepoint < 0x0800) { - utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0); - utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80); - utf8Buf[2] = 0; - } else if (codepoint < 0x10000) { - utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0); - utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80); - utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80); - utf8Buf[3] = 0; - } else if (codepoint < 0x200000) { - utf8Buf[0] =(char)((codepoint >> 18) | 0xF0); - utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80); - utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80); - utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80); - utf8Buf[4] = 0; - } else { - utf8Buf[0] = '?'; - utf8Buf[1] = 0; - } + if (codepoint < 0x80) { + utf8Buf[0] = (char)codepoint; + utf8Buf[1] = 0; + } else if (codepoint < 0x0800) { + utf8Buf[0] = (char)((codepoint >> 6) | 0xC0); + utf8Buf[1] = (char)((codepoint & 0x3F) | 0x80); + utf8Buf[2] = 0; + } else if (codepoint < 0x10000) { + utf8Buf[0] = (char)((codepoint >> 12) | 0xE0); + utf8Buf[1] = (char)(((codepoint >> 6) & 0x3F) | 0x80); + utf8Buf[2] = (char)((codepoint & 0x3F) | 0x80); + utf8Buf[3] = 0; + } else if (codepoint < 0x200000) { + utf8Buf[0] = (char)((codepoint >> 18) | 0xF0); + utf8Buf[1] = (char)(((codepoint >> 12) & 0x3F) | 0x80); + utf8Buf[2] = (char)(((codepoint >> 6) & 0x3F) | 0x80); + utf8Buf[3] = (char)((codepoint & 0x3F) | 0x80); + utf8Buf[4] = 0; + } else { + utf8Buf[0] = '?'; + utf8Buf[1] = 0; + } } - /* Do not worry about invalid JSON, it was already parsed by jsmn. */ static void unescape_string(char *string, int len) { - unsigned char *val = (unsigned char *) string; - unsigned char *end; - int i = 0; - - end = val + len; - while (val < end) { - if (*val != '\\') { - string[i++] = *val++; - continue; - } - switch (*++val) { - case 'n': - string[i++] = '\n'; - break; - case 't': - string[i++] = '\t'; - break; - case 'r': - string[i++] = '\r'; - break; - case 'b': - string[i++] = '\b'; - break; - case 'f': - string[i++] = '\f'; - break; - case '\\': - string[i++] = '\\'; - break; - case '\"': - string[i++] = '\"'; - break; - case '/': - string[i++] = '/'; - break; - case 'u': { - const char * unescaped = "?"; - char utf8Buf[5]; - unsigned int codepoint = 0; - hexToDigit(&codepoint, val++); - val+=3; - /* check if this is a surrogate */ - if ((codepoint & 0xFC00) == 0xD800) { - val++; - if (val[0] == '\\' && val[1] == 'u') { - unsigned int surrogate = 0; - hexToDigit(&surrogate, val + 2); - codepoint = - (((codepoint & 0x3F) << 10) | - ((((codepoint >> 6) & 0xF) + 1) << 16) | - (surrogate & 0x3FF)); - val += 5; - } else { - unescaped = "?"; - break; - } - } - - Utf32toUtf8(codepoint, utf8Buf); - unescaped = utf8Buf; - - if (codepoint == 0) { - memcpy(&string[i++], unescaped, 1); - continue; - } - memcpy(&string[i], unescaped, (unsigned int)strlen(unescaped)); - break; - } - } - } - string[i] = '\0'; + unsigned char *val = (unsigned char *)string; + unsigned char *end; + int i = 0; + + end = val + len; + while (val < end) { + if (*val != '\\') { + string[i++] = *val++; + continue; + } + switch (*++val) { + case 'n': + string[i++] = '\n'; + break; + case 't': + string[i++] = '\t'; + break; + case 'r': + string[i++] = '\r'; + break; + case 'b': + string[i++] = '\b'; + break; + case 'f': + string[i++] = '\f'; + break; + case '\\': + string[i++] = '\\'; + break; + case '\"': + string[i++] = '\"'; + break; + case '/': + string[i++] = '/'; + break; + case 'u': { + const char *unescaped = "?"; + char utf8Buf[5]; + unsigned int codepoint = 0; + hexToDigit(&codepoint, val++); + val += 3; + /* check if this is a surrogate */ + if ((codepoint & 0xFC00) == 0xD800) { + val++; + if (val[0] == '\\' && val[1] == 'u') { + unsigned int surrogate = 0; + hexToDigit(&surrogate, val + 2); + codepoint = (((codepoint & 0x3F) << 10) | + ((((codepoint >> 6) & 0xF) + 1) << 16) | + (surrogate & 0x3FF)); + val += 5; + } else { + unescaped = "?"; + break; + } + } + + Utf32toUtf8(codepoint, utf8Buf); + unescaped = utf8Buf; + + if (codepoint == 0) { + memcpy(&string[i++], unescaped, 1); + continue; + } + memcpy(&string[i], unescaped, (unsigned int)strlen(unescaped)); + break; + } + } + } + string[i] = '\0'; } static void config_parse_env(char *data, jsmntok_t *token) { - jsmntok_t *tenv; - char *env, *env_val; - int len; - int i; - - for (i = 0; i < token->size; i++) { - tenv = &token[i + 1]; - - env = data + tenv->start; - len = tenv->end - tenv->start; - - unescape_string(env, len); - - env_val = strstr(env, "="); - if (!env_val) { - continue; - } - - env[len] = '\0'; - *env_val = '\0'; - env_val++; - - if ((strcmp(env, "HOME") == 0) || - (strcmp(env, "TERM") == 0)) { - setenv(env, env_val, 1); - } else { - setenv(env, env_val, 0); - } - } + jsmntok_t *tenv; + char *env, *env_val; + int len; + int i; + + for (i = 0; i < token->size; i++) { + tenv = &token[i + 1]; + + env = data + tenv->start; + len = tenv->end - tenv->start; + + unescape_string(env, len); + + env_val = strstr(env, "="); + if (!env_val) { + continue; + } + + env[len] = '\0'; + *env_val = '\0'; + env_val++; + + if ((strcmp(env, "HOME") == 0) || (strcmp(env, "TERM") == 0)) { + setenv(env, env_val, 1); + } else { + setenv(env, env_val, 0); + } + } } -static char ** config_parse_args(char *data, jsmntok_t *token) +static char **config_parse_args(char *data, jsmntok_t *token) { - jsmntok_t *targ; - char *arg, *value; - char **argv; - int len; - int i, j; + jsmntok_t *targ; + char *arg, *value; + char **argv; + int len; + int i, j; - argv = malloc(MAX_ARGS * sizeof(char *)); - j = 0; + argv = malloc(MAX_ARGS * sizeof(char *)); + j = 0; - for (i = 0; i < token->size; i++) { - targ = &token[i + 1]; + for (i = 0; i < token->size; i++) { + targ = &token[i + 1]; - value = data + targ->start; - len = targ->end - targ->start; + value = data + targ->start; + len = targ->end - targ->start; - arg = malloc(len + 1); - memcpy(arg, value, len); - arg[len] = '\0'; + arg = malloc(len + 1); + memcpy(arg, value, len); + arg[len] = '\0'; - unescape_string(arg, len); + unescape_string(arg, len); - argv[j] = arg; - j++; - } + argv[j] = arg; + j++; + } - if (j == 0) { - free(argv); - argv = NULL; - } else { - argv[j] = NULL; - } + if (j == 0) { + free(argv); + argv = NULL; + } else { + argv[j] = NULL; + } - return argv; + return argv; } -static char * config_parse_string(char *data, jsmntok_t *token) +static char *config_parse_string(char *data, jsmntok_t *token) { - char *string; - char *val; - int len; + char *string; + char *val; + int len; - val = data + token->start; - len = token->end - token->start; - if (!len) { - return NULL; - } + val = data + token->start; + len = token->end - token->start; + if (!len) { + return NULL; + } - string = malloc(len + 1); + string = malloc(len + 1); - if (!string) { - return NULL; - } - memcpy(string, val, len); - string[len] = '\0'; + if (!string) { + return NULL; + } + memcpy(string, val, len); + string[len] = '\0'; - unescape_string(string, len); + unescape_string(string, len); - return string; + return string; } -static int jsoneq(const char *json, jsmntok_t *tok, const char *s) { - if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start && - strncasecmp(json + tok->start, s, tok->end - tok->start) == 0) { - return 0; - } - return -1; +static int jsoneq(const char *json, jsmntok_t *tok, const char *s) +{ + if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start && + strncasecmp(json + tok->start, s, tok->end - tok->start) == 0) { + return 0; + } + return -1; } -char ** concat_entrypoint_argv(char **entrypoint, char **config_argv) +char **concat_entrypoint_argv(char **entrypoint, char **config_argv) { - char **argv; - int i, j; + char **argv; + int i, j; - argv = malloc(MAX_ARGS * sizeof(char *)); + argv = malloc(MAX_ARGS * sizeof(char *)); - for (i = 0; i < MAX_ARGS && entrypoint[i]; i++) { - argv[i] = entrypoint[i]; - } + for (i = 0; i < MAX_ARGS && entrypoint[i]; i++) { + argv[i] = entrypoint[i]; + } - for (j = 0; j < MAX_ARGS && config_argv[j]; i++, j++) { - argv[i] = config_argv[j]; - } + for (j = 0; j < MAX_ARGS && config_argv[j]; i++, j++) { + argv[i] = config_argv[j]; + } - argv[i] = NULL; + argv[i] = NULL; - return argv; + return argv; } static int config_parse_file(char ***argv, char **workdir) { - jsmn_parser parser; - jsmntok_t *tokens; - struct stat stat; - char *data; - char *config_file; - char **config_argv; - char **entrypoint; - int parsed_env, parsed_workdir, parsed_args, parsed_entrypoint; - int num_tokens; - int ret = -1; - int fd; - int i; - - config_file = getenv("KRUN_CONFIG"); - if (!config_file) { - config_file = CONFIG_FILE_PATH; - } - - fd = open(config_file, O_RDONLY); - if (fd < 0) { - return ret; - } - - if (fstat(fd, &stat) != 0) { - perror("Couldn't stat config file"); - goto cleanup_fd; - } - - data = malloc(stat.st_size); - if (!data) { - perror("Couldn't allocate memory"); - goto cleanup_fd; - } - - if (read(fd, data, stat.st_size) < 0) { - perror("Error reading config file"); - goto cleanup_data; - } - - tokens = malloc(MAX_TOKENS * sizeof(jsmntok_t)); - if (!tokens) { - perror("Couldn't allocate memory"); - goto cleanup_data; - } - - jsmn_init(&parser); - num_tokens = jsmn_parse(&parser, data, strlen(data), - tokens, MAX_TOKENS); - if (num_tokens < 0) { - printf("Error parsing config file\n"); - goto cleanup_tokens; - } - - if (num_tokens < 1 || tokens[0].type != JSMN_OBJECT) { - printf("Couldn't find object in config file\n"); - goto cleanup_tokens; - } - - config_argv = NULL; - entrypoint = NULL; - parsed_env = parsed_workdir = parsed_args = parsed_entrypoint = 0; - - for (i = 1; i < num_tokens && (!parsed_env || !parsed_args || !parsed_workdir); i++) { - if (!parsed_env && jsoneq(data, &tokens[i], "Env") == 0 && - (i + 1) < num_tokens && tokens[i + 1].type == JSMN_ARRAY) { - config_parse_env(data, &tokens[i + 1]); - parsed_env = 1; - } - - if (!parsed_args && jsoneq(data, &tokens[i], "args") == 0 && - (i + 1) < num_tokens) { - config_argv = config_parse_args(data, &tokens[i + 1]); - parsed_args = 1; - } - - if (!parsed_args && jsoneq(data, &tokens[i], "Cmd") == 0 && - (i + 1) < num_tokens) { - config_argv = config_parse_args(data, &tokens[i + 1]); - parsed_args = 1; - } - - if (!parsed_workdir && jsoneq(data, &tokens[i], "WorkingDir") == 0 && - (i + 1) < num_tokens) { - *workdir = config_parse_string(data, &tokens[i + 1]); - parsed_workdir = 1; - } - - if (!parsed_workdir && jsoneq(data, &tokens[i], "Cwd") == 0 && - (i + 1) < num_tokens) { - *workdir = config_parse_string(data, &tokens[i + 1]); - parsed_workdir = 1; - } - - if (!parsed_entrypoint && jsoneq(data, &tokens[i], "Entrypoint") == 0 && - (i + 1) < num_tokens) { - entrypoint = config_parse_args(data, &tokens[i + 1]); - parsed_entrypoint = 1; - } - } - - if (config_argv && entrypoint) { - *argv = concat_entrypoint_argv(entrypoint, config_argv); - } else { - *argv = config_argv; - } - - ret = 0; + jsmn_parser parser; + jsmntok_t *tokens; + struct stat stat; + char *data; + char *config_file; + char **config_argv; + char **entrypoint; + int parsed_env, parsed_workdir, parsed_args, parsed_entrypoint; + int num_tokens; + int ret = -1; + int fd; + int i; + + config_file = getenv("KRUN_CONFIG"); + if (!config_file) { + config_file = CONFIG_FILE_PATH; + } + + fd = open(config_file, O_RDONLY); + if (fd < 0) { + return ret; + } + + if (fstat(fd, &stat) != 0) { + perror("Couldn't stat config file"); + goto cleanup_fd; + } + + data = malloc(stat.st_size); + if (!data) { + perror("Couldn't allocate memory"); + goto cleanup_fd; + } + + if (read(fd, data, stat.st_size) < 0) { + perror("Error reading config file"); + goto cleanup_data; + } + + tokens = malloc(MAX_TOKENS * sizeof(jsmntok_t)); + if (!tokens) { + perror("Couldn't allocate memory"); + goto cleanup_data; + } + + jsmn_init(&parser); + num_tokens = jsmn_parse(&parser, data, strlen(data), tokens, MAX_TOKENS); + if (num_tokens < 0) { + printf("Error parsing config file\n"); + goto cleanup_tokens; + } + + if (num_tokens < 1 || tokens[0].type != JSMN_OBJECT) { + printf("Couldn't find object in config file\n"); + goto cleanup_tokens; + } + + config_argv = NULL; + entrypoint = NULL; + parsed_env = parsed_workdir = parsed_args = parsed_entrypoint = 0; + + for (i = 1; + i < num_tokens && (!parsed_env || !parsed_args || !parsed_workdir); + i++) { + if (!parsed_env && jsoneq(data, &tokens[i], "Env") == 0 && + (i + 1) < num_tokens && tokens[i + 1].type == JSMN_ARRAY) { + config_parse_env(data, &tokens[i + 1]); + parsed_env = 1; + } + + if (!parsed_args && jsoneq(data, &tokens[i], "args") == 0 && + (i + 1) < num_tokens) { + config_argv = config_parse_args(data, &tokens[i + 1]); + parsed_args = 1; + } + + if (!parsed_args && jsoneq(data, &tokens[i], "Cmd") == 0 && + (i + 1) < num_tokens) { + config_argv = config_parse_args(data, &tokens[i + 1]); + parsed_args = 1; + } + + if (!parsed_workdir && jsoneq(data, &tokens[i], "WorkingDir") == 0 && + (i + 1) < num_tokens) { + *workdir = config_parse_string(data, &tokens[i + 1]); + parsed_workdir = 1; + } + + if (!parsed_workdir && jsoneq(data, &tokens[i], "Cwd") == 0 && + (i + 1) < num_tokens) { + *workdir = config_parse_string(data, &tokens[i + 1]); + parsed_workdir = 1; + } + + if (!parsed_entrypoint && jsoneq(data, &tokens[i], "Entrypoint") == 0 && + (i + 1) < num_tokens) { + entrypoint = config_parse_args(data, &tokens[i + 1]); + parsed_entrypoint = 1; + } + } + + if (config_argv && entrypoint) { + *argv = concat_entrypoint_argv(entrypoint, config_argv); + } else { + *argv = config_argv; + } + + ret = 0; cleanup_tokens: - free(tokens); + free(tokens); cleanup_data: - free(data); + free(data); cleanup_fd: - close(fd); + close(fd); - return ret; + return ret; } #ifdef __TIMESYNC__ @@ -835,62 +834,62 @@ cleanup_fd: void clock_worker() { - int sockfd, n; - struct sockaddr_vm serveraddr; - char buf[BUFSIZE]; - struct timespec gtime; - struct timespec htime; - uint64_t gtime_ns; - uint64_t htime_ns; - - sockfd = socket(AF_VSOCK, SOCK_DGRAM, 0); - if (sockfd < 0) { - perror("Couldn't create timesync socket\n"); - return; - } - - bzero((char *) &serveraddr, sizeof(serveraddr)); - serveraddr.svm_family = AF_VSOCK; - serveraddr.svm_port = TSYNC_PORT; - serveraddr.svm_cid = 3; - - bzero(buf, BUFSIZE); - - n = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); - if (n < 0) { - printf("Couldn't bind timesync socket\n"); - return; - } - - while (1) { - n = recv(sockfd, buf, BUFSIZE, 0); - if (n < 0) { - perror("Error in timesync recv\n"); - return; - } else if (n != 8) { - printf("Ignoring bogus timesync packet\n"); - continue; - } - - htime_ns = *(uint64_t *) &buf[0]; - clock_gettime(CLOCK_REALTIME, >ime); - gtime_ns = gtime.tv_sec * NANOS_IN_SECOND; - gtime_ns += gtime.tv_nsec; - - if (llabs(htime_ns - gtime_ns) > DELTA_SYNC) { - htime.tv_sec = htime_ns / NANOS_IN_SECOND; - htime.tv_nsec = htime_ns % NANOS_IN_SECOND; - clock_settime(CLOCK_REALTIME, &htime); - } - } + int sockfd, n; + struct sockaddr_vm serveraddr; + char buf[BUFSIZE]; + struct timespec gtime; + struct timespec htime; + uint64_t gtime_ns; + uint64_t htime_ns; + + sockfd = socket(AF_VSOCK, SOCK_DGRAM, 0); + if (sockfd < 0) { + perror("Couldn't create timesync socket\n"); + return; + } + + bzero((char *)&serveraddr, sizeof(serveraddr)); + serveraddr.svm_family = AF_VSOCK; + serveraddr.svm_port = TSYNC_PORT; + serveraddr.svm_cid = 3; + + bzero(buf, BUFSIZE); + + n = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); + if (n < 0) { + printf("Couldn't bind timesync socket\n"); + return; + } + + while (1) { + n = recv(sockfd, buf, BUFSIZE, 0); + if (n < 0) { + perror("Error in timesync recv\n"); + return; + } else if (n != 8) { + printf("Ignoring bogus timesync packet\n"); + continue; + } + + htime_ns = *(uint64_t *)&buf[0]; + clock_gettime(CLOCK_REALTIME, >ime); + gtime_ns = gtime.tv_sec * NANOS_IN_SECOND; + gtime_ns += gtime.tv_nsec; + + if (llabs(htime_ns - gtime_ns) > DELTA_SYNC) { + htime.tv_sec = htime_ns / NANOS_IN_SECOND; + htime.tv_nsec = htime_ns % NANOS_IN_SECOND; + clock_settime(CLOCK_REALTIME, &htime); + } + } } #endif int reopen_fd(int fd, char *path, int flags) { - int newfd = open(path,flags); + int newfd = open(path, flags); if (newfd < 0) { - printf("Failed to open '%s': %s\n", path,strerror(errno)); + printf("Failed to open '%s': %s\n", path, strerror(errno)); return -1; } @@ -916,9 +915,11 @@ int setup_redirects() char name_buf[1024]; struct dirent *entry = NULL; - while ((entry=readdir(ports_dir))) { - char* port_identifier = entry->d_name; - int result_len = snprintf(path, sizeof(path), "/sys/class/virtio-ports/%s/name", port_identifier); + while ((entry = readdir(ports_dir))) { + char *port_identifier = entry->d_name; + int result_len = + snprintf(path, sizeof(path), "/sys/class/virtio-ports/%s/name", + port_identifier); // result was truncated if (result_len > sizeof(name_buf) - 1) { @@ -938,10 +939,12 @@ int setup_redirects() // if previous snprintf didn't fail, this one cannot fail either snprintf(path, sizeof(path), "/dev/%s", port_identifier); reopen_fd(STDIN_FILENO, path, O_RDONLY); - } else if (port_name != NULL && strcmp(port_name, "krun-stdout\n") == 0) { - snprintf(path, sizeof(path), "/dev/%s", port_identifier); - reopen_fd(STDOUT_FILENO, path, O_WRONLY); - } else if (port_name != NULL && strcmp(port_name, "krun-stderr\n") == 0) { + } else if (port_name != NULL && + strcmp(port_name, "krun-stdout\n") == 0) { + snprintf(path, sizeof(path), "/dev/%s", port_identifier); + reopen_fd(STDOUT_FILENO, path, O_WRONLY); + } else if (port_name != NULL && + strcmp(port_name, "krun-stderr\n") == 0) { snprintf(path, sizeof(path), "/dev/%s", port_identifier); reopen_fd(STDERR_FILENO, path, O_WRONLY); } @@ -953,101 +956,104 @@ int setup_redirects() int main(int argc, char **argv) { - struct ifreq ifr; - int sockfd; - char localhost[] = "localhost\0"; - char *hostname; - char *krun_home; - char *krun_term; - char *krun_init; - char *config_workdir, *env_workdir; - char *rlimits; - char **config_argv, **exec_argv; + struct ifreq ifr; + int sockfd; + char localhost[] = "localhost\0"; + char *hostname; + char *krun_home; + char *krun_term; + char *krun_init; + char *config_workdir, *env_workdir; + char *rlimits; + char **config_argv, **exec_argv; #ifdef SEV - if (chroot_luks() < 0) { - printf("Couldn't switch to LUKS volume, bailing out\n"); - exit(-1); - } + if (chroot_luks() < 0) { + printf("Couldn't switch to LUKS volume, bailing out\n"); + exit(-1); + } #endif - if (mount_filesystems() < 0) { - printf("Couldn't mount filesystems, bailing out\n"); - exit(-2); - } - - setsid(); - ioctl(0, TIOCSCTTY, 1); - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd >= 0) { - memset(&ifr, 0, sizeof ifr); - strncpy(ifr.ifr_name, "lo", IFNAMSIZ); - ifr.ifr_flags |= IFF_UP; - ioctl(sockfd, SIOCSIFFLAGS, &ifr); - close(sockfd); - } - - config_argv = NULL; - config_workdir = NULL; - - config_parse_file(&config_argv, &config_workdir); - - krun_home = getenv("KRUN_HOME"); - if (krun_home) { - setenv("HOME", krun_home, 1); - } - - krun_term = getenv("KRUN_TERM"); - if (krun_term) { - setenv("TERM", krun_term, 1); - } - - hostname = getenv("HOSTNAME"); - if (hostname) { - sethostname(hostname, strlen(hostname)); - } else { - sethostname(&localhost[0], strlen(localhost)); - } - - rlimits = getenv("KRUN_RLIMITS"); - if (rlimits) { - set_rlimits(rlimits); - } - - env_workdir = getenv("KRUN_WORKDIR"); - if (env_workdir) { - chdir(env_workdir); - } else if (config_workdir) { - chdir(config_workdir); - } - - exec_argv = argv; - krun_init = getenv("KRUN_INIT"); - if (krun_init) { - exec_argv[0] = krun_init; - } else if (config_argv) { - exec_argv = config_argv; - } else { - exec_argv[0] = &DEFAULT_KRUN_INIT[0]; - } + if (mount_filesystems() < 0) { + printf("Couldn't mount filesystems, bailing out\n"); + exit(-2); + } + + setsid(); + ioctl(0, TIOCSCTTY, 1); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd >= 0) { + memset(&ifr, 0, sizeof ifr); + strncpy(ifr.ifr_name, "lo", IFNAMSIZ); + ifr.ifr_flags |= IFF_UP; + ioctl(sockfd, SIOCSIFFLAGS, &ifr); + close(sockfd); + } + + config_argv = NULL; + config_workdir = NULL; + + config_parse_file(&config_argv, &config_workdir); + + krun_home = getenv("KRUN_HOME"); + if (krun_home) { + setenv("HOME", krun_home, 1); + } + + krun_term = getenv("KRUN_TERM"); + if (krun_term) { + setenv("TERM", krun_term, 1); + } + + hostname = getenv("HOSTNAME"); + if (hostname) { + sethostname(hostname, strlen(hostname)); + } else { + sethostname(&localhost[0], strlen(localhost)); + } + + rlimits = getenv("KRUN_RLIMITS"); + if (rlimits) { + set_rlimits(rlimits); + } + + env_workdir = getenv("KRUN_WORKDIR"); + if (env_workdir) { + chdir(env_workdir); + } else if (config_workdir) { + chdir(config_workdir); + } + + exec_argv = argv; + krun_init = getenv("KRUN_INIT"); + if (krun_init) { + exec_argv[0] = krun_init; + } else if (config_argv) { + exec_argv = config_argv; + } else { + exec_argv[0] = &DEFAULT_KRUN_INIT[0]; + } #ifdef __TIMESYNC__ - if (fork() == 0) { - clock_worker(); - } + if (fork() == 0) { + clock_worker(); + } #endif - // We need to fork ourselves, because pid 1 cannot doesn't receive SIGINT signal + // We need to fork ourselves, because pid 1 cannot doesn't receive SIGINT + // signal int pid = fork(); if (pid < 0) { perror("fork"); exit(-3); - } if (pid == 0) { // child + } + if (pid == 0) { // child if (setup_redirects() < 0) { - exit(-4); + exit(-4); } if (execvp(exec_argv[0], exec_argv) < 0) { - printf("Couldn't execute '%s' inside the vm: %s\n", exec_argv[0], strerror(errno)); + printf("Couldn't execute '%s' inside the vm: %s\n", exec_argv[0], + strerror(errno)); exit(-3); } } else { // parent @@ -1058,5 +1064,5 @@ int main(int argc, char **argv) waitpid(pid, NULL, 0); } - return 0; + return 0; } diff --git a/init/jsmn.h b/init/jsmn.h index bdddd7f..e485024 100644 --- a/init/jsmn.h +++ b/init/jsmn.h @@ -40,20 +40,20 @@ extern "C" { * o Other primitive: number, boolean (true/false) or null */ typedef enum { - JSMN_UNDEFINED = 0, - JSMN_OBJECT = 1 << 0, - JSMN_ARRAY = 1 << 1, - JSMN_STRING = 1 << 2, - JSMN_PRIMITIVE = 1 << 3 + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1 << 0, + JSMN_ARRAY = 1 << 1, + JSMN_STRING = 1 << 2, + JSMN_PRIMITIVE = 1 << 3 } jsmntype_t; enum jsmnerr { - /* Not enough tokens were provided */ - JSMN_ERROR_NOMEM = -1, - /* Invalid character inside JSON string */ - JSMN_ERROR_INVAL = -2, - /* The string is not a full JSON packet, more bytes expected */ - JSMN_ERROR_PART = -3 + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 }; /** @@ -63,12 +63,12 @@ enum jsmnerr { * end end position in JSON data string */ typedef struct jsmntok { - jsmntype_t type; - int start; - int end; - int size; + jsmntype_t type; + int start; + int end; + int size; #ifdef JSMN_PARENT_LINKS - int parent; + int parent; #endif } jsmntok_t; @@ -77,9 +77,9 @@ typedef struct jsmntok { * the string being parsed now and current position in that string. */ typedef struct jsmn_parser { - unsigned int pos; /* offset in the JSON string */ - unsigned int toknext; /* next token to allocate */ - int toksuper; /* superior token node, e.g. parent object or array */ + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g. parent object or array */ } jsmn_parser; /** @@ -100,29 +100,31 @@ JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, * Allocates a fresh unused token from the token pool. */ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *tok; - if (parser->toknext >= num_tokens) { - return NULL; - } - tok = &tokens[parser->toknext++]; - tok->start = tok->end = -1; - tok->size = 0; + const size_t num_tokens) +{ + jsmntok_t *tok; + if (parser->toknext >= num_tokens) { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; #ifdef JSMN_PARENT_LINKS - tok->parent = -1; + tok->parent = -1; #endif - return tok; + return tok; } /** * Fills token type and boundaries. */ static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type, - const int start, const int end) { - token->type = type; - token->start = start; - token->end = end; - token->size = 0; + const int start, const int end) +{ + token->type = type; + token->start = start; + token->end = end; + token->size = 0; } /** @@ -130,59 +132,60 @@ static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type, */ static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *token; - int start; + const size_t num_tokens) +{ + jsmntok_t *token; + int start; - start = parser->pos; + start = parser->pos; - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - switch (js[parser->pos]) { + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { #ifndef JSMN_STRICT - /* In strict mode primitive must be followed by "," or "}" or "]" */ - case ':': + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': #endif - case '\t': - case '\r': - case '\n': - case ' ': - case ',': - case ']': - case '}': - goto found; - default: - /* to quiet a warning from gcc*/ - break; - } - /* libkrun: Let's be permissive with non-ASCII bytes - if (js[parser->pos] < 32 || js[parser->pos] >= 127) { - parser->pos = start; - return JSMN_ERROR_INVAL; + case '\t': + case '\r': + case '\n': + case ' ': + case ',': + case ']': + case '}': + goto found; + default: + /* to quiet a warning from gcc*/ + break; + } + /* libkrun: Let's be permissive with non-ASCII bytes + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + */ } - */ - } #ifdef JSMN_STRICT - /* In strict mode primitive must be followed by a comma/object/array */ - parser->pos = start; - return JSMN_ERROR_PART; + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; #endif found: - if (tokens == NULL) { - parser->pos--; - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); #ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; + token->parent = parser->toksuper; #endif - parser->pos--; - return 0; + parser->pos--; + return 0; } /** @@ -190,274 +193,282 @@ found: */ static int jsmn_parse_string(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *token; + const size_t num_tokens) +{ + jsmntok_t *token; - int start = parser->pos; - - /* Skip starting quote */ - parser->pos++; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c = js[parser->pos]; + int start = parser->pos; - /* Quote: end of string */ - if (c == '\"') { - if (tokens == NULL) { - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); + /* Skip starting quote */ + parser->pos++; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; + + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) { + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); #ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; + token->parent = parser->toksuper; #endif - return 0; - } + return 0; + } - /* Backslash: Quoted symbol expected */ - if (c == '\\' && parser->pos + 1 < len) { - int i; - parser->pos++; - switch (js[parser->pos]) { - /* Allowed escaped symbols */ - case '\"': - case '/': - case '\\': - case 'b': - case 'f': - case 'r': - case 'n': - case 't': - break; - /* Allows escaped symbol \uXXXX */ - case 'u': - parser->pos++; - for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; - i++) { - /* If it isn't a hex character we have an error */ - if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ - (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ - (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ - parser->pos = start; - return JSMN_ERROR_INVAL; - } - parser->pos++; + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': + case '/': + case '\\': + case 'b': + case 'f': + case 'r': + case 'n': + case 't': + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for (i = 0; + i < 4 && parser->pos < len && js[parser->pos] != '\0'; + i++) { + /* If it isn't a hex character we have an error */ + if (!((js[parser->pos] >= 48 && + js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && + js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && + js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } } - parser->pos--; - break; - /* Unexpected symbol */ - default: - parser->pos = start; - return JSMN_ERROR_INVAL; - } } - } - parser->pos = start; - return JSMN_ERROR_PART; + parser->pos = start; + return JSMN_ERROR_PART; } /** * Parse JSON string and fill tokens. */ JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, - jsmntok_t *tokens, const unsigned int num_tokens) { - int r; - int i; - jsmntok_t *token; - int count = parser->toknext; + jsmntok_t *tokens, const unsigned int num_tokens) +{ + int r; + int i; + jsmntok_t *token; + int count = parser->toknext; - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c; - jsmntype_t type; + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; - c = js[parser->pos]; - switch (c) { - case '{': - case '[': - count++; - if (tokens == NULL) { - break; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - return JSMN_ERROR_NOMEM; - } - if (parser->toksuper != -1) { - jsmntok_t *t = &tokens[parser->toksuper]; + c = js[parser->pos]; + switch (c) { + case '{': + case '[': + count++; + if (tokens == NULL) { + break; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + return JSMN_ERROR_NOMEM; + } + if (parser->toksuper != -1) { + jsmntok_t *t = &tokens[parser->toksuper]; #ifdef JSMN_STRICT - /* In strict mode an object or array can't become a key */ - if (t->type == JSMN_OBJECT) { - return JSMN_ERROR_INVAL; - } + /* In strict mode an object or array can't become a key */ + if (t->type == JSMN_OBJECT) { + return JSMN_ERROR_INVAL; + } #endif - t->size++; + t->size++; #ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; + token->parent = parser->toksuper; #endif - } - token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); - token->start = parser->pos; - parser->toksuper = parser->toknext - 1; - break; - case '}': - case ']': - if (tokens == NULL) { - break; - } - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': + case ']': + if (tokens == NULL) { + break; + } + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); #ifdef JSMN_PARENT_LINKS - if (parser->toknext < 1) { - return JSMN_ERROR_INVAL; - } - token = &tokens[parser->toknext - 1]; - for (;;) { - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - token->end = parser->pos + 1; - parser->toksuper = token->parent; - break; - } - if (token->parent == -1) { - if (token->type != type || parser->toksuper == -1) { - return JSMN_ERROR_INVAL; - } - break; - } - token = &tokens[token->parent]; - } + if (parser->toknext < 1) { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) { + if (token->type != type || parser->toksuper == -1) { + return JSMN_ERROR_INVAL; + } + break; + } + token = &tokens[token->parent]; + } #else - for (i = parser->toknext - 1; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - parser->toksuper = -1; - token->end = parser->pos + 1; - break; - } - } - /* Error if unmatched closing bracket */ - if (i == -1) { - return JSMN_ERROR_INVAL; - } - for (; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - parser->toksuper = i; - break; - } - } + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) { + return JSMN_ERROR_INVAL; + } + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } #endif - break; - case '\"': - r = jsmn_parse_string(parser, js, len, tokens, num_tokens); - if (r < 0) { - return r; - } - count++; - if (parser->toksuper != -1 && tokens != NULL) { - tokens[parser->toksuper].size++; - } - break; - case '\t': - case '\r': - case '\n': - case ' ': - break; - case ':': - parser->toksuper = parser->toknext - 1; - break; - case ',': - if (tokens != NULL && parser->toksuper != -1 && - tokens[parser->toksuper].type != JSMN_ARRAY && - tokens[parser->toksuper].type != JSMN_OBJECT) { + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) { + return r; + } + count++; + if (parser->toksuper != -1 && tokens != NULL) { + tokens[parser->toksuper].size++; + } + break; + case '\t': + case '\r': + case '\n': + case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { #ifdef JSMN_PARENT_LINKS - parser->toksuper = tokens[parser->toksuper].parent; + parser->toksuper = tokens[parser->toksuper].parent; #else - for (i = parser->toknext - 1; i >= 0; i--) { - if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { - if (tokens[i].start != -1 && tokens[i].end == -1) { - parser->toksuper = i; - break; - } - } - } + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || + tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } #endif - } - break; + } + break; #ifdef JSMN_STRICT - /* In strict mode primitives are: numbers and booleans */ - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 't': - case 'f': - case 'n': - /* And they must not be keys of the object */ - if (tokens != NULL && parser->toksuper != -1) { - const jsmntok_t *t = &tokens[parser->toksuper]; - if (t->type == JSMN_OBJECT || - (t->type == JSMN_STRING && t->size != 0)) { - return JSMN_ERROR_INVAL; - } - } + /* In strict mode primitives are: numbers and booleans */ + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 't': + case 'f': + case 'n': + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) { + const jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } #else - /* In non-strict mode every unquoted value is a primitive */ - default: + /* In non-strict mode every unquoted value is a primitive */ + default: #endif - r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); - if (r < 0) { - return r; - } - count++; - if (parser->toksuper != -1 && tokens != NULL) { - tokens[parser->toksuper].size++; - } - break; + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) { + return r; + } + count++; + if (parser->toksuper != -1 && tokens != NULL) { + tokens[parser->toksuper].size++; + } + break; #ifdef JSMN_STRICT - /* Unexpected char in strict mode */ - default: - return JSMN_ERROR_INVAL; + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; #endif + } } - } - if (tokens != NULL) { - for (i = parser->toknext - 1; i >= 0; i--) { - /* Unmatched opened object or array */ - if (tokens[i].start != -1 && tokens[i].end == -1) { - return JSMN_ERROR_PART; - } + if (tokens != NULL) { + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) { + return JSMN_ERROR_PART; + } + } } - } - return count; + return count; } /** * Creates a new parser based over a given buffer with an array of tokens * available. */ -JSMN_API void jsmn_init(jsmn_parser *parser) { - parser->pos = 0; - parser->toknext = 0; - parser->toksuper = -1; +JSMN_API void jsmn_init(jsmn_parser *parser) +{ + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; } #endif /* JSMN_HEADER */ diff --git a/init/tee/kbs/kbs.h b/init/tee/kbs/kbs.h index 5af9086..9549a76 100644 --- a/init/tee/kbs/kbs.h +++ b/init/tee/kbs/kbs.h @@ -4,8 +4,8 @@ #define _KBS #include -#include #include +#include #include "../snp_attest.h" @@ -13,19 +13,19 @@ * Identifiers for all possible TEE architectures. */ enum tee { - TEE_SEV, - TEE_SGX, - TEE_SNP, - TEE_TDX, + TEE_SEV, + TEE_SGX, + TEE_SNP, + TEE_TDX, }; /* * The type of KBS operation to be performed. */ enum curl_post_type { - KBS_CURL_REQ, - KBS_CURL_ATTEST, - KBS_CURL_GET_KEY, + KBS_CURL_REQ, + KBS_CURL_ATTEST, + KBS_CURL_GET_KEY, }; // kbs_util.c diff --git a/init/tee/kbs/kbs_crypto.c b/init/tee/kbs/kbs_crypto.c index e925470..516fa2c 100644 --- a/init/tee/kbs/kbs_crypto.c +++ b/init/tee/kbs/kbs_crypto.c @@ -3,195 +3,192 @@ #include #include -#include -#include -#include -#include #include #include +#include +#include #include +#include #include "kbs.h" /* * Create an OpenSSL TEE public/private key pair. */ -int -kbs_tee_pubkey_create(EVP_PKEY **pkey, BIGNUM **n, BIGNUM **e) +int kbs_tee_pubkey_create(EVP_PKEY **pkey, BIGNUM **n, BIGNUM **e) { - int ret, rc; - EVP_PKEY_CTX *ctx; + int ret, rc; + EVP_PKEY_CTX *ctx; - rc = -1; - ctx = NULL; + rc = -1; + ctx = NULL; - /* - * The public/private key pair will use an RSA algorithm. Generate the - * keys' context. - */ - ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); - if (ctx == NULL) { - printf("ERROR: creating TEE public key context\n"); + /* + * The public/private key pair will use an RSA algorithm. Generate the + * keys' context. + */ + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + if (ctx == NULL) { + printf("ERROR: creating TEE public key context\n"); - return rc; - } + return rc; + } - ret = EVP_PKEY_keygen_init(ctx); - if (ret < 1) { - printf("ERROR: initializing TEE public key generation\n"); + ret = EVP_PKEY_keygen_init(ctx); + if (ret < 1) { + printf("ERROR: initializing TEE public key generation\n"); - goto ctx_free; - } + goto ctx_free; + } - /* - * Set key generation bits to 2048 and generate the key pair. - */ - ret = EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048); - if (ret < 1) { - printf("ERROR: setting RSA keygen bits\n"); + /* + * Set key generation bits to 2048 and generate the key pair. + */ + ret = EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048); + if (ret < 1) { + printf("ERROR: setting RSA keygen bits\n"); - goto ctx_free; - } + goto ctx_free; + } - *pkey = NULL; - ret = EVP_PKEY_keygen(ctx, pkey); - if (ret < 1) { - printf("ERROR: generating RSA key\n"); + *pkey = NULL; + ret = EVP_PKEY_keygen(ctx, pkey); + if (ret < 1) { + printf("ERROR: generating RSA key\n"); - goto ctx_free; - } + goto ctx_free; + } - /* - * Get the modulus and exponents of the key pair. - */ - ret = EVP_PKEY_get_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_N, n); - if (ret < 0 || n == NULL) { - printf("ERROR: getting public key modulus\n"); + /* + * Get the modulus and exponents of the key pair. + */ + ret = EVP_PKEY_get_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_N, n); + if (ret < 0 || n == NULL) { + printf("ERROR: getting public key modulus\n"); - goto ctx_free; - } + goto ctx_free; + } - ret = EVP_PKEY_get_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_E, e); - if (ret < 0 || e == NULL) { - printf("ERROR: getting public key exponent\n"); + ret = EVP_PKEY_get_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_E, e); + if (ret < 0 || e == NULL) { + printf("ERROR: getting public key exponent\n"); - goto ctx_free; - } + goto ctx_free; + } - rc = 0; + rc = 0; ctx_free: - EVP_PKEY_CTX_free(ctx); + EVP_PKEY_CTX_free(ctx); - return rc; + return rc; } /* * Create a SHA512 hash of the nonce and TEE public key to send to the * attestation server. */ -int -kbs_nonce_pubkey_hash(char *nonce, EVP_PKEY *pkey, unsigned char **hash, - unsigned int *size) +int kbs_nonce_pubkey_hash(char *nonce, EVP_PKEY *pkey, unsigned char **hash, + unsigned int *size) { - int rc; - EVP_MD_CTX *md_ctx; - BIGNUM *n, *e; - char n_b64[512], e_b64[512]; + int rc; + EVP_MD_CTX *md_ctx; + BIGNUM *n, *e; + char n_b64[512], e_b64[512]; - rc = -1; + rc = -1; - /* - * Initialize an MD context and initialize the SHA512 digest. - */ - md_ctx = EVP_MD_CTX_new(); - if (md_ctx == NULL) { - printf("ERROR: generating SHA512 context\n"); + /* + * Initialize an MD context and initialize the SHA512 digest. + */ + md_ctx = EVP_MD_CTX_new(); + if (md_ctx == NULL) { + printf("ERROR: generating SHA512 context\n"); - return rc; - } - - if (EVP_DigestInit_ex(md_ctx, EVP_sha512(), NULL) < 1) { - printf("ERROR: initializing SHA512 hash\n"); + return rc; + } - goto md_ctx_free; - } + if (EVP_DigestInit_ex(md_ctx, EVP_sha512(), NULL) < 1) { + printf("ERROR: initializing SHA512 hash\n"); - /* - * Update the digest with the data from the nonce. - */ - if (EVP_DigestUpdate(md_ctx, (void *) nonce, strlen(nonce)) < 1) { - printf("ERROR: updating SHA512 digest with nonce\n"); + goto md_ctx_free; + } - goto md_ctx_free; - } + /* + * Update the digest with the data from the nonce. + */ + if (EVP_DigestUpdate(md_ctx, (void *)nonce, strlen(nonce)) < 1) { + printf("ERROR: updating SHA512 digest with nonce\n"); - /* - * Update the digest with the data from the TEE public key. - * - * To do this, we will write the base64 encoding of the TEE public - * key's modulus and exponent. - */ - n = e = NULL; - if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &n) == 0) { - printf("ERROR: unable to retrieve public key modulus\n"); + goto md_ctx_free; + } + + /* + * Update the digest with the data from the TEE public key. + * + * To do this, we will write the base64 encoding of the TEE public + * key's modulus and exponent. + */ + n = e = NULL; + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &n) == 0) { + printf("ERROR: unable to retrieve public key modulus\n"); - goto md_ctx_free; - } + goto md_ctx_free; + } - if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) == 0) { - printf("ERROR: unable to retrieve public key exponent\n"); + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) == 0) { + printf("ERROR: unable to retrieve public key exponent\n"); - goto md_ctx_free; - } + goto md_ctx_free; + } - /* - * base64-encode the modulus and exponents, and hash the base64 strings - * into the SHA512 digest. - */ - BN_b64(n, n_b64); - BN_b64(e, e_b64); + /* + * base64-encode the modulus and exponents, and hash the base64 strings + * into the SHA512 digest. + */ + BN_b64(n, n_b64); + BN_b64(e, e_b64); - if (EVP_DigestUpdate(md_ctx, (void *) n_b64, strlen(n_b64)) < 1) { - printf("ERROR: updating SHA512 digest with public key N\n"); + if (EVP_DigestUpdate(md_ctx, (void *)n_b64, strlen(n_b64)) < 1) { + printf("ERROR: updating SHA512 digest with public key N\n"); - goto md_ctx_free; - } + goto md_ctx_free; + } - if (EVP_DigestUpdate(md_ctx, (void *) e_b64, strlen(e_b64)) < 1) { - printf("ERROR: updating SHA512 digest with public key E\n"); + if (EVP_DigestUpdate(md_ctx, (void *)e_b64, strlen(e_b64)) < 1) { + printf("ERROR: updating SHA512 digest with public key E\n"); - goto md_ctx_free; - } + goto md_ctx_free; + } - /* - * Allocate the memory to hold the SHA512 hash, and write the SHA512 - * hash to the "hash" byte array. - */ - *hash = (unsigned char *) OPENSSL_malloc(EVP_MD_size(EVP_sha512())); - if (*hash == NULL) { - printf("ERROR: allocating memory for SHA512 hash\n"); + /* + * Allocate the memory to hold the SHA512 hash, and write the SHA512 + * hash to the "hash" byte array. + */ + *hash = (unsigned char *)OPENSSL_malloc(EVP_MD_size(EVP_sha512())); + if (*hash == NULL) { + printf("ERROR: allocating memory for SHA512 hash\n"); - goto md_ctx_free; - } + goto md_ctx_free; + } - if (EVP_DigestFinal_ex(md_ctx, *hash, size) < 1) { - printf("ERROR: finalizing the SHA512 hash\n"); + if (EVP_DigestFinal_ex(md_ctx, *hash, size) < 1) { + printf("ERROR: finalizing the SHA512 hash\n"); - goto hash_free; - } + goto hash_free; + } - rc = 0; + rc = 0; - goto md_ctx_free; + goto md_ctx_free; hash_free: - OPENSSL_free((void *) *hash); + OPENSSL_free((void *)*hash); md_ctx_free: - EVP_MD_CTX_free(md_ctx); + EVP_MD_CTX_free(md_ctx); - return rc; + return rc; } /* @@ -199,140 +196,137 @@ md_ctx_free: * encoded string of text. Store the plaintext of the encrypted text into a * buffer and point "plain_ptr" to said buffer. */ -int -rsa_pkey_decrypt(EVP_PKEY *pkey, char *enc, char **plain_ptr) +int rsa_pkey_decrypt(EVP_PKEY *pkey, char *enc, char **plain_ptr) { - int rc; - EVP_PKEY_CTX *ctx; - char enc_bin[4096], *plain; - size_t enc_bin_len, secret_plain_len = 4096; - - rc = -1; - - /* - * Decode the hex-encoded string to its byte format. - */ - if (OPENSSL_hexstr2buf_ex((unsigned char *) enc_bin, 4096, &enc_bin_len, - enc, '\0') != 1) { - printf("Error converting hex to buf\n"); - - return rc; - } - - /* - * Initialize the public key decryption context. - */ - ctx = EVP_PKEY_CTX_new(pkey, NULL); - if (ctx == NULL) { - printf("ERROR: creation of pkey context for decryption\n"); - - return rc; - } - - if (EVP_PKEY_decrypt_init(ctx) <= 0) { - printf("ERROR: creation of decryption context for pkey\n"); - - goto ctx_free; - } - - if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { - printf("Error setting RSA padding\n"); - - goto ctx_free; - } - - /* - * To first get the length that the plain secret buffer should be, call - * EVP_PKEY_decrypt() with a NULL output buffer argument. Then, - * "secret_plain_len" will contain the proper amount of bytes to - * allocate for the output buffer. - */ - rc = EVP_PKEY_decrypt(ctx, NULL, - &secret_plain_len, (unsigned char *) enc_bin, - enc_bin_len); - if (rc <= 0) { - printf("ERROR: finding plaintext passphrase length: %d\n", rc); - - goto ctx_free; - } - - /* - * Allocate the output buffer using "secret_plain_len". - */ - plain = OPENSSL_malloc(secret_plain_len); - if (plain == NULL) - goto ctx_free; - - /* - * Decrypt the string using the OpenSSL RSA public key. - */ - rc = EVP_PKEY_decrypt(ctx, (unsigned char *) plain, &secret_plain_len, - (unsigned char *) enc_bin, enc_bin_len); - if (rc <= 0) { - printf("ERROR: decrypting RSA-encrypted passphrase: %d\n", rc); - OPENSSL_free(plain); - - goto ctx_free; - } - plain[secret_plain_len] = '\0'; - - /* - * Set the "plain_ptr" arg to the plaintext passphrase". - */ - *plain_ptr = plain; - - rc = 0; + int rc; + EVP_PKEY_CTX *ctx; + char enc_bin[4096], *plain; + size_t enc_bin_len, secret_plain_len = 4096; -ctx_free: - EVP_PKEY_CTX_free(ctx); + rc = -1; + + /* + * Decode the hex-encoded string to its byte format. + */ + if (OPENSSL_hexstr2buf_ex((unsigned char *)enc_bin, 4096, &enc_bin_len, enc, + '\0') != 1) { + printf("Error converting hex to buf\n"); + + return rc; + } + + /* + * Initialize the public key decryption context. + */ + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (ctx == NULL) { + printf("ERROR: creation of pkey context for decryption\n"); return rc; + } + + if (EVP_PKEY_decrypt_init(ctx) <= 0) { + printf("ERROR: creation of decryption context for pkey\n"); + + goto ctx_free; + } + + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { + printf("Error setting RSA padding\n"); + + goto ctx_free; + } + + /* + * To first get the length that the plain secret buffer should be, call + * EVP_PKEY_decrypt() with a NULL output buffer argument. Then, + * "secret_plain_len" will contain the proper amount of bytes to + * allocate for the output buffer. + */ + rc = EVP_PKEY_decrypt(ctx, NULL, &secret_plain_len, + (unsigned char *)enc_bin, enc_bin_len); + if (rc <= 0) { + printf("ERROR: finding plaintext passphrase length: %d\n", rc); + + goto ctx_free; + } + + /* + * Allocate the output buffer using "secret_plain_len". + */ + plain = OPENSSL_malloc(secret_plain_len); + if (plain == NULL) + goto ctx_free; + + /* + * Decrypt the string using the OpenSSL RSA public key. + */ + rc = EVP_PKEY_decrypt(ctx, (unsigned char *)plain, &secret_plain_len, + (unsigned char *)enc_bin, enc_bin_len); + if (rc <= 0) { + printf("ERROR: decrypting RSA-encrypted passphrase: %d\n", rc); + OPENSSL_free(plain); + + goto ctx_free; + } + plain[secret_plain_len] = '\0'; + + /* + * Set the "plain_ptr" arg to the plaintext passphrase". + */ + *plain_ptr = plain; + + rc = 0; + +ctx_free: + EVP_PKEY_CTX_free(ctx); + + return rc; } /* * base64-encode the contents of an OpenSSL BIGNUM. */ -void -BN_b64(BIGNUM *bn, char *str) +void BN_b64(BIGNUM *bn, char *str) { - BIO *bio; - BIO *b64; - char *bn_bin; - char *bn_b64; - int bn_binlen; - int bn_b64len; - - /* - * Encode the BIGNUM contents to binary. - */ - bn_binlen = BN_num_bytes(bn); - bn_bin = malloc(bn_binlen); - BN_bn2bin(bn, (unsigned char *) bn_bin); - - /* - * Write the binary-encoded string to to a base64-configured OpenSSL - * BIO. - */ - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - bio = BIO_new(BIO_s_mem()); - BIO_push(b64, bio); - BIO_write(b64, bn_bin, bn_binlen); - BIO_flush(b64); - - /* - * Retrieve the base64-encoded contents of the BIO, null-terminate the - * string, and copy those contents to the output string. - */ - bn_b64len = BIO_get_mem_data(b64, &bn_b64); - bn_b64[bn_b64len] = '\0'; - - strcpy(str, bn_b64); - - /* - * Cleanup OpenSSL data structures. - */ - BIO_free(b64); - BIO_free(bio); - free(bn_bin); + BIO *bio; + BIO *b64; + char *bn_bin; + char *bn_b64; + int bn_binlen; + int bn_b64len; + + /* + * Encode the BIGNUM contents to binary. + */ + bn_binlen = BN_num_bytes(bn); + bn_bin = malloc(bn_binlen); + BN_bn2bin(bn, (unsigned char *)bn_bin); + + /* + * Write the binary-encoded string to to a base64-configured OpenSSL + * BIO. + */ + b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + bio = BIO_new(BIO_s_mem()); + BIO_push(b64, bio); + BIO_write(b64, bn_bin, bn_binlen); + BIO_flush(b64); + + /* + * Retrieve the base64-encoded contents of the BIO, null-terminate the + * string, and copy those contents to the output string. + */ + bn_b64len = BIO_get_mem_data(b64, &bn_b64); + bn_b64[bn_b64len] = '\0'; + + strcpy(str, bn_b64); + + /* + * Cleanup OpenSSL data structures. + */ + BIO_free(b64); + BIO_free(bio); + free(bn_bin); } diff --git a/init/tee/kbs/kbs_curl.c b/init/tee/kbs/kbs_curl.c index 2d7b198..eb639db 100644 --- a/init/tee/kbs/kbs_curl.c +++ b/init/tee/kbs/kbs_curl.c @@ -1,13 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 +#include #include #include -#include #include "kbs.h" -#define KBS_CURL_ERR(x) printf("%s: %s\n", __func__, x); \ - return -1; \ +#define KBS_CURL_ERR(x) \ + printf("%s: %s\n", __func__, x); \ + return -1; static CURLcode kbs_curl_set_headers(CURL *, char *); size_t cwrite(void *, size_t, size_t, void *); @@ -16,181 +17,178 @@ size_t cwrite(void *, size_t, size_t, void *); * Complete a cURL POST request. POST the "in" string and retrieve the contents * of the POST request "out" string. * - * Depending on the type of request, some extra headers may need to be set. + * Depending on the type of request, some extra headers may need to be set. * For example, on a KBS REQUEST, no session ID has been retrieved from the * attestation server so far. Yet, during a KBS_ATTEST request, a session ID * has been given from the server and must be added to the headers. */ -int -kbs_curl_post(CURL *curl, char *url, char *in, char *out, int type) +int kbs_curl_post(CURL *curl, char *url, char *in, char *out, int type) { - CURLcode code; - struct curl_slist *cks; - char full_url[256], *session_id_label, session_id[256]; - - /* - * Neither the input or output strings should be invalid/NULL. - */ - if (!in) { - KBS_CURL_ERR("Input argument NULL"); - } + CURLcode code; + struct curl_slist *cks; + char full_url[256], *session_id_label, session_id[256]; - if (!out) { - KBS_CURL_ERR("Output argument NULL"); - } + /* + * Neither the input or output strings should be invalid/NULL. + */ + if (!in) { + KBS_CURL_ERR("Input argument NULL"); + } - if (curl_easy_setopt(curl, CURLOPT_POST, 1L) != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_POST"); - } + if (!out) { + KBS_CURL_ERR("Output argument NULL"); + } - if (curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cwrite) != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_WRITEFUNCTION"); - } + if (curl_easy_setopt(curl, CURLOPT_POST, 1L) != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_POST"); + } - /* - * If the operation being completed is a KBS REQUEST, then this is the - * initial request to the attestation server, and there is no session - * ID to make note of. Otherwise, the session ID has been established - * and must be parsed from the cURL cookies data. - */ - cks = NULL; - if (type == KBS_CURL_REQ) { - sprintf(full_url, "%s/kbs/v0/auth", url); - - if (curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "") != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_COOKIEFILE"); - } - - if (kbs_curl_set_headers(curl, NULL) != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_HTTPHEADER"); - } - } else { - sprintf(full_url, "%s/kbs/v0/attest", url); - - if (curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cks) - != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_COOKIELIST"); - } - - session_id_label = NULL; - while (cks) { - session_id_label = find_cookie(cks->data, "session_id"); - - if (session_id_label) - break; - cks = cks->next; - } - - if (session_id_label == NULL) { - KBS_CURL_ERR("No session_id cookie found"); - } - - if (read_cookie_val(session_id_label, session_id) < 0) { - KBS_CURL_ERR("No session_id value for cookie"); - } - - if (kbs_curl_set_headers(curl, (char *) session_id) != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_HTTPHEADER"); - } - } + if (curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cwrite) != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_WRITEFUNCTION"); + } - if (curl_easy_setopt(curl, CURLOPT_URL, full_url) != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_URL"); - } + /* + * If the operation being completed is a KBS REQUEST, then this is the + * initial request to the attestation server, and there is no session + * ID to make note of. Otherwise, the session ID has been established + * and must be parsed from the cURL cookies data. + */ + cks = NULL; + if (type == KBS_CURL_REQ) { + sprintf(full_url, "%s/kbs/v0/auth", url); - /* - * This is a cURL POST request that will write data to the "out" - * argument. "out" is expected to have been allocated beforehand and - * able to hold the full response from the attestation server. - */ - if (curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) strlen(in)) - != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_POSTFIELDSIZE"); + if (curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "") != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_COOKIEFILE"); } - if (curl_easy_setopt(curl, CURLOPT_POSTFIELDS, in) != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_POSTFIELDS"); + if (kbs_curl_set_headers(curl, NULL) != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_HTTPHEADER"); } + } else { + sprintf(full_url, "%s/kbs/v0/attest", url); - if (curl_easy_setopt(curl, CURLOPT_WRITEDATA, out) != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_WRITEDATA"); + if (curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cks) != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_COOKIELIST"); } - code = curl_easy_perform(curl); - if (code != CURLE_OK && code != CURLE_WRITE_ERROR) { - KBS_CURL_ERR("CURL_EASY_PERFORM"); - } - - return 0; -} - -/* - * A cURL GET request. No input is given, and we are simply retrieving data - * from the KBS attestation server. - */ -int -kbs_curl_get(CURL *curl, char *url, char *wid, char *out, int type) -{ - CURLcode code; - char full_url[100], *session_id_label, session_id[100]; - struct curl_slist *cookies; + session_id_label = NULL; + while (cks) { + session_id_label = find_cookie(cks->data, "session_id"); - if (type != KBS_CURL_GET_KEY) { - KBS_CURL_ERR("Invalid KBS operation"); - } - - code = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies); - if (code != CURLE_OK) { - KBS_CURL_ERR("Cannot retrieve cURL cookies"); - } - - /* - * This API is used by kbs_get_key(), therefore we are expected to have - * a valid session ID by this point. Parse the cURL cookies data to find - * this session ID. - */ - while (cookies != NULL) { - session_id_label = find_cookie(cookies->data, "session_id"); - if (session_id_label) - break; - - cookies = cookies->next; + if (session_id_label) + break; + cks = cks->next; } if (session_id_label == NULL) { - KBS_CURL_ERR("Couldn't find cookie labeled\n"); + KBS_CURL_ERR("No session_id cookie found"); } - /* - * Read the session ID and include it in the cURL headers. - */ if (read_cookie_val(session_id_label, session_id) < 0) { - KBS_CURL_ERR("Couldn't read cookie value\n"); + KBS_CURL_ERR("No session_id value for cookie"); } - if (kbs_curl_set_headers(curl, (char *) session_id) != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_HTTPHEADER"); + if (kbs_curl_set_headers(curl, (char *)session_id) != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_HTTPHEADER"); } + } - /* - * The location of the KBS key is located at - * $ATTESTATION_URL/kbs/v0/key/$WORKLOAD_ID. - */ - sprintf(full_url, "%s/kbs/v0/key/%s", url, wid); + if (curl_easy_setopt(curl, CURLOPT_URL, full_url) != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_URL"); + } - if (curl_easy_setopt(curl, CURLOPT_URL, full_url) != CURLE_OK) { - KBS_CURL_ERR("CURLOPT_URL"); - } + /* + * This is a cURL POST request that will write data to the "out" + * argument. "out" is expected to have been allocated beforehand and + * able to hold the full response from the attestation server. + */ + if (curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(in)) != + CURLE_OK) { + KBS_CURL_ERR("CURLOPT_POSTFIELDSIZE"); + } - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cwrite); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, out); + if (curl_easy_setopt(curl, CURLOPT_POSTFIELDS, in) != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_POSTFIELDS"); + } - code = curl_easy_perform(curl); - if (code != CURLE_OK && code != CURLE_WRITE_ERROR) { - KBS_CURL_ERR("CURL_EASY_PERFORM"); - } + if (curl_easy_setopt(curl, CURLOPT_WRITEDATA, out) != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_WRITEDATA"); + } + + code = curl_easy_perform(curl); + if (code != CURLE_OK && code != CURLE_WRITE_ERROR) { + KBS_CURL_ERR("CURL_EASY_PERFORM"); + } + + return 0; +} - return 0; +/* + * A cURL GET request. No input is given, and we are simply retrieving data + * from the KBS attestation server. + */ +int kbs_curl_get(CURL *curl, char *url, char *wid, char *out, int type) +{ + CURLcode code; + char full_url[100], *session_id_label, session_id[100]; + struct curl_slist *cookies; + + if (type != KBS_CURL_GET_KEY) { + KBS_CURL_ERR("Invalid KBS operation"); + } + + code = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies); + if (code != CURLE_OK) { + KBS_CURL_ERR("Cannot retrieve cURL cookies"); + } + + /* + * This API is used by kbs_get_key(), therefore we are expected to have + * a valid session ID by this point. Parse the cURL cookies data to find + * this session ID. + */ + while (cookies != NULL) { + session_id_label = find_cookie(cookies->data, "session_id"); + if (session_id_label) + break; + + cookies = cookies->next; + } + + if (session_id_label == NULL) { + KBS_CURL_ERR("Couldn't find cookie labeled\n"); + } + + /* + * Read the session ID and include it in the cURL headers. + */ + if (read_cookie_val(session_id_label, session_id) < 0) { + KBS_CURL_ERR("Couldn't read cookie value\n"); + } + + if (kbs_curl_set_headers(curl, (char *)session_id) != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_HTTPHEADER"); + } + + /* + * The location of the KBS key is located at + * $ATTESTATION_URL/kbs/v0/key/$WORKLOAD_ID. + */ + sprintf(full_url, "%s/kbs/v0/key/%s", url, wid); + + if (curl_easy_setopt(curl, CURLOPT_URL, full_url) != CURLE_OK) { + KBS_CURL_ERR("CURLOPT_URL"); + } + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cwrite); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, out); + + code = curl_easy_perform(curl); + if (code != CURLE_OK && code != CURLE_WRITE_ERROR) { + KBS_CURL_ERR("CURL_EASY_PERFORM"); + } + + return 0; } /* @@ -198,39 +196,37 @@ kbs_curl_get(CURL *curl, char *url, char *wid, char *out, int type) * the session ID has been retrieved from attestation server before, and that * session ID should be included in the headers. */ -static CURLcode -kbs_curl_set_headers(CURL *curl, char *session) +static CURLcode kbs_curl_set_headers(CURL *curl, char *session) { - struct curl_slist *slist; - char session_buf[512]; - - slist = NULL; - slist = curl_slist_append(slist, "Accept: application/json"); - slist = curl_slist_append(slist, - "Content-Type: application/json; charset=utf-8"); - - /* - * Add the session ID cookie if the session ID exists. - */ - if (session) { - sprintf(session_buf, "Cookie: session_id=%s", session); - curl_slist_append(slist, session_buf); - } - - /* - * Set the headers. - */ - return curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); + struct curl_slist *slist; + char session_buf[512]; + + slist = NULL; + slist = curl_slist_append(slist, "Accept: application/json"); + slist = curl_slist_append(slist, + "Content-Type: application/json; charset=utf-8"); + + /* + * Add the session ID cookie if the session ID exists. + */ + if (session) { + sprintf(session_buf, "Cookie: session_id=%s", session); + curl_slist_append(slist, session_buf); + } + + /* + * Set the headers. + */ + return curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); } /* * Simple strcpy() for attestation server responses. Required by a cURL * operation that writes data. */ -size_t -cwrite(void *data, size_t size, size_t nmemb, void *userp) +size_t cwrite(void *data, size_t size, size_t nmemb, void *userp) { - strcpy((char *) userp, (char *) data); + strcpy((char *)userp, (char *)data); - return size; + return size; } diff --git a/init/tee/kbs/kbs_types.c b/init/tee/kbs/kbs_types.c index d7ec103..b9f512d 100644 --- a/init/tee/kbs/kbs_types.c +++ b/init/tee/kbs/kbs_types.c @@ -1,47 +1,46 @@ // SPDX-License-Identifier: Apache-2.0 -#include #include +#include #include -#include -#include #include +#include #include +#include #include "kbs.h" #include "../snp_attest.h" static void kbs_attestation_marshal(struct snp_report *, char *, BIGNUM *, - BIGNUM *, char *); + BIGNUM *, char *); static void kbs_attestation_marshal_tee_pubkey(char *, BIGNUM *, BIGNUM *); /* * Given a TEE architecture and workload ID, write the JSON string of the * KBS REQUEST. */ -int -kbs_request_marshal(char *json_request, int tee, char *workload_id) +int kbs_request_marshal(char *json_request, int tee, char *workload_id) { - char *teestr; - - /* - * Retrieve the KBS string equivalent of the TEE enum value. - */ - teestr = tee_str(tee); - if (teestr == NULL) - return -1; - - /* - * Build the KBS REQUEST JSON string. - */ - sprintf(json_request, - "{\"extra-params\":\"{\\\"workload_id\\\":\\\"%s\\\"}\",\"tee\":\"%s\",\"version\":\"0.0.0\"}", - workload_id, - teestr); - - return 0; + char *teestr; + + /* + * Retrieve the KBS string equivalent of the TEE enum value. + */ + teestr = tee_str(tee); + if (teestr == NULL) + return -1; + + /* + * Build the KBS REQUEST JSON string. + */ + sprintf(json_request, + "{\"extra-params\":\"{\\\"workload_id\\\":\\\"%s\\\"}\",\"tee\":\"%" + "s\",\"version\":\"0.0.0\"}", + workload_id, teestr); + + return 0; } /* @@ -50,202 +49,199 @@ kbs_request_marshal(char *json_request, int tee, char *workload_id) * "json_request" is the JSON string of the KBS REQUEST. * "nonce" is the output argument to be retrieved from the attestation server. */ -int -kbs_challenge(CURL *curl, char *url, char *json_request, char *nonce) +int kbs_challenge(CURL *curl, char *url, char *json_request, char *nonce) { - int ret, rc; - char *nonce_json; + int ret, rc; + char *nonce_json; - rc = -1; + rc = -1; - nonce_json = (char *) malloc(0x2000); - if (nonce_json == NULL) { - printf("ERROR: unable to allocate JSON nonce buffer\n"); + nonce_json = (char *)malloc(0x2000); + if (nonce_json == NULL) { + printf("ERROR: unable to allocate JSON nonce buffer\n"); - return rc; - } + return rc; + } - ret = kbs_curl_post(curl, url, (void *) json_request, (void *) nonce_json, KBS_CURL_REQ); - if (ret < 0) { - printf("ERROR: could not complete KBS challenge\n"); + ret = kbs_curl_post(curl, url, (void *)json_request, (void *)nonce_json, + KBS_CURL_REQ); + if (ret < 0) { + printf("ERROR: could not complete KBS challenge\n"); - goto out; - } + goto out; + } - /* - * Parse the JSON response from the KBS server to retrieve the nonce. - */ - if (json_parse_str(nonce, "nonce", nonce_json) < 0) { - printf("ERROR: unable to parse nonce from server response\n"); + /* + * Parse the JSON response from the KBS server to retrieve the nonce. + */ + if (json_parse_str(nonce, "nonce", nonce_json) < 0) { + printf("ERROR: unable to parse nonce from server response\n"); - goto out; - } + goto out; + } - rc = 0; + rc = 0; out: - free(nonce_json); + free(nonce_json); - return rc; + return rc; } /* * Send all required materials (attestation report, certificate chain, etc..) * to the attestation server for attestation. */ -int -kbs_attest(CURL *curl, char *url, struct snp_report *report, BIGNUM *mod, - BIGNUM *exp, char *gen) +int kbs_attest(CURL *curl, char *url, struct snp_report *report, BIGNUM *mod, + BIGNUM *exp, char *gen) { - int rc; - char *json, errmsg[200]; + int rc; + char *json, errmsg[200]; + + rc = -1; + json = (char *)malloc(0x1000); + if (json == NULL) { + printf("ERROR: unable to allocate JSON buffer\n"); + + return rc; + } + + /* + * Marshal the kbs_types Attestation JSON struct with the given + * attestation report and certificate chain. + */ + kbs_attestation_marshal(report, json, mod, exp, gen); + + /* + * Ensure the error messaging string is empty, because we will + * eventually read this string as indicator of a cURL attestation + * server error. + */ + strcpy(errmsg, ""); + + if (kbs_curl_post(curl, url, json, errmsg, KBS_CURL_ATTEST) < 0) { + printf("ERROR: could not complete KBS attestation\n"); rc = -1; - json = (char *) malloc(0x1000); - if (json == NULL) { - printf("ERROR: unable to allocate JSON buffer\n"); - - return rc; - } - - /* - * Marshal the kbs_types Attestation JSON struct with the given - * attestation report and certificate chain. - */ - kbs_attestation_marshal(report, json, mod, exp, gen); - - /* - * Ensure the error messaging string is empty, because we will - * eventually read this string as indicator of a cURL attestation - * server error. - */ - strcpy(errmsg, ""); - - if (kbs_curl_post(curl, url, json, errmsg, KBS_CURL_ATTEST) < 0) { - printf("ERROR: could not complete KBS attestation\n"); - - rc = -1; - goto out; - } - - /* - * If there is no error message, it can be assumed that the attestation - * was completed successfully. - */ - if (strcmp(errmsg, "") != 0) { - rc = -1; - printf("ATTESTATION ERROR: %s\n", errmsg); - - goto out; - } - - rc = 0; + goto out; + } + + /* + * If there is no error message, it can be assumed that the attestation + * was completed successfully. + */ + if (strcmp(errmsg, "") != 0) { + rc = -1; + printf("ATTESTATION ERROR: %s\n", errmsg); + + goto out; + } + + rc = 0; out: - free((void *) json); + free((void *)json); - return rc; + return rc; } /* * Retrieve the secret from the KBS attestation server. */ -int -kbs_get_key(CURL *curl, char *url, char *wid, EVP_PKEY *pkey, char *pass) +int kbs_get_key(CURL *curl, char *url, char *wid, EVP_PKEY *pkey, char *pass) { - int end_idx; - char json[4096]; - char encrypted[4096], *plain; + int end_idx; + char json[4096]; + char encrypted[4096], *plain; - /* - * The key is represented as a JSON byte list, copy this JSON list - * string to "json". - */ - if (kbs_curl_get(curl, url, wid, json, KBS_CURL_GET_KEY) < 0) { - printf("ERROR: could not complete KBS passphrase retrieval\n"); + /* + * The key is represented as a JSON byte list, copy this JSON list + * string to "json". + */ + if (kbs_curl_get(curl, url, wid, json, KBS_CURL_GET_KEY) < 0) { + printf("ERROR: could not complete KBS passphrase retrieval\n"); - return -1; - } + return -1; + } - end_idx = strlen(json) - 2; + end_idx = strlen(json) - 2; - memcpy(encrypted, json + 1, end_idx); - encrypted[end_idx] = '\0'; + memcpy(encrypted, json + 1, end_idx); + encrypted[end_idx] = '\0'; - if (rsa_pkey_decrypt(pkey, encrypted, &plain) < 0) { - printf("ERROR: could not decrypt passphrase from KBS server\n"); + if (rsa_pkey_decrypt(pkey, encrypted, &plain) < 0) { + printf("ERROR: could not decrypt passphrase from KBS server\n"); - return -1; - } + return -1; + } - strcpy(pass, plain); + strcpy(pass, plain); - OPENSSL_free(plain); + OPENSSL_free(plain); - return 0; + return 0; } /* * Marshal a JSON string of the kbs_types Attestation struct from the given * attestation report and certificate data. */ -static void -kbs_attestation_marshal(struct snp_report *report, char *json, BIGNUM *mod, - BIGNUM *exp, char *gen) +static void kbs_attestation_marshal(struct snp_report *report, char *json, + BIGNUM *mod, BIGNUM *exp, char *gen) { - char buf[4096], *report_hexstr; - size_t report_hexstr_len; + char buf[4096], *report_hexstr; + size_t report_hexstr_len; - report_hexstr = (char *) malloc(0x1000); - if (report_hexstr == NULL) - return; + report_hexstr = (char *)malloc(0x1000); + if (report_hexstr == NULL) + return; - sprintf(buf, "{"); - strcpy(json, buf); + sprintf(buf, "{"); + strcpy(json, buf); - kbs_attestation_marshal_tee_pubkey(json, mod, exp); + kbs_attestation_marshal_tee_pubkey(json, mod, exp); - sprintf(buf, "\"tee-evidence\":\"{"); - strcat(json, buf); + sprintf(buf, "\"tee-evidence\":\"{"); + strcat(json, buf); - sprintf(buf, "\\\"gen\\\":\\\"%s\\\",", gen); - strcat(json, buf); + sprintf(buf, "\\\"gen\\\":\\\"%s\\\",", gen); + strcat(json, buf); - OPENSSL_buf2hexstr_ex(report_hexstr, 0x1000, &report_hexstr_len, - (unsigned char *) report, sizeof(*report), '\0'); - report_hexstr[report_hexstr_len] = '\0'; - sprintf(buf, "\\\"report\\\":\\\"%s\\\",", report_hexstr); - strcat(json, buf); + OPENSSL_buf2hexstr_ex(report_hexstr, 0x1000, &report_hexstr_len, + (unsigned char *)report, sizeof(*report), '\0'); + report_hexstr[report_hexstr_len] = '\0'; + sprintf(buf, "\\\"report\\\":\\\"%s\\\",", report_hexstr); + strcat(json, buf); - strcat(json, "\\\"cert_chain\\\":\\\"[]\\\"}"); + strcat(json, "\\\"cert_chain\\\":\\\"[]\\\"}"); - strcat(json, "\"}"); + strcat(json, "\"}"); } /* * Marshal a JSON string of the KBS TEE public key. */ -static void -kbs_attestation_marshal_tee_pubkey(char *json, BIGNUM *mod, BIGNUM *exp) +static void kbs_attestation_marshal_tee_pubkey(char *json, BIGNUM *mod, + BIGNUM *exp) { - char mod_b64[512], exp_b64[512]; - char buf[1024]; + char mod_b64[512], exp_b64[512]; + char buf[1024]; - if (mod == NULL || exp == NULL) - return; + if (mod == NULL || exp == NULL) + return; - BN_b64(mod, mod_b64); - BN_b64(exp, exp_b64); + BN_b64(mod, mod_b64); + BN_b64(exp, exp_b64); - sprintf(buf, "\"tee-pubkey\":{"); - strcat(json, buf); + sprintf(buf, "\"tee-pubkey\":{"); + strcat(json, buf); - sprintf(buf, "\"alg\":\"RSA\","); - strcat(json, buf); + sprintf(buf, "\"alg\":\"RSA\","); + strcat(json, buf); - sprintf(buf, "\"k-mod\":\"%s\",", mod_b64); - strcat(json, buf); + sprintf(buf, "\"k-mod\":\"%s\",", mod_b64); + strcat(json, buf); - sprintf(buf, "\"k-exp\":\"%s\"},", exp_b64); - strcat(json, buf); + sprintf(buf, "\"k-exp\":\"%s\"},", exp_b64); + strcat(json, buf); } diff --git a/init/tee/kbs/kbs_util.c b/init/tee/kbs/kbs_util.c index 692ad94..6c0b7c8 100644 --- a/init/tee/kbs/kbs_util.c +++ b/init/tee/kbs/kbs_util.c @@ -3,8 +3,8 @@ #include #include -#include "kbs.h" #include "../../jsmn.h" +#include "kbs.h" #define MAX_TOKENS 16384 @@ -13,26 +13,25 @@ static int label_find(char *, char *); /* * Return the string identifier of the inputted TEE architecture. */ -char * -tee_str(int tee) +char *tee_str(int tee) { - switch (tee) { - case TEE_SEV: - return "sev"; - case TEE_SGX: - return "sgx"; - case TEE_SNP: - return "snp"; - case TEE_TDX: - return "tdx"; - - /* - * No other TEE architecture is supported. - */ - default: - printf("ERROR: tee_str(): Invalid input\n"); - return NULL; - } + switch (tee) { + case TEE_SEV: + return "sev"; + case TEE_SGX: + return "sgx"; + case TEE_SNP: + return "snp"; + case TEE_TDX: + return "tdx"; + + /* + * No other TEE architecture is supported. + */ + default: + printf("ERROR: tee_str(): Invalid input\n"); + return NULL; + } } /* @@ -40,133 +39,127 @@ tee_str(int tee) * "label" argument. This function is essentially a search of a substring * within a given string. */ -char * -find_cookie(char *cookie_data, char *label) +char *find_cookie(char *cookie_data, char *label) { - char *cookie_ptr; - size_t label_len, cookie_len; + char *cookie_ptr; + size_t label_len, cookie_len; - label_len = strlen(label); - cookie_len = strlen(cookie_data); + label_len = strlen(label); + cookie_len = strlen(cookie_data); - cookie_ptr = cookie_data; - for (int i = 0; i < (cookie_len - label_len); i++, cookie_ptr++) { - if (strncmp(cookie_ptr, label, label_len) == 0) - return cookie_ptr; - } + cookie_ptr = cookie_data; + for (int i = 0; i < (cookie_len - label_len); i++, cookie_ptr++) { + if (strncmp(cookie_ptr, label, label_len) == 0) + return cookie_ptr; + } - return NULL; + return NULL; } /* * From a label in a cURL cookie string, parse its associated value. */ -int -read_cookie_val(char *label, char *buf) +int read_cookie_val(char *label, char *buf) { - char *ptr; - int ws; - - ws = 0; - ptr = label; - for (ptr = label; *ptr != '\0'; ptr++) { - if (*ptr == ' ' || *ptr == '\t') - ws = 1; - else if (ws == 1) { - strcpy(buf, ptr); - - return 0; - } + char *ptr; + int ws; + + ws = 0; + ptr = label; + for (ptr = label; *ptr != '\0'; ptr++) { + if (*ptr == ' ' || *ptr == '\t') + ws = 1; + else if (ws == 1) { + strcpy(buf, ptr); + + return 0; } + } - return -1; + return -1; } /* * Given a JSON string and a "label", parse the string associated with that * label and write the contents to "out". */ -int -json_parse_str(char *out, char *label, char *json) +int json_parse_str(char *out, char *label, char *json) { - int ntokens, eq, rc; - jsmn_parser parser; - jsmntok_t *tokens, *curr, *next; - char *val; - int len; + int ntokens, eq, rc; + jsmn_parser parser; + jsmntok_t *tokens, *curr, *next; + char *val; + int len; - rc = -1; + rc = -1; - tokens = (jsmntok_t *) malloc (MAX_TOKENS * sizeof(jsmntok_t)); - if (tokens == NULL) { - printf("ERROR: unable to allocate JSON string\n"); + tokens = (jsmntok_t *)malloc(MAX_TOKENS * sizeof(jsmntok_t)); + if (tokens == NULL) { + printf("ERROR: unable to allocate JSON string\n"); - return rc; - } + return rc; + } - jsmn_init(&parser); + jsmn_init(&parser); - ntokens = jsmn_parse(&parser, json, strlen(json), tokens, MAX_TOKENS); - if (ntokens <= 0) { - printf("ERROR: unable to find any tokens in KBS challenge\n"); + ntokens = jsmn_parse(&parser, json, strlen(json), tokens, MAX_TOKENS); + if (ntokens <= 0) { + printf("ERROR: unable to find any tokens in KBS challenge\n"); - goto out; - } + goto out; + } + + /* + * Traverse each token of the JSON string. + */ + for (int i = 0; i < ntokens - 1; i++) { + curr = &tokens[i]; + next = &tokens[i + 1]; /* - * Traverse each token of the JSON string. + * Only interested in reading a string. */ - for (int i = 0; i < ntokens - 1; i++) { - curr = &tokens[i]; - next = &tokens[i + 1]; - - /* - * Only interested in reading a string. - */ - if (curr->type != JSMN_STRING) - continue; - - /* - * Compare the current token with the label being searched for. - */ - eq = label_find(label, json + curr->start); - if (eq && next->type == JSMN_STRING) { - /* - * Found the string associated with the label, calculate - * its beginning and ending indexes within the JSON - * string and copy the contents over to "out". - */ - val = json + next->start; - len = next->end - next->start; - - memcpy((void *) out, (void *) val, len); - rc = 0; - - goto out; - } + if (curr->type != JSMN_STRING) + continue; + /* + * Compare the current token with the label being searched for. + */ + eq = label_find(label, json + curr->start); + if (eq && next->type == JSMN_STRING) { + /* + * Found the string associated with the label, calculate + * its beginning and ending indexes within the JSON + * string and copy the contents over to "out". + */ + val = json + next->start; + len = next->end - next->start; + + memcpy((void *)out, (void *)val, len); + rc = 0; + + goto out; } + } out: - free((void *) tokens); + free((void *)tokens); - return rc; + return rc; } -static int -label_find(char *label, char *str) +static int label_find(char *label, char *str) { - size_t label_sz; + size_t label_sz; - label_sz = strlen(label); + label_sz = strlen(label); - for (int i = 0; i < label_sz; i++) { - if (label[i] != str[i]) - return 0; - if (label[i] != '\0') - continue; - - } + for (int i = 0; i < label_sz; i++) { + if (label[i] != str[i]) + return 0; + if (label[i] != '\0') + continue; + } - return 1; + return 1; } diff --git a/init/tee/snp_attest.c b/init/tee/snp_attest.c index e6c7e44..8303705 100644 --- a/init/tee/snp_attest.c +++ b/init/tee/snp_attest.c @@ -1,77 +1,76 @@ // SPDX-License-Identifier: Apache-2.0 -#include +#include +#include #include #include +#include +#include #include -#include #include -#include -#include #include #include #include -#include #include +#include -#include "snp_attest.h" #include "kbs/kbs.h" +#include "snp_attest.h" -#define NONCE_MAX 1024 -#define JSON_MAX 1024 -#define GEN_MAX 32 +#define NONCE_MAX 1024 +#define JSON_MAX 1024 +#define GEN_MAX 32 static int snp_get_report(const uint8_t *, size_t, struct snp_report *); static int SNP_ATTEST_ERR(char *); static void json_fmt(char *); -int -snp_attest(char *pass, char *url, char *wid, char *tee_data) +int snp_attest(char *pass, char *url, char *wid, char *tee_data) { - CURL *curl; - char nonce[NONCE_MAX], json[JSON_MAX], gen[GEN_MAX]; - struct snp_report report; - EVP_PKEY *pkey; - BIGNUM *n, *e; - unsigned int hash_size; - uint8_t *hash; + CURL *curl; + char nonce[NONCE_MAX], json[JSON_MAX], gen[GEN_MAX]; + struct snp_report report; + EVP_PKEY *pkey; + BIGNUM *n, *e; + unsigned int hash_size; + uint8_t *hash; - if (kbs_request_marshal(json, TEE_SNP, wid) < 0) - return SNP_ATTEST_ERR("Unable to marshal KBS REQUEST"); + if (kbs_request_marshal(json, TEE_SNP, wid) < 0) + return SNP_ATTEST_ERR("Unable to marshal KBS REQUEST"); - curl = curl_easy_init(); - if (curl == NULL) - return SNP_ATTEST_ERR("Unable to initialize cURL instance"); + curl = curl_easy_init(); + if (curl == NULL) + return SNP_ATTEST_ERR("Unable to initialize cURL instance"); - if (kbs_challenge(curl, url, json, nonce) < 0) - return SNP_ATTEST_ERR("Unable to retrieve nonce from server"); + if (kbs_challenge(curl, url, json, nonce) < 0) + return SNP_ATTEST_ERR("Unable to retrieve nonce from server"); - json_fmt(tee_data); - if (json_parse_str(gen, "gen", tee_data) < 0) - return SNP_ATTEST_ERR("Unable to retrieve SNP generation"); + json_fmt(tee_data); + if (json_parse_str(gen, "gen", tee_data) < 0) + return SNP_ATTEST_ERR("Unable to retrieve SNP generation"); - n = e = NULL; - if (kbs_tee_pubkey_create(&pkey, &n, &e) < 0) - return SNP_ATTEST_ERR("Unable to create TEE public key"); + n = e = NULL; + if (kbs_tee_pubkey_create(&pkey, &n, &e) < 0) + return SNP_ATTEST_ERR("Unable to create TEE public key"); - if (kbs_nonce_pubkey_hash(nonce, pkey, &hash, &hash_size) < 0) - return SNP_ATTEST_ERR("Unable to hash nonce and public key"); + if (kbs_nonce_pubkey_hash(nonce, pkey, &hash, &hash_size) < 0) + return SNP_ATTEST_ERR("Unable to hash nonce and public key"); - if (snp_get_report(hash, hash_size, &report) != EXIT_SUCCESS) - return SNP_ATTEST_ERR("Unable to retrieve attestation report"); + if (snp_get_report(hash, hash_size, &report) != EXIT_SUCCESS) + return SNP_ATTEST_ERR("Unable to retrieve attestation report"); - if (kbs_attest(curl, url, &report, n, e, gen) < 0) - return SNP_ATTEST_ERR("Unable to complete KBS ATTESTATION"); + if (kbs_attest(curl, url, &report, n, e, gen) < 0) + return SNP_ATTEST_ERR("Unable to complete KBS ATTESTATION"); - curl_easy_reset(curl); + curl_easy_reset(curl); - if (kbs_get_key(curl, url, wid, pkey, pass) < 0) - return SNP_ATTEST_ERR("Unable to retrieve passphrase"); + if (kbs_get_key(curl, url, wid, pkey, pass) < 0) + return SNP_ATTEST_ERR("Unable to retrieve passphrase"); - return 0; + return 0; } /* @@ -80,119 +79,118 @@ snp_attest(char *pass, char *url, char *wid, char *tee_data) * SNP_GET_REPORT fills both the attestation report and the certificate * data. */ -static int -snp_get_report(const uint8_t *data, size_t data_sz, struct snp_report *report) +static int snp_get_report(const uint8_t *data, size_t data_sz, + struct snp_report *report) { - int rc = EXIT_FAILURE; - int fd = -1; - struct snp_report_req req; - struct snp_report_resp resp; - struct snp_guest_request_ioctl guest_req; - struct msg_report_resp *report_resp = (struct msg_report_resp *)&resp.data; - - /* - * The kernel will attempt to fill the report, certs, and certs_size, - * Therefore, none of these values can be NULL. - */ - if (report == NULL) { - printf("report is NULL\n"); - rc = EINVAL; - - goto out; - } - - /* - * We will be filling the user_data field of the request with "data". - * Ensure that the data is valid and can fit in the user_data field. - */ - if (data && (data_sz > sizeof(req.user_data) || data_sz == 0)) { - rc = EINVAL; - - goto out; - } - - /* - * Initialize data structures. - */ - memset(&req, 0, sizeof(req)); - - /* - * Copy the data into user_data if it exists. - */ - if (data) - memcpy(&req.user_data, data, data_sz); - - memset(&resp, 0, sizeof(resp)); - - memset(&guest_req, 0, sizeof(guest_req)); - guest_req.msg_version = 1; - guest_req.req_data = (__u64) &req; - guest_req.resp_data = (__u64) &resp; - - /* - * Open the SEV guest device. - */ - errno = 0; - fd = open(SEV_GUEST_DEV, O_RDWR); - if (fd == -1) { - rc = errno; - perror("open"); - - goto out; - } - - /* - * Retrieve the SNP attestation report. - */ - errno = 0; - rc = ioctl(fd, SNP_GET_REPORT, &guest_req); - if (rc == -1) { - rc = errno; - perror("ioctl"); - fprintf(stderr, "errno is %u\n", errno); - fprintf(stderr, "firmware error %#llx\n", guest_req.fw_err); - fprintf(stderr, "report error %x\n", report_resp->status); - - goto out_close; - } - - /* - * Ensure that the report was successfully generated. - */ - if (report_resp->status != 0 ) { - fprintf(stderr, "firmware error %x\n", report_resp->status); - rc = report_resp->status; - - goto out_close; - } else if (report_resp->report_size > sizeof(*report)) { - fprintf(stderr, "report size is %u bytes (expected %lu)!\n", - report_resp->report_size, sizeof(*report)); - rc = EFBIG; - - goto out_close; - } - - /* - * Copy the report + certs data. - */ - memcpy(report, &report_resp->report, report_resp->report_size); - rc = EXIT_SUCCESS; + int rc = EXIT_FAILURE; + int fd = -1; + struct snp_report_req req; + struct snp_report_resp resp; + struct snp_guest_request_ioctl guest_req; + struct msg_report_resp *report_resp = (struct msg_report_resp *)&resp.data; + + /* + * The kernel will attempt to fill the report, certs, and certs_size, + * Therefore, none of these values can be NULL. + */ + if (report == NULL) { + printf("report is NULL\n"); + rc = EINVAL; + + goto out; + } + + /* + * We will be filling the user_data field of the request with "data". + * Ensure that the data is valid and can fit in the user_data field. + */ + if (data && (data_sz > sizeof(req.user_data) || data_sz == 0)) { + rc = EINVAL; + + goto out; + } + + /* + * Initialize data structures. + */ + memset(&req, 0, sizeof(req)); + + /* + * Copy the data into user_data if it exists. + */ + if (data) + memcpy(&req.user_data, data, data_sz); + + memset(&resp, 0, sizeof(resp)); + + memset(&guest_req, 0, sizeof(guest_req)); + guest_req.msg_version = 1; + guest_req.req_data = (__u64)&req; + guest_req.resp_data = (__u64)&resp; + + /* + * Open the SEV guest device. + */ + errno = 0; + fd = open(SEV_GUEST_DEV, O_RDWR); + if (fd == -1) { + rc = errno; + perror("open"); + + goto out; + } + + /* + * Retrieve the SNP attestation report. + */ + errno = 0; + rc = ioctl(fd, SNP_GET_REPORT, &guest_req); + if (rc == -1) { + rc = errno; + perror("ioctl"); + fprintf(stderr, "errno is %u\n", errno); + fprintf(stderr, "firmware error %#llx\n", guest_req.fw_err); + fprintf(stderr, "report error %x\n", report_resp->status); + + goto out_close; + } + + /* + * Ensure that the report was successfully generated. + */ + if (report_resp->status != 0) { + fprintf(stderr, "firmware error %x\n", report_resp->status); + rc = report_resp->status; + + goto out_close; + } else if (report_resp->report_size > sizeof(*report)) { + fprintf(stderr, "report size is %u bytes (expected %lu)!\n", + report_resp->report_size, sizeof(*report)); + rc = EFBIG; + + goto out_close; + } + + /* + * Copy the report + certs data. + */ + memcpy(report, &report_resp->report, report_resp->report_size); + rc = EXIT_SUCCESS; out_close: - if (fd > 0) { - close(fd); - fd = -1; - } + if (fd > 0) { + close(fd); + fd = -1; + } out: - return rc; + return rc; } -static int -SNP_ATTEST_ERR(char *errmsg) +static int SNP_ATTEST_ERR(char *errmsg) { - printf("SNP ATTEST ERROR: %s\n", errmsg); + printf("SNP ATTEST ERROR: %s\n", errmsg); - return -1; + return -1; } /* @@ -204,20 +202,19 @@ SNP_ATTEST_ERR(char *errmsg) * Would become: * "{"test":"123"}" */ -static void -json_fmt(char *str) +static void json_fmt(char *str) { - char cpy[strlen(str)]; - size_t sz, cpy_idx; + char cpy[strlen(str)]; + size_t sz, cpy_idx; - sz = strlen(str); - cpy_idx = 0; + sz = strlen(str); + cpy_idx = 0; - for (int i = 0; i < sz; i++) { - if (str[i] != '\\') - cpy[cpy_idx++] = str[i]; - } - cpy[cpy_idx] = '\0'; + for (int i = 0; i < sz; i++) { + if (str[i] != '\\') + cpy[cpy_idx++] = str[i]; + } + cpy[cpy_idx] = '\0'; - strcpy(str, cpy); + strcpy(str, cpy); } diff --git a/init/tee/snp_attest.h b/init/tee/snp_attest.h index a456668..d923d9b 100644 --- a/init/tee/snp_attest.h +++ b/init/tee/snp_attest.h @@ -13,9 +13,9 @@ * Cryptographic signature (should be signed by the VCEK). */ struct signature { - uint8_t r[72]; - uint8_t s[72]; - uint8_t reserved[512-144]; + uint8_t r[72]; + uint8_t s[72]; + uint8_t reserved[512 - 144]; }; /* @@ -23,14 +23,14 @@ struct signature { * Trusted Computing Base (TCB) of the SNP firmware. */ union tcb_version { - struct { - uint8_t boot_loader; - uint8_t tee; - uint8_t reserved[4]; - uint8_t snp; - uint8_t microcode; - }; - uint64_t raw; + struct { + uint8_t boot_loader; + uint8_t tee; + uint8_t reserved[4]; + uint8_t snp; + uint8_t microcode; + }; + uint64_t raw; }; /* @@ -38,11 +38,11 @@ union tcb_version { * this table should be built and parsed. */ struct cert_table { - struct cert_table_entry { - uuid_t guid; - uint32_t offset; - uint32_t len; - } *entry; + struct cert_table_entry { + uuid_t guid; + uint32_t offset; + uint32_t len; + } *entry; }; /* @@ -50,55 +50,55 @@ struct cert_table { * structure described in firmware version 1.52. */ struct snp_report { - uint32_t version; - uint32_t guest_svn; - uint64_t policy; - uint8_t family_id[16]; - uint8_t image_id[16]; - uint32_t vmpl; - uint32_t signature_algo; - union tcb_version current_tcb; + uint32_t version; + uint32_t guest_svn; + uint64_t policy; + uint8_t family_id[16]; + uint8_t image_id[16]; + uint32_t vmpl; + uint32_t signature_algo; + union tcb_version current_tcb; - /* - * TODO: Change to a "struct platform_info". - */ - uint64_t platform_info; + /* + * TODO: Change to a "struct platform_info". + */ + uint64_t platform_info; - uint32_t author_key_en : 1; - uint32_t _reserved_0 : 31; - uint32_t _reserved_1; - uint8_t report_data[64]; - uint8_t measurement[48]; - uint8_t host_data[32]; - uint8_t id_key_digest[48]; - uint8_t author_key_digest[48]; - uint8_t report_id[32]; - uint8_t report_id_ma[32]; - union tcb_version reported_tcb; - uint8_t _reserved_2[24]; - uint8_t chip_id[64]; - union tcb_version committed_tcb; - uint8_t current_build; - uint8_t current_minor; - uint8_t current_major; - uint8_t _reserved_3; - uint8_t committed_build; - uint8_t committed_minor; - uint8_t committed_major; - uint8_t _reserved_4; - union tcb_version launch_tcb; - uint8_t _reserved_5[168]; - struct signature signature; + uint32_t author_key_en : 1; + uint32_t _reserved_0 : 31; + uint32_t _reserved_1; + uint8_t report_data[64]; + uint8_t measurement[48]; + uint8_t host_data[32]; + uint8_t id_key_digest[48]; + uint8_t author_key_digest[48]; + uint8_t report_id[32]; + uint8_t report_id_ma[32]; + union tcb_version reported_tcb; + uint8_t _reserved_2[24]; + uint8_t chip_id[64]; + union tcb_version committed_tcb; + uint8_t current_build; + uint8_t current_minor; + uint8_t current_major; + uint8_t _reserved_3; + uint8_t committed_build; + uint8_t committed_minor; + uint8_t committed_major; + uint8_t _reserved_4; + union tcb_version launch_tcb; + uint8_t _reserved_5[168]; + struct signature signature; }; /* * Response from the SNP_GET_EXT_REPORT ioctl. */ struct msg_report_resp { - uint32_t status; - uint32_t report_size; - uint8_t reserved[0x20-0x8]; - struct snp_report report; + uint32_t status; + uint32_t report_size; + uint8_t reserved[0x20 - 0x8]; + struct snp_report report; }; // snp_attest.c