xref: /freebsd/tests/sys/geom/class/eli/unaligned_io.c (revision 19fae0f66023a97a9b464b3beeeabb2081f575b3)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2023 The FreeBSD Foundation
5  *
6  * This software was developed by Mark Johnston under sponsorship from
7  * the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are
11  * met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 /*
32  * Idea from a test case by Andrew "RhodiumToad" Gierth in Bugzilla PR 271766.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/disk.h>
37 #include <sys/mman.h>
38 
39 #include <crypto/cryptodev.h>
40 
41 #include <err.h>
42 #include <fcntl.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 
47 int
48 main(int argc, char **argv)
49 {
50 	const char *disk;
51 	char *buf1, *buf2;
52 	off_t disksz;
53 	size_t bufsz, iosz;
54 	ssize_t n;
55 	unsigned int offsets, secsz;
56 	int fd;
57 
58 	if (argc != 2)
59 		errx(1, "Usage: %s <disk>", argv[0]);
60 	disk = argv[1];
61 
62 	fd = open(disk, O_RDWR);
63 	if (fd < 0)
64 		err(1, "open(%s)", disk);
65 
66 	if (ioctl(fd, DIOCGSECTORSIZE, &secsz) != 0)
67 		err(1, "ioctl(DIOCGSECTORSIZE)");
68 	if (secsz == 0)
69 		errx(1, "ioctl(DIOCGSECTORSIZE) returned 0");
70 	if (ioctl(fd, DIOCGMEDIASIZE, &disksz) != 0)
71 		err(1, "ioctl(DIOCGMEDIASIZE)");
72 	if (disksz / secsz < 2)
73 		errx(1, "disk needs to be at least 2 sectors in size");
74 	iosz = 2 * secsz;
75 
76 	bufsz = iosz + secsz;
77 	buf1 = mmap(NULL, bufsz, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
78 	    -1, 0);
79 	if (buf1 == MAP_FAILED)
80 		err(1, "mmap");
81 	buf2 = mmap(NULL, bufsz, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
82 	    -1, 0);
83 	if (buf2 == MAP_FAILED)
84 		err(1, "mmap");
85 
86 	arc4random_buf(buf1, bufsz);
87 	n = pwrite(fd, buf1, bufsz, 0);
88 	if (n < 0 || (size_t)n != bufsz)
89 		err(1, "pwrite");
90 
91 	/*
92 	 * Limit the number of offsets we test with, to avoid spending too much
93 	 * time when the sector size is large.
94 	 */
95 	offsets = MAX(EALG_MAX_BLOCK_LEN, HMAC_MAX_BLOCK_LEN) + 1;
96 
97 	/*
98 	 * Read test: read the first 2 sectors into buf1, then do the same with
99 	 * buf2, except at varying offsets into buf2.  After each read, compare
100 	 * the buffers and make sure they're identical.  This exercises corner
101 	 * cases in the crypto layer's buffer handling.
102 	 */
103 	n = pread(fd, buf1, iosz, 0);
104 	if (n < 0 || (size_t)n != iosz)
105 		err(1, "pread");
106 	for (unsigned int i = 0; i < offsets; i++) {
107 		n = pread(fd, buf2 + i, iosz, 0);
108 		if (n < 0 || (size_t)n != iosz)
109 			err(1, "pread");
110 		if (memcmp(buf1, buf2 + i, iosz) != 0)
111 			errx(1, "read mismatch at offset %u/%u", i, secsz);
112 	}
113 
114 	/*
115 	 * Write test.  Try writing buffers at various alignments, and verify
116 	 * that we read back what we wrote.
117 	 */
118 	arc4random_buf(buf1, bufsz);
119 	for (unsigned int i = 0; i < offsets; i++) {
120 		n = pwrite(fd, buf1 + i, iosz, 0);
121 		if (n < 0 || (size_t)n != iosz)
122 			err(1, "pwrite");
123 		n = pread(fd, buf2, iosz, 0);
124 		if (n < 0 || (size_t)n != iosz)
125 			err(1, "pread");
126 		if (memcmp(buf1 + i, buf2, iosz) != 0)
127 			errx(1, "write mismatch at offset %u/%u", i, secsz);
128 	}
129 
130 	return (0);
131 }
132