1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018-2023, Juniper Networks, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 #include <sys/cdefs.h> 28 #include <stdlib.h> 29 #include <sysexits.h> 30 #include <unistd.h> 31 #include <paths.h> 32 #include <err.h> 33 #include <syslog.h> 34 #include <libsecureboot.h> 35 #include <libveriexec.h> 36 #include <sys/types.h> 37 38 #include "veriexec.h" 39 40 /* Globals that are shared with manifest_parser.c */ 41 int dev_fd = -1; 42 int ForceFlags = 0; 43 int Verbose = 0; 44 int VeriexecVersion = 0; 45 const char *Cdir = NULL; 46 47 /*! 48 * @brief Print help message describing program's usage 49 * @param void 50 * @return always returns code 0 51 */ 52 static int 53 veriexec_usage(void) 54 { 55 printf("%s", 56 "Usage:\tveriexec [-C path] [-hlxv] [-[iz] state] [path]\n"); 57 58 return (0); 59 } 60 61 /*! 62 * @brief Load a veriexec manifest 63 * @param manifest Pointer to the location of the manifest file 64 * @retval the error code returned from the parser 65 */ 66 static int 67 veriexec_load(const char *manifest) 68 { 69 unsigned char *content; 70 int rc; 71 72 content = verify_signed(manifest, VEF_VERBOSE); 73 if (!content) 74 errx(EX_USAGE, "cannot verify %s", manifest); 75 if (manifest_open(manifest, (const char *)content)) { 76 rc = yyparse(); 77 } else { 78 err(EX_NOINPUT, "cannot load %s", manifest); 79 } 80 free(content); 81 return (rc); 82 } 83 84 /*! 85 * @brief Get the veriexec state for the supplied argument 86 * @param arg_text String containing the argument to be processed 87 * @retval The veriexec state number for the specified argument 88 */ 89 static uint32_t 90 veriexec_state_query(const char *arg_text) 91 { 92 uint32_t state = 0; 93 unsigned long len; 94 95 len = strlen(arg_text); 96 97 if (strncmp(arg_text, "active", len) == 0) 98 state |= VERIEXEC_STATE_ACTIVE; 99 else if (strncmp(arg_text, "enforce", len) == 0) 100 state |= VERIEXEC_STATE_ENFORCE; 101 if (strncmp(arg_text, "loaded", len) == 0) 102 state |= VERIEXEC_STATE_LOADED; 103 if (strncmp(arg_text, "locked", len) == 0) 104 state |= VERIEXEC_STATE_LOCKED; 105 if (state == 0 || __bitcount(state) > 1) 106 errx(EX_USAGE, "Unknown state \'%s\'", arg_text); 107 108 return (state); 109 } 110 111 /*! 112 * @brief Get the veriexec command state for the supplied argument 113 * @param arg_text String containing the argument to be processed 114 * @retval The veriexec command state for the specified argument 115 */ 116 static uint32_t 117 veriexec_state_modify(const char *arg_text) 118 { 119 uint32_t state = 0; 120 unsigned long len; 121 122 len = strlen(arg_text); 123 124 if (strncmp(arg_text, "active", len) == 0) 125 state = VERIEXEC_ACTIVE; 126 else if (strncmp(arg_text, "enforce", len) == 0) 127 state = VERIEXEC_ENFORCE; 128 else if (strncmp(arg_text, "getstate", len) == 0) 129 state = VERIEXEC_GETSTATE; 130 else if (strncmp(arg_text, "lock", len) == 0) 131 state = VERIEXEC_LOCK; 132 else 133 errx(EX_USAGE, "Unknown command \'%s\'", arg_text); 134 135 return (state); 136 } 137 138 #ifdef HAVE_VERIEXEC_GET_PATH_LABEL 139 static void 140 veriexec_check_labels(int argc, char *argv[]) 141 { 142 char buf[BUFSIZ]; 143 char *cp; 144 int n; 145 146 n = (argc - optind); 147 for (; optind < argc; optind++) { 148 cp = veriexec_get_path_label(argv[optind], buf, sizeof(buf)); 149 if (cp) { 150 if (n > 1) 151 printf("%s: %s\n", argv[optind], cp); 152 else 153 printf("%s\n", cp); 154 if (cp != buf) 155 free(cp); 156 } 157 } 158 exit(EX_OK); 159 } 160 #endif 161 162 static void 163 veriexec_check_paths(int argc, char *argv[]) 164 { 165 int x; 166 167 x = EX_OK; 168 for (; optind < argc; optind++) { 169 if (veriexec_check_path(argv[optind])) { 170 warn("%s", argv[optind]); 171 x = 2; 172 } 173 } 174 exit(x); 175 } 176 177 int 178 main(int argc, char *argv[]) 179 { 180 long long converted_int; 181 uint32_t state; 182 int c, x; 183 184 if (argc < 2) 185 return (veriexec_usage()); 186 187 dev_fd = open(_PATH_DEV_VERIEXEC, O_WRONLY, 0); 188 189 while ((c = getopt(argc, argv, "C:hi:lSxvz:")) != -1) { 190 switch (c) { 191 case 'h': 192 /* Print usage info */ 193 194 return (veriexec_usage()); 195 case 'C': 196 /* Get the provided directory argument */ 197 198 Cdir = optarg; 199 break; 200 case 'i': 201 /* Query the current state */ 202 203 if (dev_fd < 0) { 204 err(EX_UNAVAILABLE, "cannot open veriexec"); 205 } 206 if (ioctl(dev_fd, VERIEXEC_GETSTATE, &x)) { 207 err(EX_UNAVAILABLE, 208 "Cannot get veriexec state"); 209 } 210 211 state = veriexec_state_query(optarg); 212 213 exit((x & state) == 0); 214 break; 215 #ifdef HAVE_VERIEXEC_GET_PATH_LABEL 216 case 'l': 217 veriexec_check_labels(argc, argv); 218 break; 219 #endif 220 case 'S': 221 /* Strictly enforce certificate validity */ 222 ve_enforce_validity_set(1); 223 break; 224 case 'v': 225 /* Increase the verbosity */ 226 227 Verbose++; 228 break; 229 case 'x': 230 /* Check veriexec paths */ 231 232 /* 233 * -x says all other args are paths to check. 234 */ 235 veriexec_check_paths(argc, argv); 236 break; 237 case 'z': 238 /* Modify the state */ 239 240 if (strncmp(optarg, "debug", strlen(optarg)) == 0) { 241 const char *error; 242 243 if (optind >= argc) 244 errx(EX_USAGE, 245 "Missing mac_veriexec verbosity level \'N\', veriexec -z debug N, where N is \'off\' or the value 0 or greater"); 246 247 if (strncmp(argv[optind], "off", strlen(argv[optind])) == 0) { 248 state = VERIEXEC_DEBUG_OFF; 249 x = 0; 250 } else { 251 state = VERIEXEC_DEBUG_ON; 252 253 converted_int = strtonum(argv[optind], 0, INT_MAX, &error); 254 255 if (error != NULL) 256 errx(EX_USAGE, "Conversion error for argument \'%s\' : %s", 257 argv[optind], error); 258 259 x = (int) converted_int; 260 261 262 if (x == 0) 263 state = VERIEXEC_DEBUG_OFF; 264 } 265 } else 266 state = veriexec_state_modify(optarg); 267 268 if (dev_fd < 0) 269 err(EX_UNAVAILABLE, "Cannot open veriexec"); 270 if (ioctl(dev_fd, state, &x)) 271 err(EX_UNAVAILABLE, "Cannot %s veriexec", optarg); 272 273 if (state == VERIEXEC_DEBUG_ON || state == VERIEXEC_DEBUG_OFF) 274 printf("mac_veriexec debug verbosity level: %d\n", x); 275 else if (state == VERIEXEC_GETSTATE) 276 printf("Veriexec state (octal) : %#o\n", x); 277 278 exit(EX_OK); 279 break; 280 default: 281 282 /* Missing argument, print usage info.*/ 283 veriexec_usage(); 284 exit(EX_USAGE); 285 break; 286 } 287 } 288 289 if (Verbose) 290 printf("Verbosity level : %d\n", Verbose); 291 292 if (dev_fd < 0) 293 err(EX_UNAVAILABLE, "Cannot open veriexec"); 294 295 openlog(getprogname(), LOG_PID, LOG_AUTH); 296 if (ve_trust_init() < 1) 297 errx(EX_OSFILE, "cannot initialize trust store"); 298 #ifdef VERIEXEC_GETVERSION 299 if (ioctl(dev_fd, VERIEXEC_GETVERSION, &VeriexecVersion)) { 300 VeriexecVersion = 0; /* unknown */ 301 } 302 #endif 303 304 for (; optind < argc; optind++) { 305 if (veriexec_load(argv[optind])) { 306 err(EX_DATAERR, "cannot load %s", argv[optind]); 307 } 308 } 309 exit(EX_OK); 310 } 311