cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intel_sdsi.c (12350B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * sdsi: Intel Software Defined Silicon tool for provisioning certificates
      4 * and activation payloads on supported cpus.
      5 *
      6 * See https://github.com/intel/intel-sdsi/blob/master/os-interface.rst
      7 * for register descriptions.
      8 *
      9 * Copyright (C) 2022 Intel Corporation. All rights reserved.
     10 */
     11
     12#include <dirent.h>
     13#include <errno.h>
     14#include <fcntl.h>
     15#include <getopt.h>
     16#include <stdbool.h>
     17#include <stdio.h>
     18#include <stdint.h>
     19#include <stdlib.h>
     20#include <string.h>
     21#include <unistd.h>
     22
     23#include <sys/types.h>
     24
     25#define SDSI_DEV		"intel_vsec.sdsi"
     26#define AUX_DEV_PATH		"/sys/bus/auxiliary/devices/"
     27#define SDSI_PATH		(AUX_DEV_DIR SDSI_DEV)
     28#define GUID			0x6dd191
     29#define REGISTERS_MIN_SIZE	72
     30
     31#define __round_mask(x, y) ((__typeof__(x))((y) - 1))
     32#define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1)
     33
     34struct enabled_features {
     35	uint64_t reserved:3;
     36	uint64_t sdsi:1;
     37	uint64_t reserved1:60;
     38};
     39
     40struct auth_fail_count {
     41	uint64_t key_failure_count:3;
     42	uint64_t key_failure_threshold:3;
     43	uint64_t auth_failure_count:3;
     44	uint64_t auth_failure_threshold:3;
     45	uint64_t reserved:52;
     46};
     47
     48struct availability {
     49	uint64_t reserved:48;
     50	uint64_t available:3;
     51	uint64_t threshold:3;
     52};
     53
     54struct sdsi_regs {
     55	uint64_t ppin;
     56	uint64_t reserved;
     57	struct enabled_features en_features;
     58	uint64_t reserved1;
     59	struct auth_fail_count auth_fail_count;
     60	struct availability prov_avail;
     61	uint64_t reserved2;
     62	uint64_t reserved3;
     63	uint64_t socket_id;
     64};
     65
     66struct sdsi_dev {
     67	struct sdsi_regs regs;
     68	char *dev_name;
     69	char *dev_path;
     70	int guid;
     71};
     72
     73enum command {
     74	CMD_NONE,
     75	CMD_SOCKET_INFO,
     76	CMD_DUMP_CERT,
     77	CMD_PROV_AKC,
     78	CMD_PROV_CAP,
     79};
     80
     81static void sdsi_list_devices(void)
     82{
     83	struct dirent *entry;
     84	DIR *aux_dir;
     85	bool found = false;
     86
     87	aux_dir = opendir(AUX_DEV_PATH);
     88	if (!aux_dir) {
     89		fprintf(stderr, "Cannot open directory %s\n", AUX_DEV_PATH);
     90		return;
     91	}
     92
     93	while ((entry = readdir(aux_dir))) {
     94		if (!strncmp(SDSI_DEV, entry->d_name, strlen(SDSI_DEV))) {
     95			found = true;
     96			printf("%s\n", entry->d_name);
     97		}
     98	}
     99
    100	if (!found)
    101		fprintf(stderr, "No sdsi devices found.\n");
    102}
    103
    104static int sdsi_update_registers(struct sdsi_dev *s)
    105{
    106	FILE *regs_ptr;
    107	int ret;
    108
    109	memset(&s->regs, 0, sizeof(s->regs));
    110
    111	/* Open the registers file */
    112	ret = chdir(s->dev_path);
    113	if (ret == -1) {
    114		perror("chdir");
    115		return ret;
    116	}
    117
    118	regs_ptr = fopen("registers", "r");
    119	if (!regs_ptr) {
    120		perror("Could not open 'registers' file");
    121		return -1;
    122	}
    123
    124	if (s->guid != GUID) {
    125		fprintf(stderr, "Unrecognized guid, 0x%x\n", s->guid);
    126		fclose(regs_ptr);
    127		return -1;
    128	}
    129
    130	/* Update register info for this guid */
    131	ret = fread(&s->regs, sizeof(uint8_t), sizeof(s->regs), regs_ptr);
    132	if (ret != sizeof(s->regs)) {
    133		fprintf(stderr, "Could not read 'registers' file\n");
    134		fclose(regs_ptr);
    135		return -1;
    136	}
    137
    138	fclose(regs_ptr);
    139
    140	return 0;
    141}
    142
    143static int sdsi_read_reg(struct sdsi_dev *s)
    144{
    145	int ret;
    146
    147	ret = sdsi_update_registers(s);
    148	if (ret)
    149		return ret;
    150
    151	/* Print register info for this guid */
    152	printf("\n");
    153	printf("Socket information for device %s\n", s->dev_name);
    154	printf("\n");
    155	printf("PPIN:                           0x%lx\n", s->regs.ppin);
    156	printf("Enabled Features\n");
    157	printf("    SDSi:                       %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");
    158	printf("Authorization Failure Count\n");
    159	printf("    AKC Failure Count:          %d\n", s->regs.auth_fail_count.key_failure_count);
    160	printf("    AKC Failure Threshold:      %d\n", s->regs.auth_fail_count.key_failure_threshold);
    161	printf("    CAP Failure Count:          %d\n", s->regs.auth_fail_count.auth_failure_count);
    162	printf("    CAP Failure Threshold:      %d\n", s->regs.auth_fail_count.auth_failure_threshold);
    163	printf("Provisioning Availability\n");
    164	printf("    Updates Available:          %d\n", s->regs.prov_avail.available);
    165	printf("    Updates Threshold:          %d\n", s->regs.prov_avail.threshold);
    166	printf("Socket ID:                      %ld\n", s->regs.socket_id & 0xF);
    167
    168	return 0;
    169}
    170
    171static int sdsi_certificate_dump(struct sdsi_dev *s)
    172{
    173	uint64_t state_certificate[512] = {0};
    174	bool first_instance;
    175	uint64_t previous;
    176	FILE *cert_ptr;
    177	int i, ret, size;
    178
    179	ret = sdsi_update_registers(s);
    180	if (ret)
    181		return ret;
    182
    183	if (!s->regs.en_features.sdsi) {
    184		fprintf(stderr, "SDSi feature is present but not enabled.");
    185		fprintf(stderr, " Unable to read state certificate");
    186		return -1;
    187	}
    188
    189	ret = chdir(s->dev_path);
    190	if (ret == -1) {
    191		perror("chdir");
    192		return ret;
    193	}
    194
    195	cert_ptr = fopen("state_certificate", "r");
    196	if (!cert_ptr) {
    197		perror("Could not open 'state_certificate' file");
    198		return -1;
    199	}
    200
    201	size = fread(state_certificate, 1, sizeof(state_certificate), cert_ptr);
    202	if (!size) {
    203		fprintf(stderr, "Could not read 'state_certificate' file\n");
    204		fclose(cert_ptr);
    205		return -1;
    206	}
    207
    208	printf("%3d: 0x%lx\n", 0, state_certificate[0]);
    209	previous = state_certificate[0];
    210	first_instance = true;
    211
    212	for (i = 1; i < (int)(round_up(size, sizeof(uint64_t))/sizeof(uint64_t)); i++) {
    213		if (state_certificate[i] == previous) {
    214			if (first_instance) {
    215				puts("*");
    216				first_instance = false;
    217			}
    218			continue;
    219		}
    220		printf("%3d: 0x%lx\n", i, state_certificate[i]);
    221		previous = state_certificate[i];
    222		first_instance = true;
    223	}
    224	printf("%3d\n", i);
    225
    226	fclose(cert_ptr);
    227
    228	return 0;
    229}
    230
    231static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command command)
    232{
    233	int bin_fd, prov_fd, size, ret;
    234	char buf[4096] = { 0 };
    235	char cap[] = "provision_cap";
    236	char akc[] = "provision_akc";
    237	char *prov_file;
    238
    239	if (!bin_file) {
    240		fprintf(stderr, "No binary file provided\n");
    241		return -1;
    242	}
    243
    244	/* Open the binary */
    245	bin_fd = open(bin_file, O_RDONLY);
    246	if (bin_fd == -1) {
    247		fprintf(stderr, "Could not open file %s: %s\n", bin_file, strerror(errno));
    248		return bin_fd;
    249	}
    250
    251	prov_file = (command == CMD_PROV_AKC) ? akc : cap;
    252
    253	ret = chdir(s->dev_path);
    254	if (ret == -1) {
    255		perror("chdir");
    256		close(bin_fd);
    257		return ret;
    258	}
    259
    260	/* Open the provision file */
    261	prov_fd = open(prov_file, O_WRONLY);
    262	if (prov_fd == -1) {
    263		fprintf(stderr, "Could not open file %s: %s\n", prov_file, strerror(errno));
    264		close(bin_fd);
    265		return prov_fd;
    266	}
    267
    268	/* Read the binary file into the buffer */
    269	size = read(bin_fd, buf, 4096);
    270	if (size == -1) {
    271		close(bin_fd);
    272		close(prov_fd);
    273		return -1;
    274	}
    275
    276	ret = write(prov_fd, buf, size);
    277	if (ret == -1) {
    278		close(bin_fd);
    279		close(prov_fd);
    280		perror("Provisioning failed");
    281		return ret;
    282	}
    283
    284	printf("Provisioned %s file %s successfully\n", prov_file, bin_file);
    285
    286	close(bin_fd);
    287	close(prov_fd);
    288
    289	return 0;
    290}
    291
    292static int sdsi_provision_akc(struct sdsi_dev *s, char *bin_file)
    293{
    294	int ret;
    295
    296	ret = sdsi_update_registers(s);
    297	if (ret)
    298		return ret;
    299
    300	if (!s->regs.en_features.sdsi) {
    301		fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision");
    302		return -1;
    303	}
    304
    305	if (!s->regs.prov_avail.available) {
    306		fprintf(stderr, "Maximum number of updates (%d) has been reached.\n",
    307			s->regs.prov_avail.threshold);
    308		return -1;
    309	}
    310
    311	if (s->regs.auth_fail_count.key_failure_count ==
    312	    s->regs.auth_fail_count.key_failure_threshold) {
    313		fprintf(stderr, "Maximum number of AKC provision failures (%d) has been reached.\n",
    314			s->regs.auth_fail_count.key_failure_threshold);
    315		fprintf(stderr, "Power cycle the system to reset the counter\n");
    316		return -1;
    317	}
    318
    319	return sdsi_provision(s, bin_file, CMD_PROV_AKC);
    320}
    321
    322static int sdsi_provision_cap(struct sdsi_dev *s, char *bin_file)
    323{
    324	int ret;
    325
    326	ret = sdsi_update_registers(s);
    327	if (ret)
    328		return ret;
    329
    330	if (!s->regs.en_features.sdsi) {
    331		fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision");
    332		return -1;
    333	}
    334
    335	if (!s->regs.prov_avail.available) {
    336		fprintf(stderr, "Maximum number of updates (%d) has been reached.\n",
    337			s->regs.prov_avail.threshold);
    338		return -1;
    339	}
    340
    341	if (s->regs.auth_fail_count.auth_failure_count ==
    342	    s->regs.auth_fail_count.auth_failure_threshold) {
    343		fprintf(stderr, "Maximum number of CAP provision failures (%d) has been reached.\n",
    344			s->regs.auth_fail_count.auth_failure_threshold);
    345		fprintf(stderr, "Power cycle the system to reset the counter\n");
    346		return -1;
    347	}
    348
    349	return sdsi_provision(s, bin_file, CMD_PROV_CAP);
    350}
    351
    352static int read_sysfs_data(const char *file, int *value)
    353{
    354	char buff[16];
    355	FILE *fp;
    356
    357	fp = fopen(file, "r");
    358	if (!fp) {
    359		perror(file);
    360		return -1;
    361	}
    362
    363	if (!fgets(buff, 16, fp)) {
    364		fprintf(stderr, "Failed to read file '%s'", file);
    365		fclose(fp);
    366		return -1;
    367	}
    368
    369	fclose(fp);
    370	*value = strtol(buff, NULL, 0);
    371
    372	return 0;
    373}
    374
    375static struct sdsi_dev *sdsi_create_dev(char *dev_no)
    376{
    377	int dev_name_len = sizeof(SDSI_DEV) + strlen(dev_no) + 1;
    378	struct sdsi_dev *s;
    379	int guid;
    380	DIR *dir;
    381
    382	s = (struct sdsi_dev *)malloc(sizeof(*s));
    383	if (!s) {
    384		perror("malloc");
    385		return NULL;
    386	}
    387
    388	s->dev_name = (char *)malloc(sizeof(SDSI_DEV) + strlen(dev_no) + 1);
    389	if (!s->dev_name) {
    390		perror("malloc");
    391		free(s);
    392		return NULL;
    393	}
    394
    395	snprintf(s->dev_name, dev_name_len, "%s.%s", SDSI_DEV, dev_no);
    396
    397	s->dev_path = (char *)malloc(sizeof(AUX_DEV_PATH) + dev_name_len);
    398	if (!s->dev_path) {
    399		perror("malloc");
    400		free(s->dev_name);
    401		free(s);
    402		return NULL;
    403	}
    404
    405	snprintf(s->dev_path, sizeof(AUX_DEV_PATH) + dev_name_len, "%s%s", AUX_DEV_PATH,
    406		 s->dev_name);
    407	dir = opendir(s->dev_path);
    408	if (!dir) {
    409		fprintf(stderr, "Could not open directory '%s': %s\n", s->dev_path,
    410			strerror(errno));
    411		free(s->dev_path);
    412		free(s->dev_name);
    413		free(s);
    414		return NULL;
    415	}
    416
    417	if (chdir(s->dev_path) == -1) {
    418		perror("chdir");
    419		free(s->dev_path);
    420		free(s->dev_name);
    421		free(s);
    422		return NULL;
    423	}
    424
    425	if (read_sysfs_data("guid", &guid)) {
    426		free(s->dev_path);
    427		free(s->dev_name);
    428		free(s);
    429		return NULL;
    430	}
    431
    432	s->guid = guid;
    433
    434	return s;
    435}
    436
    437static void sdsi_free_dev(struct sdsi_dev *s)
    438{
    439	free(s->dev_path);
    440	free(s->dev_name);
    441	free(s);
    442}
    443
    444static void usage(char *prog)
    445{
    446	printf("Usage: %s [-l] [-d DEVNO [-iD] [-a FILE] [-c FILE]]\n", prog);
    447}
    448
    449static void show_help(void)
    450{
    451	printf("Commands:\n");
    452	printf("  %-18s\t%s\n", "-l, --list",		"list available sdsi devices");
    453	printf("  %-18s\t%s\n", "-d, --devno DEVNO",	"sdsi device number");
    454	printf("  %-18s\t%s\n", "-i --info",		"show socket information");
    455	printf("  %-18s\t%s\n", "-D --dump",		"dump state certificate data");
    456	printf("  %-18s\t%s\n", "-a --akc FILE",	"provision socket with AKC FILE");
    457	printf("  %-18s\t%s\n", "-c --cap FILE>",	"provision socket with CAP FILE");
    458}
    459
    460int main(int argc, char *argv[])
    461{
    462	char bin_file[PATH_MAX], *dev_no = NULL;
    463	char *progname;
    464	enum command command = CMD_NONE;
    465	struct sdsi_dev *s;
    466	int ret = 0, opt;
    467	int option_index = 0;
    468
    469	static struct option long_options[] = {
    470		{"akc",		required_argument,	0, 'a'},
    471		{"cap",		required_argument,	0, 'c'},
    472		{"devno",	required_argument,	0, 'd'},
    473		{"dump",	no_argument,		0, 'D'},
    474		{"help",	no_argument,		0, 'h'},
    475		{"info",	no_argument,		0, 'i'},
    476		{"list",	no_argument,		0, 'l'},
    477		{0,		0,			0, 0 }
    478	};
    479
    480
    481	progname = argv[0];
    482
    483	while ((opt = getopt_long_only(argc, argv, "+a:c:d:Da:c:h", long_options,
    484			&option_index)) != -1) {
    485		switch (opt) {
    486		case 'd':
    487			dev_no = optarg;
    488			break;
    489		case 'l':
    490			sdsi_list_devices();
    491			return 0;
    492		case 'i':
    493			command = CMD_SOCKET_INFO;
    494			break;
    495		case 'D':
    496			command = CMD_DUMP_CERT;
    497			break;
    498		case 'a':
    499		case 'c':
    500			if (!access(optarg, F_OK) == 0) {
    501				fprintf(stderr, "Could not open file '%s': %s\n", optarg,
    502					strerror(errno));
    503				return -1;
    504			}
    505
    506			if (!realpath(optarg, bin_file)) {
    507				perror("realpath");
    508				return -1;
    509			}
    510
    511			command = (opt == 'a') ? CMD_PROV_AKC : CMD_PROV_CAP;
    512			break;
    513		case 'h':
    514			usage(progname);
    515			show_help();
    516			return 0;
    517		default:
    518			usage(progname);
    519			return -1;
    520		}
    521	}
    522
    523	if (!dev_no) {
    524		if (command != CMD_NONE)
    525			fprintf(stderr, "Missing device number, DEVNO, for this command\n");
    526		usage(progname);
    527		return -1;
    528	}
    529
    530	s = sdsi_create_dev(dev_no);
    531	if (!s)
    532		return -1;
    533
    534	/* Run the command */
    535	switch (command) {
    536	case CMD_NONE:
    537		fprintf(stderr, "Missing command for device %s\n", dev_no);
    538		usage(progname);
    539		break;
    540	case CMD_SOCKET_INFO:
    541		ret = sdsi_read_reg(s);
    542		break;
    543	case CMD_DUMP_CERT:
    544		ret = sdsi_certificate_dump(s);
    545		break;
    546	case CMD_PROV_AKC:
    547		ret = sdsi_provision_akc(s, bin_file);
    548		break;
    549	case CMD_PROV_CAP:
    550		ret = sdsi_provision_cap(s, bin_file);
    551		break;
    552	}
    553
    554
    555	sdsi_free_dev(s);
    556
    557	return ret;
    558}