1ced56a00Sopenharmony_ci// SPDX-License-Identifier: MIT 2ced56a00Sopenharmony_ci/* 3ced56a00Sopenharmony_ci * Utility functions for the 'fsverity' program 4ced56a00Sopenharmony_ci * 5ced56a00Sopenharmony_ci * Copyright 2018 Google LLC 6ced56a00Sopenharmony_ci * 7ced56a00Sopenharmony_ci * Use of this source code is governed by an MIT-style 8ced56a00Sopenharmony_ci * license that can be found in the LICENSE file or at 9ced56a00Sopenharmony_ci * https://opensource.org/licenses/MIT. 10ced56a00Sopenharmony_ci */ 11ced56a00Sopenharmony_ci 12ced56a00Sopenharmony_ci#include "utils.h" 13ced56a00Sopenharmony_ci 14ced56a00Sopenharmony_ci#include <errno.h> 15ced56a00Sopenharmony_ci#include <fcntl.h> 16ced56a00Sopenharmony_ci#include <inttypes.h> 17ced56a00Sopenharmony_ci#include <limits.h> 18ced56a00Sopenharmony_ci#include <stdarg.h> 19ced56a00Sopenharmony_ci#include <sys/stat.h> 20ced56a00Sopenharmony_ci#include <unistd.h> 21ced56a00Sopenharmony_ci#ifdef _WIN32 22ced56a00Sopenharmony_ci# include <windows.h> 23ced56a00Sopenharmony_ci#endif 24ced56a00Sopenharmony_ci 25ced56a00Sopenharmony_ci/* ========== Memory allocation ========== */ 26ced56a00Sopenharmony_ci 27ced56a00Sopenharmony_civoid *xmalloc(size_t size) 28ced56a00Sopenharmony_ci{ 29ced56a00Sopenharmony_ci void *p = malloc(size); 30ced56a00Sopenharmony_ci 31ced56a00Sopenharmony_ci if (!p) 32ced56a00Sopenharmony_ci fatal_error("out of memory"); 33ced56a00Sopenharmony_ci return p; 34ced56a00Sopenharmony_ci} 35ced56a00Sopenharmony_ci 36ced56a00Sopenharmony_civoid *xzalloc(size_t size) 37ced56a00Sopenharmony_ci{ 38ced56a00Sopenharmony_ci return memset(xmalloc(size), 0, size); 39ced56a00Sopenharmony_ci} 40ced56a00Sopenharmony_ci 41ced56a00Sopenharmony_civoid *xmemdup(const void *mem, size_t size) 42ced56a00Sopenharmony_ci{ 43ced56a00Sopenharmony_ci return memcpy(xmalloc(size), mem, size); 44ced56a00Sopenharmony_ci} 45ced56a00Sopenharmony_ci 46ced56a00Sopenharmony_cichar *xstrdup(const char *s) 47ced56a00Sopenharmony_ci{ 48ced56a00Sopenharmony_ci return xmemdup(s, strlen(s) + 1); 49ced56a00Sopenharmony_ci} 50ced56a00Sopenharmony_ci 51ced56a00Sopenharmony_ci/* ========== Error messages and assertions ========== */ 52ced56a00Sopenharmony_ci 53ced56a00Sopenharmony_cistatic void do_error_msg(const char *format, va_list va, int err) 54ced56a00Sopenharmony_ci{ 55ced56a00Sopenharmony_ci fputs("ERROR: ", stderr); 56ced56a00Sopenharmony_ci vfprintf(stderr, format, va); 57ced56a00Sopenharmony_ci if (err) 58ced56a00Sopenharmony_ci fprintf(stderr, ": %s", strerror(err)); 59ced56a00Sopenharmony_ci putc('\n', stderr); 60ced56a00Sopenharmony_ci} 61ced56a00Sopenharmony_ci 62ced56a00Sopenharmony_civoid error_msg(const char *format, ...) 63ced56a00Sopenharmony_ci{ 64ced56a00Sopenharmony_ci va_list va; 65ced56a00Sopenharmony_ci 66ced56a00Sopenharmony_ci va_start(va, format); 67ced56a00Sopenharmony_ci do_error_msg(format, va, 0); 68ced56a00Sopenharmony_ci va_end(va); 69ced56a00Sopenharmony_ci} 70ced56a00Sopenharmony_ci 71ced56a00Sopenharmony_civoid error_msg_errno(const char *format, ...) 72ced56a00Sopenharmony_ci{ 73ced56a00Sopenharmony_ci va_list va; 74ced56a00Sopenharmony_ci 75ced56a00Sopenharmony_ci va_start(va, format); 76ced56a00Sopenharmony_ci do_error_msg(format, va, errno); 77ced56a00Sopenharmony_ci va_end(va); 78ced56a00Sopenharmony_ci} 79ced56a00Sopenharmony_ci 80ced56a00Sopenharmony_ci__noreturn void fatal_error(const char *format, ...) 81ced56a00Sopenharmony_ci{ 82ced56a00Sopenharmony_ci va_list va; 83ced56a00Sopenharmony_ci 84ced56a00Sopenharmony_ci va_start(va, format); 85ced56a00Sopenharmony_ci do_error_msg(format, va, 0); 86ced56a00Sopenharmony_ci va_end(va); 87ced56a00Sopenharmony_ci abort(); 88ced56a00Sopenharmony_ci} 89ced56a00Sopenharmony_ci 90ced56a00Sopenharmony_ci__noreturn void assertion_failed(const char *expr, const char *file, int line) 91ced56a00Sopenharmony_ci{ 92ced56a00Sopenharmony_ci fatal_error("Assertion failed: %s at %s:%d", expr, file, line); 93ced56a00Sopenharmony_ci} 94ced56a00Sopenharmony_ci 95ced56a00Sopenharmony_cistatic void print_libfsverity_error(const char *msg) 96ced56a00Sopenharmony_ci{ 97ced56a00Sopenharmony_ci error_msg("%s", msg); 98ced56a00Sopenharmony_ci} 99ced56a00Sopenharmony_ci 100ced56a00Sopenharmony_civoid install_libfsverity_error_handler(void) 101ced56a00Sopenharmony_ci{ 102ced56a00Sopenharmony_ci libfsverity_set_error_callback(print_libfsverity_error); 103ced56a00Sopenharmony_ci} 104ced56a00Sopenharmony_ci 105ced56a00Sopenharmony_ci/* ========== File utilities ========== */ 106ced56a00Sopenharmony_ci 107ced56a00Sopenharmony_cibool open_file(struct filedes *file, const char *filename, int flags, int mode) 108ced56a00Sopenharmony_ci{ 109ced56a00Sopenharmony_ci file->fd = open(filename, flags | O_BINARY, mode); 110ced56a00Sopenharmony_ci if (file->fd < 0) { 111ced56a00Sopenharmony_ci error_msg_errno("can't open '%s' for %s", filename, 112ced56a00Sopenharmony_ci (flags & O_ACCMODE) == O_RDONLY ? "reading" : 113ced56a00Sopenharmony_ci (flags & O_ACCMODE) == O_WRONLY ? "writing" : 114ced56a00Sopenharmony_ci "reading and writing"); 115ced56a00Sopenharmony_ci return false; 116ced56a00Sopenharmony_ci } 117ced56a00Sopenharmony_ci file->name = xstrdup(filename); 118ced56a00Sopenharmony_ci return true; 119ced56a00Sopenharmony_ci} 120ced56a00Sopenharmony_ci 121ced56a00Sopenharmony_cibool get_file_size(struct filedes *file, u64 *size_ret) 122ced56a00Sopenharmony_ci{ 123ced56a00Sopenharmony_ci struct stat stbuf; 124ced56a00Sopenharmony_ci 125ced56a00Sopenharmony_ci if (fstat(file->fd, &stbuf) != 0) { 126ced56a00Sopenharmony_ci error_msg_errno("can't stat file '%s'", file->name); 127ced56a00Sopenharmony_ci return false; 128ced56a00Sopenharmony_ci } 129ced56a00Sopenharmony_ci *size_ret = stbuf.st_size; 130ced56a00Sopenharmony_ci return true; 131ced56a00Sopenharmony_ci} 132ced56a00Sopenharmony_ci 133ced56a00Sopenharmony_cibool preallocate_file(struct filedes *file, u64 size) 134ced56a00Sopenharmony_ci{ 135ced56a00Sopenharmony_ci int res; 136ced56a00Sopenharmony_ci 137ced56a00Sopenharmony_ci if (size == 0) 138ced56a00Sopenharmony_ci return true; 139ced56a00Sopenharmony_ci#ifdef _WIN32 140ced56a00Sopenharmony_ci /* Not exactly the same as posix_fallocate(), but good enough... */ 141ced56a00Sopenharmony_ci res = _chsize_s(file->fd, size); 142ced56a00Sopenharmony_ci#else 143ced56a00Sopenharmony_ci res = posix_fallocate(file->fd, 0, size); 144ced56a00Sopenharmony_ci#endif 145ced56a00Sopenharmony_ci if (res != 0) { 146ced56a00Sopenharmony_ci error_msg_errno("preallocating %" PRIu64 "-byte file '%s'", 147ced56a00Sopenharmony_ci size, file->name); 148ced56a00Sopenharmony_ci return false; 149ced56a00Sopenharmony_ci } 150ced56a00Sopenharmony_ci return true; 151ced56a00Sopenharmony_ci} 152ced56a00Sopenharmony_ci 153ced56a00Sopenharmony_cibool full_read(struct filedes *file, void *buf, size_t count) 154ced56a00Sopenharmony_ci{ 155ced56a00Sopenharmony_ci while (count) { 156ced56a00Sopenharmony_ci int n = read(file->fd, buf, min(count, INT_MAX)); 157ced56a00Sopenharmony_ci 158ced56a00Sopenharmony_ci if (n < 0) { 159ced56a00Sopenharmony_ci error_msg_errno("reading from '%s'", file->name); 160ced56a00Sopenharmony_ci return false; 161ced56a00Sopenharmony_ci } 162ced56a00Sopenharmony_ci if (n == 0) { 163ced56a00Sopenharmony_ci error_msg("unexpected end-of-file on '%s'", file->name); 164ced56a00Sopenharmony_ci return false; 165ced56a00Sopenharmony_ci } 166ced56a00Sopenharmony_ci buf += n; 167ced56a00Sopenharmony_ci count -= n; 168ced56a00Sopenharmony_ci } 169ced56a00Sopenharmony_ci return true; 170ced56a00Sopenharmony_ci} 171ced56a00Sopenharmony_ci 172ced56a00Sopenharmony_cibool full_write(struct filedes *file, const void *buf, size_t count) 173ced56a00Sopenharmony_ci{ 174ced56a00Sopenharmony_ci while (count) { 175ced56a00Sopenharmony_ci int n = write(file->fd, buf, min(count, INT_MAX)); 176ced56a00Sopenharmony_ci 177ced56a00Sopenharmony_ci if (n < 0) { 178ced56a00Sopenharmony_ci error_msg_errno("writing to '%s'", file->name); 179ced56a00Sopenharmony_ci return false; 180ced56a00Sopenharmony_ci } 181ced56a00Sopenharmony_ci buf += n; 182ced56a00Sopenharmony_ci count -= n; 183ced56a00Sopenharmony_ci } 184ced56a00Sopenharmony_ci return true; 185ced56a00Sopenharmony_ci} 186ced56a00Sopenharmony_ci 187ced56a00Sopenharmony_cistatic int raw_pwrite(int fd, const void *buf, int count, u64 offset) 188ced56a00Sopenharmony_ci{ 189ced56a00Sopenharmony_ci#ifdef _WIN32 190ced56a00Sopenharmony_ci HANDLE h = (HANDLE)_get_osfhandle(fd); 191ced56a00Sopenharmony_ci OVERLAPPED pos = { .Offset = offset, .OffsetHigh = offset >> 32 }; 192ced56a00Sopenharmony_ci DWORD written = 0; 193ced56a00Sopenharmony_ci 194ced56a00Sopenharmony_ci /* Not exactly the same as pwrite(), but good enough... */ 195ced56a00Sopenharmony_ci if (!WriteFile(h, buf, count, &written, &pos)) { 196ced56a00Sopenharmony_ci errno = EIO; 197ced56a00Sopenharmony_ci return -1; 198ced56a00Sopenharmony_ci } 199ced56a00Sopenharmony_ci return written; 200ced56a00Sopenharmony_ci#else 201ced56a00Sopenharmony_ci return pwrite(fd, buf, count, offset); 202ced56a00Sopenharmony_ci#endif 203ced56a00Sopenharmony_ci} 204ced56a00Sopenharmony_ci 205ced56a00Sopenharmony_cibool full_pwrite(struct filedes *file, const void *buf, size_t count, 206ced56a00Sopenharmony_ci u64 offset) 207ced56a00Sopenharmony_ci{ 208ced56a00Sopenharmony_ci while (count) { 209ced56a00Sopenharmony_ci int n = raw_pwrite(file->fd, buf, min(count, INT_MAX), offset); 210ced56a00Sopenharmony_ci 211ced56a00Sopenharmony_ci if (n < 0) { 212ced56a00Sopenharmony_ci error_msg_errno("writing to '%s'", file->name); 213ced56a00Sopenharmony_ci return false; 214ced56a00Sopenharmony_ci } 215ced56a00Sopenharmony_ci buf += n; 216ced56a00Sopenharmony_ci count -= n; 217ced56a00Sopenharmony_ci offset += n; 218ced56a00Sopenharmony_ci } 219ced56a00Sopenharmony_ci return true; 220ced56a00Sopenharmony_ci} 221ced56a00Sopenharmony_ci 222ced56a00Sopenharmony_cibool filedes_close(struct filedes *file) 223ced56a00Sopenharmony_ci{ 224ced56a00Sopenharmony_ci int res; 225ced56a00Sopenharmony_ci 226ced56a00Sopenharmony_ci if (file->fd < 0) 227ced56a00Sopenharmony_ci return true; 228ced56a00Sopenharmony_ci res = close(file->fd); 229ced56a00Sopenharmony_ci if (res != 0) 230ced56a00Sopenharmony_ci error_msg_errno("closing '%s'", file->name); 231ced56a00Sopenharmony_ci file->fd = -1; 232ced56a00Sopenharmony_ci free(file->name); 233ced56a00Sopenharmony_ci file->name = NULL; 234ced56a00Sopenharmony_ci return res == 0; 235ced56a00Sopenharmony_ci} 236ced56a00Sopenharmony_ci 237ced56a00Sopenharmony_ciint read_callback(void *file, void *buf, size_t count) 238ced56a00Sopenharmony_ci{ 239ced56a00Sopenharmony_ci errno = 0; 240ced56a00Sopenharmony_ci if (!full_read(file, buf, count)) 241ced56a00Sopenharmony_ci return errno ? -errno : -EIO; 242ced56a00Sopenharmony_ci return 0; 243ced56a00Sopenharmony_ci} 244ced56a00Sopenharmony_ci 245ced56a00Sopenharmony_ci/* ========== String utilities ========== */ 246ced56a00Sopenharmony_ci 247ced56a00Sopenharmony_cistatic int hex2bin_char(char c) 248ced56a00Sopenharmony_ci{ 249ced56a00Sopenharmony_ci if (c >= '0' && c <= '9') 250ced56a00Sopenharmony_ci return c - '0'; 251ced56a00Sopenharmony_ci if (c >= 'a' && c <= 'f') 252ced56a00Sopenharmony_ci return 10 + (c - 'a'); 253ced56a00Sopenharmony_ci if (c >= 'A' && c <= 'F') 254ced56a00Sopenharmony_ci return 10 + (c - 'A'); 255ced56a00Sopenharmony_ci return -1; 256ced56a00Sopenharmony_ci} 257ced56a00Sopenharmony_ci 258ced56a00Sopenharmony_cibool hex2bin(const char *hex, u8 *bin, size_t bin_len) 259ced56a00Sopenharmony_ci{ 260ced56a00Sopenharmony_ci size_t i; 261ced56a00Sopenharmony_ci 262ced56a00Sopenharmony_ci if (strlen(hex) != 2 * bin_len) 263ced56a00Sopenharmony_ci return false; 264ced56a00Sopenharmony_ci 265ced56a00Sopenharmony_ci for (i = 0; i < bin_len; i++) { 266ced56a00Sopenharmony_ci int hi = hex2bin_char(*hex++); 267ced56a00Sopenharmony_ci int lo = hex2bin_char(*hex++); 268ced56a00Sopenharmony_ci 269ced56a00Sopenharmony_ci if (hi < 0 || lo < 0) 270ced56a00Sopenharmony_ci return false; 271ced56a00Sopenharmony_ci bin[i] = (hi << 4) | lo; 272ced56a00Sopenharmony_ci } 273ced56a00Sopenharmony_ci return true; 274ced56a00Sopenharmony_ci} 275ced56a00Sopenharmony_ci 276ced56a00Sopenharmony_cistatic char bin2hex_char(u8 nibble) 277ced56a00Sopenharmony_ci{ 278ced56a00Sopenharmony_ci ASSERT(nibble <= 0xf); 279ced56a00Sopenharmony_ci 280ced56a00Sopenharmony_ci if (nibble < 10) 281ced56a00Sopenharmony_ci return '0' + nibble; 282ced56a00Sopenharmony_ci return 'a' + (nibble - 10); 283ced56a00Sopenharmony_ci} 284ced56a00Sopenharmony_ci 285ced56a00Sopenharmony_civoid bin2hex(const u8 *bin, size_t bin_len, char *hex) 286ced56a00Sopenharmony_ci{ 287ced56a00Sopenharmony_ci size_t i; 288ced56a00Sopenharmony_ci 289ced56a00Sopenharmony_ci for (i = 0; i < bin_len; i++) { 290ced56a00Sopenharmony_ci *hex++ = bin2hex_char(bin[i] >> 4); 291ced56a00Sopenharmony_ci *hex++ = bin2hex_char(bin[i] & 0xf); 292ced56a00Sopenharmony_ci } 293ced56a00Sopenharmony_ci *hex = '\0'; 294ced56a00Sopenharmony_ci} 295