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 #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 [-h] [-i state] [-C] [-xv state|verbosity] [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 int 139 main(int argc, char *argv[]) 140 { 141 long long converted_int; 142 uint32_t state; 143 int c, x; 144 145 if (argc < 2) 146 return (veriexec_usage()); 147 148 dev_fd = open(_PATH_DEV_VERIEXEC, O_WRONLY, 0); 149 150 while ((c = getopt(argc, argv, "hC:i:Sxvz:")) != -1) { 151 switch (c) { 152 case 'h': 153 /* Print usage info */ 154 155 return (veriexec_usage()); 156 case 'C': 157 /* Get the provided directory argument */ 158 159 Cdir = optarg; 160 break; 161 case 'i': 162 /* Query the current state */ 163 164 if (dev_fd < 0) { 165 err(EX_UNAVAILABLE, "cannot open veriexec"); 166 } 167 if (ioctl(dev_fd, VERIEXEC_GETSTATE, &x)) { 168 err(EX_UNAVAILABLE, 169 "Cannot get veriexec state"); 170 } 171 172 state = veriexec_state_query(optarg); 173 174 exit((x & state) == 0); 175 break; 176 case 'S': 177 /* Strictly enforce certificate validity */ 178 ve_enforce_validity_set(1); 179 break; 180 case 'v': 181 /* Increase the verbosity */ 182 183 Verbose++; 184 break; 185 case 'x': 186 /* Check veriexec paths */ 187 188 /* 189 * -x says all other args are paths to check. 190 */ 191 for (x = EX_OK; optind < argc; optind++) { 192 if (veriexec_check_path(argv[optind])) { 193 warn("%s", argv[optind]); 194 x = 2; 195 } 196 } 197 exit(x); 198 break; 199 case 'z': 200 /* Modify the state */ 201 202 if (strncmp(optarg, "debug", strlen(optarg)) == 0) { 203 const char *error; 204 205 if (optind >= argc) 206 errx(EX_USAGE, 207 "Missing mac_veriexec verbosity level \'N\', veriexec -z debug N, where N is \'off\' or the value 0 or greater"); 208 209 if (strncmp(argv[optind], "off", strlen(argv[optind])) == 0) { 210 state = VERIEXEC_DEBUG_OFF; 211 x = 0; 212 } else { 213 state = VERIEXEC_DEBUG_ON; 214 215 converted_int = strtonum(argv[optind], 0, INT_MAX, &error); 216 217 if (error != NULL) 218 errx(EX_USAGE, "Conversion error for argument \'%s\' : %s", 219 argv[optind], error); 220 221 x = (int) converted_int; 222 223 224 if (x == 0) 225 state = VERIEXEC_DEBUG_OFF; 226 } 227 } else 228 state = veriexec_state_modify(optarg); 229 230 if (dev_fd < 0) 231 err(EX_UNAVAILABLE, "Cannot open veriexec"); 232 if (ioctl(dev_fd, state, &x)) 233 err(EX_UNAVAILABLE, "Cannot %s veriexec", optarg); 234 235 if (state == VERIEXEC_DEBUG_ON || state == VERIEXEC_DEBUG_OFF) 236 printf("mac_veriexec debug verbosity level: %d\n", x); 237 else if (state == VERIEXEC_GETSTATE) 238 printf("Veriexec state (octal) : %#o\n", x); 239 240 exit(EX_OK); 241 break; 242 default: 243 244 /* Missing argument, print usage info.*/ 245 veriexec_usage(); 246 exit(EX_USAGE); 247 break; 248 } 249 } 250 251 if (Verbose) 252 printf("Verbosity level : %d\n", Verbose); 253 254 if (dev_fd < 0) 255 err(EX_UNAVAILABLE, "Cannot open veriexec"); 256 257 openlog(getprogname(), LOG_PID, LOG_AUTH); 258 if (ve_trust_init() < 1) 259 errx(EX_OSFILE, "cannot initialize trust store"); 260 #ifdef VERIEXEC_GETVERSION 261 if (ioctl(dev_fd, VERIEXEC_GETVERSION, &VeriexecVersion)) { 262 VeriexecVersion = 0; /* unknown */ 263 } 264 #endif 265 266 for (; optind < argc; optind++) { 267 if (veriexec_load(argv[optind])) { 268 err(EX_DATAERR, "cannot load %s", argv[optind]); 269 } 270 } 271 exit(EX_OK); 272 } 273