Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/powerpc/dexcr: Add chdexcr utility

Adds a utility to exercise the prctl DEXCR inheritance in the shell.
Supports setting and clearing each aspect.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
[mpe: Use correct SPDX license, use execvp() for usability, print errors]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240417112325.728010-9-bgray@linux.ibm.com

authored by

Benjamin Gray and committed by
Michael Ellerman
f88723a6 9c4866b2

+185 -103
+1
tools/testing/selftests/powerpc/dexcr/.gitignore
··· 1 1 dexcr_test 2 2 hashchk_test 3 + chdexcr 3 4 lsdexcr
+1 -1
tools/testing/selftests/powerpc/dexcr/Makefile
··· 1 1 TEST_GEN_PROGS := dexcr_test hashchk_test 2 - TEST_GEN_FILES := lsdexcr 2 + TEST_GEN_FILES := lsdexcr chdexcr 3 3 4 4 include ../../lib.mk 5 5 include ../flags.mk
+112
tools/testing/selftests/powerpc/dexcr/chdexcr.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + #include <errno.h> 4 + #include <stddef.h> 5 + #include <stdio.h> 6 + #include <stdlib.h> 7 + #include <string.h> 8 + #include <sys/prctl.h> 9 + 10 + #include "dexcr.h" 11 + #include "utils.h" 12 + 13 + static void die(const char *msg) 14 + { 15 + printf("%s\n", msg); 16 + exit(1); 17 + } 18 + 19 + static void help(void) 20 + { 21 + printf("Invoke a provided program with a custom DEXCR on-exec reset value\n" 22 + "\n" 23 + "usage: chdexcr [CHDEXCR OPTIONS] -- PROGRAM [ARGS...]\n" 24 + "\n" 25 + "Each configurable DEXCR aspect is exposed as an option.\n" 26 + "\n" 27 + "The normal option sets the aspect in the DEXCR. The --no- variant\n" 28 + "clears that aspect. For example, --ibrtpd sets the IBRTPD aspect bit,\n" 29 + "so indirect branch predicition will be disabled in the provided program.\n" 30 + "Conversely, --no-ibrtpd clears the aspect bit, so indirect branch\n" 31 + "prediction may occur.\n" 32 + "\n" 33 + "CHDEXCR OPTIONS:\n"); 34 + 35 + for (int i = 0; i < ARRAY_SIZE(aspects); i++) { 36 + const struct dexcr_aspect *aspect = &aspects[i]; 37 + 38 + if (aspect->prctl == -1) 39 + continue; 40 + 41 + printf(" --%-6s / --no-%-6s : %s\n", aspect->opt, aspect->opt, aspect->desc); 42 + } 43 + } 44 + 45 + static const struct dexcr_aspect *opt_to_aspect(const char *opt) 46 + { 47 + for (int i = 0; i < ARRAY_SIZE(aspects); i++) 48 + if (aspects[i].prctl != -1 && !strcmp(aspects[i].opt, opt)) 49 + return &aspects[i]; 50 + 51 + return NULL; 52 + } 53 + 54 + static int apply_option(const char *option) 55 + { 56 + const struct dexcr_aspect *aspect; 57 + const char *opt = NULL; 58 + const char *set_prefix = "--"; 59 + const char *clear_prefix = "--no-"; 60 + unsigned long ctrl = 0; 61 + int err; 62 + 63 + if (!strcmp(option, "-h") || !strcmp(option, "--help")) { 64 + help(); 65 + exit(0); 66 + } 67 + 68 + /* Strip out --(no-) prefix and determine ctrl value */ 69 + if (!strncmp(option, clear_prefix, strlen(clear_prefix))) { 70 + opt = &option[strlen(clear_prefix)]; 71 + ctrl |= PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC; 72 + } else if (!strncmp(option, set_prefix, strlen(set_prefix))) { 73 + opt = &option[strlen(set_prefix)]; 74 + ctrl |= PR_PPC_DEXCR_CTRL_SET_ONEXEC; 75 + } 76 + 77 + if (!opt || !*opt) 78 + return 1; 79 + 80 + aspect = opt_to_aspect(opt); 81 + if (!aspect) 82 + die("unknown aspect"); 83 + 84 + err = pr_set_dexcr(aspect->prctl, ctrl); 85 + if (err) 86 + die("failed to apply option"); 87 + 88 + return 0; 89 + } 90 + 91 + int main(int argc, char *const argv[]) 92 + { 93 + int i; 94 + 95 + if (!dexcr_exists()) 96 + die("DEXCR not detected on this hardware"); 97 + 98 + for (i = 1; i < argc; i++) 99 + if (apply_option(argv[i])) 100 + break; 101 + 102 + if (i < argc && !strcmp(argv[i], "--")) 103 + i++; 104 + 105 + if (i >= argc) 106 + die("missing command"); 107 + 108 + execvp(argv[i], &argv[i]); 109 + perror("execve"); 110 + 111 + return errno; 112 + }
+47
tools/testing/selftests/powerpc/dexcr/dexcr.h
··· 9 9 #define _SELFTESTS_POWERPC_DEXCR_DEXCR_H 10 10 11 11 #include <stdbool.h> 12 + #include <sys/prctl.h> 12 13 #include <sys/types.h> 13 14 14 15 #include "reg.h" ··· 26 25 str(.long (0x7C0005A4 | PPC_RAW_HASH_ARGS(b, i, a));) 27 26 #define PPC_RAW_HASHCHK(b, i, a) \ 28 27 str(.long (0x7C0005E4 | PPC_RAW_HASH_ARGS(b, i, a));) 28 + 29 + struct dexcr_aspect { 30 + const char *name; /* Short display name */ 31 + const char *opt; /* Option name for chdexcr */ 32 + const char *desc; /* Expanded aspect meaning */ 33 + unsigned int index; /* Aspect bit index in DEXCR */ 34 + unsigned long prctl; /* 'which' value for get/set prctl */ 35 + }; 36 + 37 + static const struct dexcr_aspect aspects[] = { 38 + { 39 + .name = "SBHE", 40 + .opt = "sbhe", 41 + .desc = "Speculative branch hint enable", 42 + .index = 0, 43 + .prctl = PR_PPC_DEXCR_SBHE, 44 + }, 45 + { 46 + .name = "IBRTPD", 47 + .opt = "ibrtpd", 48 + .desc = "Indirect branch recurrent target prediction disable", 49 + .index = 3, 50 + .prctl = PR_PPC_DEXCR_IBRTPD, 51 + }, 52 + { 53 + .name = "SRAPD", 54 + .opt = "srapd", 55 + .desc = "Subroutine return address prediction disable", 56 + .index = 4, 57 + .prctl = PR_PPC_DEXCR_SRAPD, 58 + }, 59 + { 60 + .name = "NPHIE", 61 + .opt = "nphie", 62 + .desc = "Non-privileged hash instruction enable", 63 + .index = 5, 64 + .prctl = PR_PPC_DEXCR_NPHIE, 65 + }, 66 + { 67 + .name = "PHIE", 68 + .opt = "phie", 69 + .desc = "Privileged hash instruction enable", 70 + .index = 6, 71 + .prctl = -1, 72 + }, 73 + }; 29 74 30 75 bool dexcr_exists(void); 31 76
+24 -102
tools/testing/selftests/powerpc/dexcr/lsdexcr.c
··· 12 12 static unsigned int hdexcr; 13 13 static unsigned int effective; 14 14 15 - struct dexcr_aspect { 16 - const char *name; 17 - const char *desc; 18 - unsigned int index; 19 - unsigned long prctl; 20 - const char *sysctl; 21 - }; 22 - 23 - static const struct dexcr_aspect aspects[] = { 24 - { 25 - .name = "SBHE", 26 - .desc = "Speculative branch hint enable", 27 - .index = 0, 28 - .prctl = PR_PPC_DEXCR_SBHE, 29 - .sysctl = "speculative_branch_hint_enable", 30 - }, 31 - { 32 - .name = "IBRTPD", 33 - .desc = "Indirect branch recurrent target prediction disable", 34 - .index = 3, 35 - .prctl = PR_PPC_DEXCR_IBRTPD, 36 - .sysctl = "indirect_branch_recurrent_target_prediction_disable", 37 - }, 38 - { 39 - .name = "SRAPD", 40 - .desc = "Subroutine return address prediction disable", 41 - .index = 4, 42 - .prctl = PR_PPC_DEXCR_SRAPD, 43 - .sysctl = "subroutine_return_address_prediction_disable", 44 - }, 45 - { 46 - .name = "NPHIE", 47 - .desc = "Non-privileged hash instruction enable", 48 - .index = 5, 49 - .prctl = PR_PPC_DEXCR_NPHIE, 50 - .sysctl = "nonprivileged_hash_instruction_enable", 51 - }, 52 - { 53 - .name = "PHIE", 54 - .desc = "Privileged hash instruction enable", 55 - .index = 6, 56 - .prctl = -1, 57 - .sysctl = NULL, 58 - }, 59 - }; 60 - 61 15 static void print_list(const char *list[], size_t len) 62 16 { 63 17 for (size_t i = 0; i < len; i++) { ··· 71 117 72 118 static void print_aspect_config(const struct dexcr_aspect *aspect) 73 119 { 74 - char sysctl_path[128] = "/proc/sys/kernel/dexcr/"; 75 - const char *reason = "unknown"; 120 + const char *reason = NULL; 76 121 const char *reason_hyp = NULL; 77 - const char *reason_sysctl = "no sysctl"; 78 122 const char *reason_prctl = "no prctl"; 79 123 bool actual = effective & DEXCR_PR_BIT(aspect->index); 80 - bool expected = false; 124 + bool expected = actual; /* Assume it's fine if we don't expect a specific set/clear value */ 81 125 82 - long sysctl_ctrl = 0; 83 - int prctl_ctrl = 0; 84 - int err; 126 + if (actual) 127 + reason = "set by unknown"; 128 + else 129 + reason = "cleared by unknown"; 85 130 86 - if (aspect->prctl >= 0) { 87 - prctl_ctrl = pr_get_dexcr(aspect->prctl); 88 - if (prctl_ctrl < 0) 89 - reason_prctl = "(failed to read prctl)"; 90 - else { 91 - if (prctl_ctrl & PR_PPC_DEXCR_CTRL_SET) { 131 + if (aspect->prctl != -1) { 132 + int ctrl = pr_get_dexcr(aspect->prctl); 133 + 134 + if (ctrl < 0) { 135 + reason_prctl = "failed to read prctl"; 136 + } else { 137 + if (ctrl & PR_PPC_DEXCR_CTRL_SET) { 92 138 reason_prctl = "set by prctl"; 93 139 expected = true; 94 - } else if (prctl_ctrl & PR_PPC_DEXCR_CTRL_CLEAR) { 140 + } else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR) { 95 141 reason_prctl = "cleared by prctl"; 96 142 expected = false; 97 - } else 143 + } else { 98 144 reason_prctl = "unknown prctl"; 145 + } 99 146 100 147 reason = reason_prctl; 101 148 } 102 149 } 103 150 104 - if (aspect->sysctl) { 105 - strcat(sysctl_path, aspect->sysctl); 106 - err = read_long(sysctl_path, &sysctl_ctrl, 10); 107 - if (err) 108 - reason_sysctl = "(failed to read sysctl)"; 109 - else { 110 - switch (sysctl_ctrl) { 111 - case 0: 112 - reason_sysctl = "cleared by sysctl"; 113 - reason = reason_sysctl; 114 - expected = false; 115 - break; 116 - case 1: 117 - reason_sysctl = "set by sysctl"; 118 - reason = reason_sysctl; 119 - expected = true; 120 - break; 121 - case 2: 122 - reason_sysctl = "not modified by sysctl"; 123 - break; 124 - case 3: 125 - reason_sysctl = "cleared by sysctl (permanent)"; 126 - reason = reason_sysctl; 127 - expected = false; 128 - break; 129 - case 4: 130 - reason_sysctl = "set by sysctl (permanent)"; 131 - reason = reason_sysctl; 132 - expected = true; 133 - break; 134 - default: 135 - reason_sysctl = "unknown sysctl"; 136 - break; 137 - } 138 - } 139 - } 140 - 141 - 142 151 if (hdexcr & DEXCR_PR_BIT(aspect->index)) { 143 152 reason_hyp = "set by hypervisor"; 144 153 reason = reason_hyp; 145 154 expected = true; 146 - } else 155 + } else { 147 156 reason_hyp = "not modified by hypervisor"; 157 + } 148 158 149 - printf("%12s (%d): %-28s (%s, %s, %s)\n", 159 + printf("%12s (%d): %-28s (%s, %s)\n", 150 160 aspect->name, 151 161 aspect->index, 152 162 reason, 153 163 reason_hyp, 154 - reason_sysctl, 155 164 reason_prctl); 156 165 166 + /* 167 + * The checks are not atomic, so this can technically trigger if the 168 + * hypervisor makes a change while we are checking each source. It's 169 + * far more likely to be a bug if we see this though. 170 + */ 157 171 if (actual != expected) 158 172 printf(" : ! actual %s does not match config\n", aspect->name); 159 173 }