/src/cryptsetup/tests/fuzz/crypt2_load_fuzz.cc
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * cryptsetup LUKS2 fuzz target |
4 | | * |
5 | | * Copyright (C) 2022-2025 Daniel Zatovic <daniel.zatovic@gmail.com> |
6 | | * Copyright (C) 2022-2025 Red Hat, Inc. All rights reserved. |
7 | | */ |
8 | | |
9 | | extern "C" { |
10 | 5.46k | #define FILESIZE (16777216) |
11 | | #include "src/cryptsetup.h" |
12 | | #include "luks2/luks2.h" |
13 | | #include "crypto_backend/crypto_backend.h" |
14 | | #include "FuzzerInterface.h" |
15 | | |
16 | 21 | #define CHKSUM_ALG "sha256" |
17 | 21 | #define CHKSUM_SIZE 32 |
18 | | |
19 | | static bool fix_checksum_hdr(struct luks2_hdr_disk *hdr, const char *data, size_t len) |
20 | 21 | { |
21 | 21 | char *csum = (char *)&hdr->csum; |
22 | 21 | struct crypt_hash *hd = NULL; |
23 | 21 | bool r = false; |
24 | | |
25 | 21 | if (crypt_hash_init(&hd, CHKSUM_ALG)) |
26 | 0 | return false; |
27 | | |
28 | 21 | memset(csum, 0, LUKS2_CHECKSUM_L); |
29 | | |
30 | 21 | if (!crypt_hash_write(hd, data, len) && |
31 | 21 | !crypt_hash_final(hd, csum, CHKSUM_SIZE)) |
32 | 21 | r = true; |
33 | | |
34 | 21 | crypt_hash_destroy(hd); |
35 | 21 | return r; |
36 | 21 | } |
37 | | |
38 | | static bool calculate_checksum(const char *data, size_t size, struct luks2_hdr_disk *hdr_rw) |
39 | 4.50k | { |
40 | 4.50k | uint64_t hdr_size; |
41 | | |
42 | | /* Primary header cannot fit in data */ |
43 | 4.50k | if (sizeof(*hdr_rw) > size) |
44 | 0 | return false; |
45 | | |
46 | 4.50k | hdr_size = be64_to_cpu(((struct luks2_hdr_disk *)data)->hdr_size); |
47 | 4.50k | if (hdr_size > size || hdr_size <= sizeof(*hdr_rw)) |
48 | 4.47k | return false; |
49 | | |
50 | | /* Calculate checksum for primary header */ |
51 | 21 | memcpy(hdr_rw, data, sizeof(*hdr_rw)); |
52 | 21 | return fix_checksum_hdr(hdr_rw, data, (size_t)hdr_size); |
53 | 4.50k | } |
54 | | |
55 | | int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) |
56 | 5.46k | { |
57 | 5.46k | int fd, r = EXIT_FAILURE; |
58 | 5.46k | struct crypt_device *cd = NULL; |
59 | 5.46k | char name[] = "/tmp/test-script-fuzz.XXXXXX"; |
60 | 5.46k | struct luks2_hdr_disk hdr_rw; |
61 | 5.46k | size_t modified_data_size; |
62 | | |
63 | | /* if csum calculation fails, keep fuzzer running on original input */ |
64 | 5.46k | if (size >= sizeof(hdr_rw) && calculate_checksum((const char *)data, size, &hdr_rw)) |
65 | 21 | modified_data_size = sizeof(hdr_rw); |
66 | 5.44k | else |
67 | 5.44k | modified_data_size = 0; |
68 | | |
69 | | /* create file with LUKS header for libcryptsetup */ |
70 | 5.46k | fd = mkostemp(name, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC); |
71 | 5.46k | if (fd == -1) |
72 | 0 | return r; |
73 | | |
74 | | /* enlarge header */ |
75 | 5.46k | if (ftruncate(fd, FILESIZE) == -1) |
76 | 0 | goto out; |
77 | | |
78 | 5.46k | if (modified_data_size && |
79 | 21 | write_buffer(fd, &hdr_rw, modified_data_size) != (ssize_t)modified_data_size) |
80 | 0 | goto out; |
81 | | |
82 | 5.46k | if (write_buffer(fd, data + modified_data_size, size - modified_data_size) != (ssize_t)size) |
83 | 21 | goto out; |
84 | | |
85 | | /* Actual fuzzing */ |
86 | 5.44k | if (crypt_init(&cd, name) == 0) |
87 | 5.44k | (void)crypt_load(cd, CRYPT_LUKS2, NULL); |
88 | 5.44k | crypt_free(cd); |
89 | 5.44k | r = 0; |
90 | 5.46k | out: |
91 | 5.46k | close(fd); |
92 | 5.46k | unlink(name); |
93 | | |
94 | 5.46k | return r; |
95 | 5.44k | } |
96 | | } |