1 /*- 2 * Copyright (c) 2018, Juniper Networks, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 14 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 15 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 16 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 17 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 19 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 #include <sys/cdefs.h> 26 __FBSDID("$FreeBSD$"); 27 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() 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 char c; 144 int x; 145 146 if (argc < 2) 147 return (veriexec_usage()); 148 149 dev_fd = open(_PATH_DEV_VERIEXEC, O_WRONLY, 0); 150 151 while ((c = getopt(argc, argv, "hC:i:xvz:")) != -1) { 152 switch (c) { 153 case 'h': 154 /* Print usage info */ 155 156 return (veriexec_usage()); 157 case 'C': 158 /* Get the provided directory argument */ 159 160 Cdir = optarg; 161 break; 162 case 'i': 163 /* Query the current state */ 164 165 if (dev_fd < 0) { 166 err(EX_UNAVAILABLE, "cannot open veriexec"); 167 } 168 if (ioctl(dev_fd, VERIEXEC_GETSTATE, &x)) { 169 err(EX_UNAVAILABLE, 170 "Cannot get veriexec state"); 171 } 172 173 state = veriexec_state_query(optarg); 174 175 exit((x & state) == 0); 176 break; 177 case 'v': 178 /* Increase the verbosity */ 179 180 Verbose++; 181 break; 182 case 'x': 183 /* Check veriexec paths */ 184 185 /* 186 * -x says all other args are paths to check. 187 */ 188 for (x = EX_OK; optind < argc; optind++) { 189 if (veriexec_check_path(argv[optind])) { 190 warn("%s", argv[optind]); 191 x = 2; 192 } 193 } 194 exit(x); 195 break; 196 case 'z': 197 /* Modify the state */ 198 199 if (strncmp(optarg, "debug", strlen(optarg)) == 0) { 200 const char *error; 201 202 if (optind >= argc) 203 errx(EX_USAGE, 204 "Missing mac_veriexec verbosity level \'N\', veriexec -z debug N, where N is \'off\' or the value 0 or greater"); 205 206 if (strncmp(argv[optind], "off", strlen(argv[optind])) == 0) { 207 state = VERIEXEC_DEBUG_OFF; 208 x = 0; 209 } else { 210 state = VERIEXEC_DEBUG_ON; 211 212 converted_int = strtonum(argv[optind], 0, INT_MAX, &error); 213 214 if (error != NULL) 215 errx(EX_USAGE, "Conversion error for argument \'%s\' : %s", 216 argv[optind], error); 217 218 x = (int) converted_int; 219 220 221 if (x == 0) 222 state = VERIEXEC_DEBUG_OFF; 223 } 224 } else 225 state = veriexec_state_modify(optarg); 226 227 if (dev_fd < 0) 228 err(EX_UNAVAILABLE, "Cannot open veriexec"); 229 if (ioctl(dev_fd, state, &x)) 230 err(EX_UNAVAILABLE, "Cannot %s veriexec", optarg); 231 232 if (state == VERIEXEC_DEBUG_ON || state == VERIEXEC_DEBUG_OFF) 233 printf("mac_veriexec debug verbosity level: %d\n", x); 234 else if (state == VERIEXEC_GETSTATE) 235 printf("Veriexec state (octal) : %#o\n", x); 236 237 exit(EX_OK); 238 break; 239 default: 240 241 /* Missing argument, print usage info.*/ 242 veriexec_usage(); 243 exit(EX_USAGE); 244 break; 245 } 246 } 247 248 if (Verbose) 249 printf("Verbosity level : %d\n", Verbose); 250 251 if (dev_fd < 0) 252 err(EX_UNAVAILABLE, "Cannot open veriexec"); 253 254 openlog(getprogname(), LOG_PID, LOG_AUTH); 255 if (ve_trust_init() < 1) 256 errx(EX_OSFILE, "cannot initialize trust store"); 257 #ifdef VERIEXEC_GETVERSION 258 if (ioctl(dev_fd, VERIEXEC_GETVERSION, &VeriexecVersion)) { 259 VeriexecVersion = 0; /* unknown */ 260 } 261 #endif 262 263 for (; optind < argc; optind++) { 264 if (veriexec_load(argv[optind])) { 265 err(EX_DATAERR, "cannot load %s", argv[optind]); 266 } 267 } 268 exit(EX_OK); 269 } 270