1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018, 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 __FBSDID("$FreeBSD$"); 29 30 #include <stdlib.h> 31 #include <sysexits.h> 32 #include <unistd.h> 33 #include <paths.h> 34 #include <err.h> 35 #include <syslog.h> 36 #include <libsecureboot.h> 37 #include <libveriexec.h> 38 #include <sys/types.h> 39 40 #include "veriexec.h" 41 42 /* Globals that are shared with manifest_parser.c */ 43 int dev_fd = -1; 44 int ForceFlags = 0; 45 int Verbose = 0; 46 int VeriexecVersion = 0; 47 const char *Cdir = NULL; 48 49 /*! 50 * @brief Print help message describing program's usage 51 * @param void 52 * @return always returns code 0 53 */ 54 static int 55 veriexec_usage(void) 56 { 57 printf("%s", 58 "Usage:\tveriexec [-h] [-i state] [-C] [-xv state|verbosity] [path]\n"); 59 60 return (0); 61 } 62 63 /*! 64 * @brief Load a veriexec manifest 65 * @param manifest Pointer to the location of the manifest file 66 * @retval the error code returned from the parser 67 */ 68 static int 69 veriexec_load(const char *manifest) 70 { 71 unsigned char *content; 72 int rc; 73 74 content = verify_signed(manifest, VEF_VERBOSE); 75 if (!content) 76 errx(EX_USAGE, "cannot verify %s", manifest); 77 if (manifest_open(manifest, (const char *)content)) { 78 rc = yyparse(); 79 } else { 80 err(EX_NOINPUT, "cannot load %s", manifest); 81 } 82 free(content); 83 return (rc); 84 } 85 86 /*! 87 * @brief Get the veriexec state for the supplied argument 88 * @param arg_text String containing the argument to be processed 89 * @retval The veriexec state number for the specified argument 90 */ 91 static uint32_t 92 veriexec_state_query(const char *arg_text) 93 { 94 uint32_t state = 0; 95 unsigned long len; 96 97 len = strlen(arg_text); 98 99 if (strncmp(arg_text, "active", len) == 0) 100 state |= VERIEXEC_STATE_ACTIVE; 101 else if (strncmp(arg_text, "enforce", len) == 0) 102 state |= VERIEXEC_STATE_ENFORCE; 103 if (strncmp(arg_text, "loaded", len) == 0) 104 state |= VERIEXEC_STATE_LOADED; 105 if (strncmp(arg_text, "locked", len) == 0) 106 state |= VERIEXEC_STATE_LOCKED; 107 if (state == 0 || __bitcount(state) > 1) 108 errx(EX_USAGE, "Unknown state \'%s\'", arg_text); 109 110 return (state); 111 } 112 113 /*! 114 * @brief Get the veriexec command state for the supplied argument 115 * @param arg_text String containing the argument to be processed 116 * @retval The veriexec command state for the specified argument 117 */ 118 static uint32_t 119 veriexec_state_modify(const char *arg_text) 120 { 121 uint32_t state = 0; 122 unsigned long len; 123 124 len = strlen(arg_text); 125 126 if (strncmp(arg_text, "active", len) == 0) 127 state = VERIEXEC_ACTIVE; 128 else if (strncmp(arg_text, "enforce", len) == 0) 129 state = VERIEXEC_ENFORCE; 130 else if (strncmp(arg_text, "getstate", len) == 0) 131 state = VERIEXEC_GETSTATE; 132 else if (strncmp(arg_text, "lock", len) == 0) 133 state = VERIEXEC_LOCK; 134 else 135 errx(EX_USAGE, "Unknown command \'%s\'", arg_text); 136 137 return (state); 138 } 139 140 int 141 main(int argc, char *argv[]) 142 { 143 long long converted_int; 144 uint32_t state; 145 int c, x; 146 147 if (argc < 2) 148 return (veriexec_usage()); 149 150 dev_fd = open(_PATH_DEV_VERIEXEC, O_WRONLY, 0); 151 152 while ((c = getopt(argc, argv, "hC:i:Sxvz:")) != -1) { 153 switch (c) { 154 case 'h': 155 /* Print usage info */ 156 157 return (veriexec_usage()); 158 case 'C': 159 /* Get the provided directory argument */ 160 161 Cdir = optarg; 162 break; 163 case 'i': 164 /* Query the current state */ 165 166 if (dev_fd < 0) { 167 err(EX_UNAVAILABLE, "cannot open veriexec"); 168 } 169 if (ioctl(dev_fd, VERIEXEC_GETSTATE, &x)) { 170 err(EX_UNAVAILABLE, 171 "Cannot get veriexec state"); 172 } 173 174 state = veriexec_state_query(optarg); 175 176 exit((x & state) == 0); 177 break; 178 case 'S': 179 /* Strictly enforce certificate validity */ 180 ve_enforce_validity_set(1); 181 break; 182 case 'v': 183 /* Increase the verbosity */ 184 185 Verbose++; 186 break; 187 case 'x': 188 /* Check veriexec paths */ 189 190 /* 191 * -x says all other args are paths to check. 192 */ 193 for (x = EX_OK; optind < argc; optind++) { 194 if (veriexec_check_path(argv[optind])) { 195 warn("%s", argv[optind]); 196 x = 2; 197 } 198 } 199 exit(x); 200 break; 201 case 'z': 202 /* Modify the state */ 203 204 if (strncmp(optarg, "debug", strlen(optarg)) == 0) { 205 const char *error; 206 207 if (optind >= argc) 208 errx(EX_USAGE, 209 "Missing mac_veriexec verbosity level \'N\', veriexec -z debug N, where N is \'off\' or the value 0 or greater"); 210 211 if (strncmp(argv[optind], "off", strlen(argv[optind])) == 0) { 212 state = VERIEXEC_DEBUG_OFF; 213 x = 0; 214 } else { 215 state = VERIEXEC_DEBUG_ON; 216 217 converted_int = strtonum(argv[optind], 0, INT_MAX, &error); 218 219 if (error != NULL) 220 errx(EX_USAGE, "Conversion error for argument \'%s\' : %s", 221 argv[optind], error); 222 223 x = (int) converted_int; 224 225 226 if (x == 0) 227 state = VERIEXEC_DEBUG_OFF; 228 } 229 } else 230 state = veriexec_state_modify(optarg); 231 232 if (dev_fd < 0) 233 err(EX_UNAVAILABLE, "Cannot open veriexec"); 234 if (ioctl(dev_fd, state, &x)) 235 err(EX_UNAVAILABLE, "Cannot %s veriexec", optarg); 236 237 if (state == VERIEXEC_DEBUG_ON || state == VERIEXEC_DEBUG_OFF) 238 printf("mac_veriexec debug verbosity level: %d\n", x); 239 else if (state == VERIEXEC_GETSTATE) 240 printf("Veriexec state (octal) : %#o\n", x); 241 242 exit(EX_OK); 243 break; 244 default: 245 246 /* Missing argument, print usage info.*/ 247 veriexec_usage(); 248 exit(EX_USAGE); 249 break; 250 } 251 } 252 253 if (Verbose) 254 printf("Verbosity level : %d\n", Verbose); 255 256 if (dev_fd < 0) 257 err(EX_UNAVAILABLE, "Cannot open veriexec"); 258 259 openlog(getprogname(), LOG_PID, LOG_AUTH); 260 if (ve_trust_init() < 1) 261 errx(EX_OSFILE, "cannot initialize trust store"); 262 #ifdef VERIEXEC_GETVERSION 263 if (ioctl(dev_fd, VERIEXEC_GETVERSION, &VeriexecVersion)) { 264 VeriexecVersion = 0; /* unknown */ 265 } 266 #endif 267 268 for (; optind < argc; optind++) { 269 if (veriexec_load(argv[optind])) { 270 err(EX_DATAERR, "cannot load %s", argv[optind]); 271 } 272 } 273 exit(EX_OK); 274 } 275