/* * VAS_EBOOT -- GRand Unified Bootloader * Copyright (C) 2017 Free Software Foundation, Inc. * * VAS_EBOOT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VAS_EBOOT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VAS_EBOOT. If not, see . * * Verifiers helper. */ #include #include #include VAS_EBOOT_MOD_LICENSE ("GPLv3+"); struct VasEBoot_file_verifier *VasEBoot_file_verifiers; struct VasEBoot_verified { VasEBoot_file_t file; void *buf; }; typedef struct VasEBoot_verified *VasEBoot_verified_t; static void verified_free (VasEBoot_verified_t verified) { if (verified) { VasEBoot_free (verified->buf); VasEBoot_free (verified); } } static VasEBoot_ssize_t verified_read (struct VasEBoot_file *file, char *buf, VasEBoot_size_t len) { VasEBoot_verified_t verified = file->data; VasEBoot_memcpy (buf, (char *) verified->buf + file->offset, len); return len; } static VasEBoot_err_t verified_close (struct VasEBoot_file *file) { VasEBoot_verified_t verified = file->data; VasEBoot_file_close (verified->file); verified_free (verified); file->data = 0; /* Device and name are freed by parent. */ file->device = 0; file->name = 0; return VasEBoot_errno; } struct VasEBoot_fs verified_fs = { .name = "verified_read", .fs_read = verified_read, .fs_close = verified_close }; static VasEBoot_file_t VasEBoot_verifiers_open (VasEBoot_file_t io, enum VasEBoot_file_type type) { VasEBoot_verified_t verified = NULL; struct VasEBoot_file_verifier *ver; void *context; VasEBoot_file_t ret = 0; VasEBoot_err_t err; int defer = 0; VasEBoot_dprintf ("verify", "file: %s type: %d\n", io->name, type); if ((type & VAS_EBOOT_FILE_TYPE_MASK) == VAS_EBOOT_FILE_TYPE_SIGNATURE || (type & VAS_EBOOT_FILE_TYPE_MASK) == VAS_EBOOT_FILE_TYPE_VERIFY_SIGNATURE || (type & VAS_EBOOT_FILE_TYPE_SKIP_SIGNATURE)) return io; if (io->device->disk && (io->device->disk->dev->id == VAS_EBOOT_DISK_DEVICE_MEMDISK_ID || io->device->disk->dev->id == VAS_EBOOT_DISK_DEVICE_PROCFS_ID)) return io; FOR_LIST_ELEMENTS(ver, VasEBoot_file_verifiers) { enum VasEBoot_verify_flags flags = 0; err = ver->init (io, type, &context, &flags); if (err) goto fail_noclose; if (flags & VAS_EBOOT_VERIFY_FLAGS_DEFER_AUTH) { defer = 1; continue; } if (!(flags & VAS_EBOOT_VERIFY_FLAGS_SKIP_VERIFICATION)) break; } if (!ver) { if (defer) { VasEBoot_error (VAS_EBOOT_ERR_ACCESS_DENIED, N_("verification requested but nobody cares: %s"), io->name); goto fail_noclose; } /* No verifiers wanted to verify. Just return underlying file. */ return io; } ret = VasEBoot_malloc (sizeof (*ret)); if (!ret) { goto fail; } *ret = *io; ret->fs = &verified_fs; ret->not_easily_seekable = 0; if (ret->size >> (sizeof (VasEBoot_size_t) * VAS_EBOOT_CHAR_BIT - 1)) { VasEBoot_error (VAS_EBOOT_ERR_NOT_IMPLEMENTED_YET, N_("big file signature isn't implemented yet")); goto fail; } verified = VasEBoot_malloc (sizeof (*verified)); if (!verified) { goto fail; } verified->buf = VasEBoot_malloc (ret->size); if (!verified->buf) { goto fail; } if (VasEBoot_file_read (io, verified->buf, ret->size) != (VasEBoot_ssize_t) ret->size) { if (!VasEBoot_errno) VasEBoot_error (VAS_EBOOT_ERR_FILE_READ_ERROR, N_("premature end of file %s"), io->name); goto fail; } err = ver->write (context, verified->buf, ret->size); if (err) goto fail; err = ver->fini ? ver->fini (context) : VAS_EBOOT_ERR_NONE; if (err) goto fail; if (ver->close) ver->close (context); FOR_LIST_ELEMENTS_NEXT(ver, VasEBoot_file_verifiers) { enum VasEBoot_verify_flags flags = 0; err = ver->init (io, type, &context, &flags); if (err) goto fail_noclose; if (flags & VAS_EBOOT_VERIFY_FLAGS_SKIP_VERIFICATION || /* Verification done earlier. So, we are happy here. */ flags & VAS_EBOOT_VERIFY_FLAGS_DEFER_AUTH) continue; err = ver->write (context, verified->buf, ret->size); if (err) goto fail; err = ver->fini ? ver->fini (context) : VAS_EBOOT_ERR_NONE; if (err) goto fail; if (ver->close) ver->close (context); } verified->file = io; ret->data = verified; return ret; fail: if (ver->close) ver->close (context); fail_noclose: verified_free (verified); VasEBoot_free (ret); return NULL; } VasEBoot_err_t VasEBoot_verify_string (char *str, enum VasEBoot_verify_string_type type) { struct VasEBoot_file_verifier *ver; VasEBoot_dprintf ("verify", "string: %s, type: %d\n", str, type); FOR_LIST_ELEMENTS(ver, VasEBoot_file_verifiers) { VasEBoot_err_t err; err = ver->verify_string ? ver->verify_string (str, type) : VAS_EBOOT_ERR_NONE; if (err) return err; } return VAS_EBOOT_ERR_NONE; } void VasEBoot_verifiers_init (void) { VasEBoot_file_filter_register (VAS_EBOOT_FILE_FILTER_VERIFY, VasEBoot_verifiers_open); }