Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * sdsi: Intel Software Defined Silicon tool for provisioning certificates
0004  * and activation payloads on supported cpus.
0005  *
0006  * See https://github.com/intel/intel-sdsi/blob/master/os-interface.rst
0007  * for register descriptions.
0008  *
0009  * Copyright (C) 2022 Intel Corporation. All rights reserved.
0010  */
0011 
0012 #include <dirent.h>
0013 #include <errno.h>
0014 #include <fcntl.h>
0015 #include <getopt.h>
0016 #include <stdbool.h>
0017 #include <stdio.h>
0018 #include <stdint.h>
0019 #include <stdlib.h>
0020 #include <string.h>
0021 #include <unistd.h>
0022 
0023 #include <sys/types.h>
0024 
0025 #define SDSI_DEV        "intel_vsec.sdsi"
0026 #define AUX_DEV_PATH        "/sys/bus/auxiliary/devices/"
0027 #define SDSI_PATH       (AUX_DEV_DIR SDSI_DEV)
0028 #define GUID            0x6dd191
0029 #define REGISTERS_MIN_SIZE  72
0030 
0031 #define __round_mask(x, y) ((__typeof__(x))((y) - 1))
0032 #define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1)
0033 
0034 struct enabled_features {
0035     uint64_t reserved:3;
0036     uint64_t sdsi:1;
0037     uint64_t reserved1:60;
0038 };
0039 
0040 struct auth_fail_count {
0041     uint64_t key_failure_count:3;
0042     uint64_t key_failure_threshold:3;
0043     uint64_t auth_failure_count:3;
0044     uint64_t auth_failure_threshold:3;
0045     uint64_t reserved:52;
0046 };
0047 
0048 struct availability {
0049     uint64_t reserved:48;
0050     uint64_t available:3;
0051     uint64_t threshold:3;
0052 };
0053 
0054 struct sdsi_regs {
0055     uint64_t ppin;
0056     uint64_t reserved;
0057     struct enabled_features en_features;
0058     uint64_t reserved1;
0059     struct auth_fail_count auth_fail_count;
0060     struct availability prov_avail;
0061     uint64_t reserved2;
0062     uint64_t reserved3;
0063     uint64_t socket_id;
0064 };
0065 
0066 struct sdsi_dev {
0067     struct sdsi_regs regs;
0068     char *dev_name;
0069     char *dev_path;
0070     int guid;
0071 };
0072 
0073 enum command {
0074     CMD_NONE,
0075     CMD_SOCKET_INFO,
0076     CMD_DUMP_CERT,
0077     CMD_PROV_AKC,
0078     CMD_PROV_CAP,
0079 };
0080 
0081 static void sdsi_list_devices(void)
0082 {
0083     struct dirent *entry;
0084     DIR *aux_dir;
0085     bool found = false;
0086 
0087     aux_dir = opendir(AUX_DEV_PATH);
0088     if (!aux_dir) {
0089         fprintf(stderr, "Cannot open directory %s\n", AUX_DEV_PATH);
0090         return;
0091     }
0092 
0093     while ((entry = readdir(aux_dir))) {
0094         if (!strncmp(SDSI_DEV, entry->d_name, strlen(SDSI_DEV))) {
0095             found = true;
0096             printf("%s\n", entry->d_name);
0097         }
0098     }
0099 
0100     if (!found)
0101         fprintf(stderr, "No sdsi devices found.\n");
0102 }
0103 
0104 static int sdsi_update_registers(struct sdsi_dev *s)
0105 {
0106     FILE *regs_ptr;
0107     int ret;
0108 
0109     memset(&s->regs, 0, sizeof(s->regs));
0110 
0111     /* Open the registers file */
0112     ret = chdir(s->dev_path);
0113     if (ret == -1) {
0114         perror("chdir");
0115         return ret;
0116     }
0117 
0118     regs_ptr = fopen("registers", "r");
0119     if (!regs_ptr) {
0120         perror("Could not open 'registers' file");
0121         return -1;
0122     }
0123 
0124     if (s->guid != GUID) {
0125         fprintf(stderr, "Unrecognized guid, 0x%x\n", s->guid);
0126         fclose(regs_ptr);
0127         return -1;
0128     }
0129 
0130     /* Update register info for this guid */
0131     ret = fread(&s->regs, sizeof(uint8_t), sizeof(s->regs), regs_ptr);
0132     if (ret != sizeof(s->regs)) {
0133         fprintf(stderr, "Could not read 'registers' file\n");
0134         fclose(regs_ptr);
0135         return -1;
0136     }
0137 
0138     fclose(regs_ptr);
0139 
0140     return 0;
0141 }
0142 
0143 static int sdsi_read_reg(struct sdsi_dev *s)
0144 {
0145     int ret;
0146 
0147     ret = sdsi_update_registers(s);
0148     if (ret)
0149         return ret;
0150 
0151     /* Print register info for this guid */
0152     printf("\n");
0153     printf("Socket information for device %s\n", s->dev_name);
0154     printf("\n");
0155     printf("PPIN:                           0x%lx\n", s->regs.ppin);
0156     printf("Enabled Features\n");
0157     printf("    SDSi:                       %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");
0158     printf("Authorization Failure Count\n");
0159     printf("    AKC Failure Count:          %d\n", s->regs.auth_fail_count.key_failure_count);
0160     printf("    AKC Failure Threshold:      %d\n", s->regs.auth_fail_count.key_failure_threshold);
0161     printf("    CAP Failure Count:          %d\n", s->regs.auth_fail_count.auth_failure_count);
0162     printf("    CAP Failure Threshold:      %d\n", s->regs.auth_fail_count.auth_failure_threshold);
0163     printf("Provisioning Availability\n");
0164     printf("    Updates Available:          %d\n", s->regs.prov_avail.available);
0165     printf("    Updates Threshold:          %d\n", s->regs.prov_avail.threshold);
0166     printf("Socket ID:                      %ld\n", s->regs.socket_id & 0xF);
0167 
0168     return 0;
0169 }
0170 
0171 static int sdsi_certificate_dump(struct sdsi_dev *s)
0172 {
0173     uint64_t state_certificate[512] = {0};
0174     bool first_instance;
0175     uint64_t previous;
0176     FILE *cert_ptr;
0177     int i, ret, size;
0178 
0179     ret = sdsi_update_registers(s);
0180     if (ret)
0181         return ret;
0182 
0183     if (!s->regs.en_features.sdsi) {
0184         fprintf(stderr, "SDSi feature is present but not enabled.");
0185         fprintf(stderr, " Unable to read state certificate");
0186         return -1;
0187     }
0188 
0189     ret = chdir(s->dev_path);
0190     if (ret == -1) {
0191         perror("chdir");
0192         return ret;
0193     }
0194 
0195     cert_ptr = fopen("state_certificate", "r");
0196     if (!cert_ptr) {
0197         perror("Could not open 'state_certificate' file");
0198         return -1;
0199     }
0200 
0201     size = fread(state_certificate, 1, sizeof(state_certificate), cert_ptr);
0202     if (!size) {
0203         fprintf(stderr, "Could not read 'state_certificate' file\n");
0204         fclose(cert_ptr);
0205         return -1;
0206     }
0207 
0208     printf("%3d: 0x%lx\n", 0, state_certificate[0]);
0209     previous = state_certificate[0];
0210     first_instance = true;
0211 
0212     for (i = 1; i < (int)(round_up(size, sizeof(uint64_t))/sizeof(uint64_t)); i++) {
0213         if (state_certificate[i] == previous) {
0214             if (first_instance) {
0215                 puts("*");
0216                 first_instance = false;
0217             }
0218             continue;
0219         }
0220         printf("%3d: 0x%lx\n", i, state_certificate[i]);
0221         previous = state_certificate[i];
0222         first_instance = true;
0223     }
0224     printf("%3d\n", i);
0225 
0226     fclose(cert_ptr);
0227 
0228     return 0;
0229 }
0230 
0231 static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command command)
0232 {
0233     int bin_fd, prov_fd, size, ret;
0234     char buf[4096] = { 0 };
0235     char cap[] = "provision_cap";
0236     char akc[] = "provision_akc";
0237     char *prov_file;
0238 
0239     if (!bin_file) {
0240         fprintf(stderr, "No binary file provided\n");
0241         return -1;
0242     }
0243 
0244     /* Open the binary */
0245     bin_fd = open(bin_file, O_RDONLY);
0246     if (bin_fd == -1) {
0247         fprintf(stderr, "Could not open file %s: %s\n", bin_file, strerror(errno));
0248         return bin_fd;
0249     }
0250 
0251     prov_file = (command == CMD_PROV_AKC) ? akc : cap;
0252 
0253     ret = chdir(s->dev_path);
0254     if (ret == -1) {
0255         perror("chdir");
0256         close(bin_fd);
0257         return ret;
0258     }
0259 
0260     /* Open the provision file */
0261     prov_fd = open(prov_file, O_WRONLY);
0262     if (prov_fd == -1) {
0263         fprintf(stderr, "Could not open file %s: %s\n", prov_file, strerror(errno));
0264         close(bin_fd);
0265         return prov_fd;
0266     }
0267 
0268     /* Read the binary file into the buffer */
0269     size = read(bin_fd, buf, 4096);
0270     if (size == -1) {
0271         close(bin_fd);
0272         close(prov_fd);
0273         return -1;
0274     }
0275 
0276     ret = write(prov_fd, buf, size);
0277     if (ret == -1) {
0278         close(bin_fd);
0279         close(prov_fd);
0280         perror("Provisioning failed");
0281         return ret;
0282     }
0283 
0284     printf("Provisioned %s file %s successfully\n", prov_file, bin_file);
0285 
0286     close(bin_fd);
0287     close(prov_fd);
0288 
0289     return 0;
0290 }
0291 
0292 static int sdsi_provision_akc(struct sdsi_dev *s, char *bin_file)
0293 {
0294     int ret;
0295 
0296     ret = sdsi_update_registers(s);
0297     if (ret)
0298         return ret;
0299 
0300     if (!s->regs.en_features.sdsi) {
0301         fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision");
0302         return -1;
0303     }
0304 
0305     if (!s->regs.prov_avail.available) {
0306         fprintf(stderr, "Maximum number of updates (%d) has been reached.\n",
0307             s->regs.prov_avail.threshold);
0308         return -1;
0309     }
0310 
0311     if (s->regs.auth_fail_count.key_failure_count ==
0312         s->regs.auth_fail_count.key_failure_threshold) {
0313         fprintf(stderr, "Maximum number of AKC provision failures (%d) has been reached.\n",
0314             s->regs.auth_fail_count.key_failure_threshold);
0315         fprintf(stderr, "Power cycle the system to reset the counter\n");
0316         return -1;
0317     }
0318 
0319     return sdsi_provision(s, bin_file, CMD_PROV_AKC);
0320 }
0321 
0322 static int sdsi_provision_cap(struct sdsi_dev *s, char *bin_file)
0323 {
0324     int ret;
0325 
0326     ret = sdsi_update_registers(s);
0327     if (ret)
0328         return ret;
0329 
0330     if (!s->regs.en_features.sdsi) {
0331         fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision");
0332         return -1;
0333     }
0334 
0335     if (!s->regs.prov_avail.available) {
0336         fprintf(stderr, "Maximum number of updates (%d) has been reached.\n",
0337             s->regs.prov_avail.threshold);
0338         return -1;
0339     }
0340 
0341     if (s->regs.auth_fail_count.auth_failure_count ==
0342         s->regs.auth_fail_count.auth_failure_threshold) {
0343         fprintf(stderr, "Maximum number of CAP provision failures (%d) has been reached.\n",
0344             s->regs.auth_fail_count.auth_failure_threshold);
0345         fprintf(stderr, "Power cycle the system to reset the counter\n");
0346         return -1;
0347     }
0348 
0349     return sdsi_provision(s, bin_file, CMD_PROV_CAP);
0350 }
0351 
0352 static int read_sysfs_data(const char *file, int *value)
0353 {
0354     char buff[16];
0355     FILE *fp;
0356 
0357     fp = fopen(file, "r");
0358     if (!fp) {
0359         perror(file);
0360         return -1;
0361     }
0362 
0363     if (!fgets(buff, 16, fp)) {
0364         fprintf(stderr, "Failed to read file '%s'", file);
0365         fclose(fp);
0366         return -1;
0367     }
0368 
0369     fclose(fp);
0370     *value = strtol(buff, NULL, 0);
0371 
0372     return 0;
0373 }
0374 
0375 static struct sdsi_dev *sdsi_create_dev(char *dev_no)
0376 {
0377     int dev_name_len = sizeof(SDSI_DEV) + strlen(dev_no) + 1;
0378     struct sdsi_dev *s;
0379     int guid;
0380     DIR *dir;
0381 
0382     s = (struct sdsi_dev *)malloc(sizeof(*s));
0383     if (!s) {
0384         perror("malloc");
0385         return NULL;
0386     }
0387 
0388     s->dev_name = (char *)malloc(sizeof(SDSI_DEV) + strlen(dev_no) + 1);
0389     if (!s->dev_name) {
0390         perror("malloc");
0391         free(s);
0392         return NULL;
0393     }
0394 
0395     snprintf(s->dev_name, dev_name_len, "%s.%s", SDSI_DEV, dev_no);
0396 
0397     s->dev_path = (char *)malloc(sizeof(AUX_DEV_PATH) + dev_name_len);
0398     if (!s->dev_path) {
0399         perror("malloc");
0400         free(s->dev_name);
0401         free(s);
0402         return NULL;
0403     }
0404 
0405     snprintf(s->dev_path, sizeof(AUX_DEV_PATH) + dev_name_len, "%s%s", AUX_DEV_PATH,
0406          s->dev_name);
0407     dir = opendir(s->dev_path);
0408     if (!dir) {
0409         fprintf(stderr, "Could not open directory '%s': %s\n", s->dev_path,
0410             strerror(errno));
0411         free(s->dev_path);
0412         free(s->dev_name);
0413         free(s);
0414         return NULL;
0415     }
0416 
0417     if (chdir(s->dev_path) == -1) {
0418         perror("chdir");
0419         free(s->dev_path);
0420         free(s->dev_name);
0421         free(s);
0422         return NULL;
0423     }
0424 
0425     if (read_sysfs_data("guid", &guid)) {
0426         free(s->dev_path);
0427         free(s->dev_name);
0428         free(s);
0429         return NULL;
0430     }
0431 
0432     s->guid = guid;
0433 
0434     return s;
0435 }
0436 
0437 static void sdsi_free_dev(struct sdsi_dev *s)
0438 {
0439     free(s->dev_path);
0440     free(s->dev_name);
0441     free(s);
0442 }
0443 
0444 static void usage(char *prog)
0445 {
0446     printf("Usage: %s [-l] [-d DEVNO [-iD] [-a FILE] [-c FILE]]\n", prog);
0447 }
0448 
0449 static void show_help(void)
0450 {
0451     printf("Commands:\n");
0452     printf("  %-18s\t%s\n", "-l, --list",       "list available sdsi devices");
0453     printf("  %-18s\t%s\n", "-d, --devno DEVNO",    "sdsi device number");
0454     printf("  %-18s\t%s\n", "-i --info",        "show socket information");
0455     printf("  %-18s\t%s\n", "-D --dump",        "dump state certificate data");
0456     printf("  %-18s\t%s\n", "-a --akc FILE",    "provision socket with AKC FILE");
0457     printf("  %-18s\t%s\n", "-c --cap FILE>",   "provision socket with CAP FILE");
0458 }
0459 
0460 int main(int argc, char *argv[])
0461 {
0462     char bin_file[PATH_MAX], *dev_no = NULL;
0463     char *progname;
0464     enum command command = CMD_NONE;
0465     struct sdsi_dev *s;
0466     int ret = 0, opt;
0467     int option_index = 0;
0468 
0469     static struct option long_options[] = {
0470         {"akc",     required_argument,  0, 'a'},
0471         {"cap",     required_argument,  0, 'c'},
0472         {"devno",   required_argument,  0, 'd'},
0473         {"dump",    no_argument,        0, 'D'},
0474         {"help",    no_argument,        0, 'h'},
0475         {"info",    no_argument,        0, 'i'},
0476         {"list",    no_argument,        0, 'l'},
0477         {0,     0,          0, 0 }
0478     };
0479 
0480 
0481     progname = argv[0];
0482 
0483     while ((opt = getopt_long_only(argc, argv, "+a:c:d:Da:c:h", long_options,
0484             &option_index)) != -1) {
0485         switch (opt) {
0486         case 'd':
0487             dev_no = optarg;
0488             break;
0489         case 'l':
0490             sdsi_list_devices();
0491             return 0;
0492         case 'i':
0493             command = CMD_SOCKET_INFO;
0494             break;
0495         case 'D':
0496             command = CMD_DUMP_CERT;
0497             break;
0498         case 'a':
0499         case 'c':
0500             if (!access(optarg, F_OK) == 0) {
0501                 fprintf(stderr, "Could not open file '%s': %s\n", optarg,
0502                     strerror(errno));
0503                 return -1;
0504             }
0505 
0506             if (!realpath(optarg, bin_file)) {
0507                 perror("realpath");
0508                 return -1;
0509             }
0510 
0511             command = (opt == 'a') ? CMD_PROV_AKC : CMD_PROV_CAP;
0512             break;
0513         case 'h':
0514             usage(progname);
0515             show_help();
0516             return 0;
0517         default:
0518             usage(progname);
0519             return -1;
0520         }
0521     }
0522 
0523     if (!dev_no) {
0524         if (command != CMD_NONE)
0525             fprintf(stderr, "Missing device number, DEVNO, for this command\n");
0526         usage(progname);
0527         return -1;
0528     }
0529 
0530     s = sdsi_create_dev(dev_no);
0531     if (!s)
0532         return -1;
0533 
0534     /* Run the command */
0535     switch (command) {
0536     case CMD_NONE:
0537         fprintf(stderr, "Missing command for device %s\n", dev_no);
0538         usage(progname);
0539         break;
0540     case CMD_SOCKET_INFO:
0541         ret = sdsi_read_reg(s);
0542         break;
0543     case CMD_DUMP_CERT:
0544         ret = sdsi_certificate_dump(s);
0545         break;
0546     case CMD_PROV_AKC:
0547         ret = sdsi_provision_akc(s, bin_file);
0548         break;
0549     case CMD_PROV_CAP:
0550         ret = sdsi_provision_cap(s, bin_file);
0551         break;
0552     }
0553 
0554 
0555     sdsi_free_dev(s);
0556 
0557     return ret;
0558 }