1 /* 2 * SPDX-License-Identifier: GPL-2.0-or-later 3 * 4 * uefi vars device - VarCheckPolicyLibMmiHandler implementation 5 * 6 * variable policy specs: 7 * https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md 8 */ 9 #include "qemu/osdep.h" 10 #include "system/dma.h" 11 #include "migration/vmstate.h" 12 13 #include "hw/uefi/var-service.h" 14 #include "hw/uefi/var-service-api.h" 15 #include "hw/uefi/var-service-edk2.h" 16 17 #include "trace/trace-hw_uefi.h" 18 19 static void calc_policy(uefi_var_policy *pol); 20 21 static int uefi_var_policy_post_load(void *opaque, int version_id) 22 { 23 uefi_var_policy *pol = opaque; 24 25 calc_policy(pol); 26 return 0; 27 } 28 29 const VMStateDescription vmstate_uefi_var_policy = { 30 .name = "uefi-var-policy", 31 .post_load = uefi_var_policy_post_load, 32 .fields = (VMStateField[]) { 33 VMSTATE_UINT32(entry_size, uefi_var_policy), 34 VMSTATE_VBUFFER_ALLOC_UINT32(entry, uefi_var_policy, 35 0, NULL, entry_size), 36 VMSTATE_END_OF_LIST() 37 }, 38 }; 39 40 static void print_policy_entry(variable_policy_entry *pe) 41 { 42 uint16_t *name = (void *)pe + pe->offset_to_name; 43 44 fprintf(stderr, "%s:\n", __func__); 45 46 fprintf(stderr, " name ´"); 47 while (*name) { 48 fprintf(stderr, "%c", *name); 49 name++; 50 } 51 fprintf(stderr, "', version=%d.%d, size=%d\n", 52 pe->version >> 16, pe->version & 0xffff, pe->size); 53 54 if (pe->min_size) { 55 fprintf(stderr, " size min=%d\n", pe->min_size); 56 } 57 if (pe->max_size != UINT32_MAX) { 58 fprintf(stderr, " size max=%u\n", pe->max_size); 59 } 60 if (pe->attributes_must_have) { 61 fprintf(stderr, " attr must=0x%x\n", pe->attributes_must_have); 62 } 63 if (pe->attributes_cant_have) { 64 fprintf(stderr, " attr cant=0x%x\n", pe->attributes_cant_have); 65 } 66 if (pe->lock_policy_type) { 67 fprintf(stderr, " lock policy type %d\n", pe->lock_policy_type); 68 } 69 } 70 71 static gboolean wildcard_str_equal(uefi_var_policy *pol, 72 uefi_variable *var) 73 { 74 return uefi_str_equal_ex(pol->name, pol->name_size, 75 var->name, var->name_size, 76 true); 77 } 78 79 static uefi_var_policy *find_policy(uefi_vars_state *uv, QemuUUID guid, 80 uint16_t *name, uint64_t name_size) 81 { 82 uefi_var_policy *pol; 83 84 QTAILQ_FOREACH(pol, &uv->var_policies, next) { 85 if (!qemu_uuid_is_equal(&pol->entry->namespace, &guid)) { 86 continue; 87 } 88 if (!uefi_str_equal(pol->name, pol->name_size, 89 name, name_size)) { 90 continue; 91 } 92 return pol; 93 } 94 return NULL; 95 } 96 97 static uefi_var_policy *wildcard_find_policy(uefi_vars_state *uv, 98 uefi_variable *var) 99 { 100 uefi_var_policy *pol; 101 102 QTAILQ_FOREACH(pol, &uv->var_policies, next) { 103 if (!qemu_uuid_is_equal(&pol->entry->namespace, &var->guid)) { 104 continue; 105 } 106 if (!wildcard_str_equal(pol, var)) { 107 continue; 108 } 109 return pol; 110 } 111 return NULL; 112 } 113 114 static void calc_policy(uefi_var_policy *pol) 115 { 116 variable_policy_entry *pe = pol->entry; 117 unsigned int i; 118 119 pol->name = (void *)pol->entry + pe->offset_to_name; 120 pol->name_size = pe->size - pe->offset_to_name; 121 122 for (i = 0; i < pol->name_size / 2; i++) { 123 if (pol->name[i] == '#') { 124 pol->hashmarks++; 125 } 126 } 127 } 128 129 uefi_var_policy *uefi_vars_add_policy(uefi_vars_state *uv, 130 variable_policy_entry *pe) 131 { 132 uefi_var_policy *pol, *p; 133 134 pol = g_new0(uefi_var_policy, 1); 135 pol->entry = g_malloc(pe->size); 136 memcpy(pol->entry, pe, pe->size); 137 pol->entry_size = pe->size; 138 139 calc_policy(pol); 140 141 /* keep list sorted by priority, add to tail of priority group */ 142 QTAILQ_FOREACH(p, &uv->var_policies, next) { 143 if ((p->hashmarks > pol->hashmarks) || 144 (!p->name_size && pol->name_size)) { 145 QTAILQ_INSERT_BEFORE(p, pol, next); 146 return pol; 147 } 148 } 149 150 QTAILQ_INSERT_TAIL(&uv->var_policies, pol, next); 151 return pol; 152 } 153 154 efi_status uefi_vars_policy_check(uefi_vars_state *uv, 155 uefi_variable *var, 156 gboolean is_newvar) 157 { 158 uefi_var_policy *pol; 159 variable_policy_entry *pe; 160 variable_lock_on_var_state *lvarstate; 161 uint16_t *lvarname; 162 size_t lvarnamesize; 163 uefi_variable *lvar; 164 165 if (!uv->end_of_dxe) { 166 return EFI_SUCCESS; 167 } 168 169 pol = wildcard_find_policy(uv, var); 170 if (!pol) { 171 return EFI_SUCCESS; 172 } 173 pe = pol->entry; 174 175 uefi_trace_variable(__func__, var->guid, var->name, var->name_size); 176 print_policy_entry(pe); 177 178 if ((var->attributes & pe->attributes_must_have) != pe->attributes_must_have) { 179 trace_uefi_vars_policy_deny("must-have-attr"); 180 return EFI_INVALID_PARAMETER; 181 } 182 if ((var->attributes & pe->attributes_cant_have) != 0) { 183 trace_uefi_vars_policy_deny("cant-have-attr"); 184 return EFI_INVALID_PARAMETER; 185 } 186 187 if (var->data_size < pe->min_size) { 188 trace_uefi_vars_policy_deny("min-size"); 189 return EFI_INVALID_PARAMETER; 190 } 191 if (var->data_size > pe->max_size) { 192 trace_uefi_vars_policy_deny("max-size"); 193 return EFI_INVALID_PARAMETER; 194 } 195 196 switch (pe->lock_policy_type) { 197 case VARIABLE_POLICY_TYPE_NO_LOCK: 198 break; 199 200 case VARIABLE_POLICY_TYPE_LOCK_NOW: 201 trace_uefi_vars_policy_deny("lock-now"); 202 return EFI_WRITE_PROTECTED; 203 204 case VARIABLE_POLICY_TYPE_LOCK_ON_CREATE: 205 if (!is_newvar) { 206 trace_uefi_vars_policy_deny("lock-on-create"); 207 return EFI_WRITE_PROTECTED; 208 } 209 break; 210 211 case VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE: 212 lvarstate = (void *)pol->entry + sizeof(*pe); 213 lvarname = (void *)pol->entry + sizeof(*pe) + sizeof(*lvarstate); 214 lvarnamesize = pe->offset_to_name - sizeof(*pe) - sizeof(*lvarstate); 215 216 uefi_trace_variable(__func__, lvarstate->namespace, 217 lvarname, lvarnamesize); 218 lvar = uefi_vars_find_variable(uv, lvarstate->namespace, 219 lvarname, lvarnamesize); 220 if (lvar && lvar->data_size == 1) { 221 uint8_t *value = lvar->data; 222 if (lvarstate->value == *value) { 223 return EFI_WRITE_PROTECTED; 224 } 225 } 226 break; 227 } 228 229 return EFI_SUCCESS; 230 } 231 232 void uefi_vars_policies_clear(uefi_vars_state *uv) 233 { 234 uefi_var_policy *pol; 235 236 while (!QTAILQ_EMPTY(&uv->var_policies)) { 237 pol = QTAILQ_FIRST(&uv->var_policies); 238 QTAILQ_REMOVE(&uv->var_policies, pol, next); 239 g_free(pol->entry); 240 g_free(pol); 241 } 242 } 243 244 static size_t uefi_vars_mm_policy_error(mm_header *mhdr, 245 mm_check_policy *mchk, 246 uint64_t status) 247 { 248 mchk->result = status; 249 return sizeof(*mchk); 250 } 251 252 static uint32_t uefi_vars_mm_check_policy_is_enabled(uefi_vars_state *uv, 253 mm_header *mhdr, 254 mm_check_policy *mchk, 255 void *func) 256 { 257 mm_check_policy_is_enabled *mpar = func; 258 size_t length; 259 260 length = sizeof(*mchk) + sizeof(*mpar); 261 if (mhdr->length < length) { 262 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE); 263 } 264 265 mpar->state = TRUE; 266 mchk->result = EFI_SUCCESS; 267 return sizeof(*mchk); 268 } 269 270 static uint32_t uefi_vars_mm_check_policy_register(uefi_vars_state *uv, 271 mm_header *mhdr, 272 mm_check_policy *mchk, 273 void *func) 274 { 275 variable_policy_entry *pe = func; 276 uefi_var_policy *pol; 277 uint64_t length; 278 279 if (uadd64_overflow(sizeof(*mchk), pe->size, &length)) { 280 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE); 281 } 282 if (mhdr->length < length) { 283 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE); 284 } 285 if (pe->size < sizeof(*pe)) { 286 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE); 287 } 288 if (pe->offset_to_name < sizeof(*pe)) { 289 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE); 290 } 291 292 if (pe->lock_policy_type == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE && 293 pe->offset_to_name < sizeof(*pe) + sizeof(variable_lock_on_var_state)) { 294 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE); 295 } 296 297 /* check space for minimum string length */ 298 if (pe->size < (size_t)pe->offset_to_name) { 299 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE); 300 } 301 302 if (!uefi_str_is_valid((void *)pe + pe->offset_to_name, 303 pe->size - pe->offset_to_name, 304 false)) { 305 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_INVALID_PARAMETER); 306 } 307 308 pol = find_policy(uv, pe->namespace, 309 (void *)pe + pe->offset_to_name, 310 pe->size - pe->offset_to_name); 311 if (pol) { 312 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_ALREADY_STARTED); 313 } 314 315 uefi_vars_add_policy(uv, pe); 316 317 mchk->result = EFI_SUCCESS; 318 return sizeof(*mchk); 319 } 320 321 uint32_t uefi_vars_mm_check_policy_proto(uefi_vars_state *uv) 322 { 323 static const char *fnames[] = { 324 "zero", 325 "disable", 326 "is-enabled", 327 "register", 328 "dump", 329 "lock", 330 }; 331 const char *fname; 332 mm_header *mhdr = (mm_header *) uv->buffer; 333 mm_check_policy *mchk = (mm_check_policy *) (uv->buffer + sizeof(*mhdr)); 334 void *func = (uv->buffer + sizeof(*mhdr) + sizeof(*mchk)); 335 336 if (mhdr->length < sizeof(*mchk)) { 337 return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE; 338 } 339 340 fname = mchk->command < ARRAY_SIZE(fnames) 341 ? fnames[mchk->command] 342 : "unknown"; 343 trace_uefi_vars_policy_cmd(fname); 344 345 switch (mchk->command) { 346 case VAR_CHECK_POLICY_COMMAND_DISABLE: 347 mchk->result = EFI_UNSUPPORTED; 348 break; 349 case VAR_CHECK_POLICY_COMMAND_IS_ENABLED: 350 uefi_vars_mm_check_policy_is_enabled(uv, mhdr, mchk, func); 351 break; 352 case VAR_CHECK_POLICY_COMMAND_REGISTER: 353 if (uv->policy_locked) { 354 mchk->result = EFI_WRITE_PROTECTED; 355 } else { 356 uefi_vars_mm_check_policy_register(uv, mhdr, mchk, func); 357 } 358 break; 359 case VAR_CHECK_POLICY_COMMAND_LOCK: 360 uv->policy_locked = true; 361 mchk->result = EFI_SUCCESS; 362 break; 363 default: 364 mchk->result = EFI_UNSUPPORTED; 365 break; 366 } 367 368 uefi_trace_status(__func__, mchk->result); 369 return UEFI_VARS_STS_SUCCESS; 370 } 371