1 /*
2  * Check decoding of ioctl SG_IO v3 commands.
3  *
4  * Copyright (c) 2017 Dmitry V. Levin <ldv@altlinux.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "tests.h"
31 
32 #ifdef HAVE_SCSI_SG_H
33 
34 # include <inttypes.h>
35 # include <stdio.h>
36 # include <sys/ioctl.h>
37 # include <sys/uio.h>
38 # include <scsi/sg.h>
39 
40 int
main(void)41 main(void)
42 {
43 	ioctl(-1, SG_IO, 0);
44 	printf("ioctl(-1, SG_IO, NULL) = -1 EBADF (%m)\n");
45 
46 	TAIL_ALLOC_OBJECT_CONST_PTR(struct sg_io_hdr, sg_io);
47 	fill_memory(sg_io, sizeof(*sg_io));
48 
49 	const void *const efault = sg_io + 1;
50 	ioctl(-1, SG_IO, efault);
51 	printf("ioctl(-1, SG_IO, %p) = -1 EBADF (%m)\n", efault);
52 
53 	ioctl(-1, SG_IO, sg_io);
54 	printf("ioctl(-1, SG_IO, [%u]) = -1 EBADF (%m)\n", sg_io->interface_id);
55 
56 	TAIL_ALLOC_OBJECT_CONST_PTR(unsigned int, piid);
57 	*piid = (unsigned char) 'S';
58 	ioctl(-1, SG_IO, piid);
59 	printf("ioctl(-1, SG_IO, {interface_id='S', %p}) = -1 EBADF (%m)\n", piid + 1);
60 
61 	sg_io->interface_id = (unsigned char) 'S';
62 	sg_io->dxfer_direction = -2;
63 	sg_io->flags = -1U;
64 	sg_io->info = -1U;
65 	sg_io->dxferp = (void *) (unsigned long) 0xfacefeedfffffff1ULL;
66 	sg_io->cmdp = (void *) (unsigned long) 0xfacefeedfffffff2ULL;
67 	sg_io->sbp = (void *) (unsigned long) 0xfacefeedfffffff3ULL;
68 
69 	ioctl(-1, SG_IO, sg_io);
70 	printf("ioctl(-1, SG_IO, {interface_id='S'"
71 	       ", dxfer_direction=SG_DXFER_TO_DEV"
72 	       ", cmd_len=%u"
73 	       ", cmdp=%p"
74 	       ", mx_sb_len=%u"
75 	       ", iovec_count=%u"
76 	       ", dxfer_len=%u"
77 	       ", timeout=%u"
78 	       ", flags=SG_FLAG_DIRECT_IO|SG_FLAG_UNUSED_LUN_INHIBIT"
79 	       "|SG_FLAG_MMAP_IO|SG_FLAG_NO_DXFER"
80 	       "|SG_FLAG_Q_AT_TAIL|SG_FLAG_Q_AT_HEAD|0xfffeffc8"
81 	       ", dxferp=%p"
82 	       ", status=%#x"
83 	       ", masked_status=%#x"
84 	       ", msg_status=%#x"
85 	       ", sb_len_wr=%u"
86 	       ", sbp=%p"
87 	       ", host_status=%#x"
88 	       ", driver_status=%#x"
89 	       ", resid=%d"
90 	       ", duration=%u"
91 	       ", info=SG_INFO_CHECK|SG_INFO_DIRECT_IO|SG_INFO_MIXED_IO|0xfffffff8"
92 	       "}) = -1 EBADF (%m)\n",
93 	       sg_io->cmd_len,
94 	       sg_io->cmdp,
95 	       sg_io->mx_sb_len,
96 	       sg_io->iovec_count,
97 	       sg_io->dxfer_len,
98 	       sg_io->timeout,
99 	       sg_io->dxferp,
100 	       sg_io->status,
101 	       sg_io->masked_status,
102 	       sg_io->msg_status,
103 	       sg_io->sb_len_wr,
104 	       sg_io->sbp,
105 	       sg_io->host_status,
106 	       sg_io->driver_status,
107 	       sg_io->resid,
108 	       sg_io->duration);
109 
110 	sg_io->dxfer_direction = -3;
111 
112 	ioctl(-1, SG_IO, sg_io);
113 	printf("ioctl(-1, SG_IO, {interface_id='S'"
114 	       ", dxfer_direction=SG_DXFER_FROM_DEV"
115 	       ", cmd_len=%u"
116 	       ", cmdp=%p"
117 	       ", mx_sb_len=%u"
118 	       ", iovec_count=%u"
119 	       ", dxfer_len=%u"
120 	       ", timeout=%u"
121 	       ", flags=SG_FLAG_DIRECT_IO|SG_FLAG_UNUSED_LUN_INHIBIT"
122 	       "|SG_FLAG_MMAP_IO|SG_FLAG_NO_DXFER"
123 	       "|SG_FLAG_Q_AT_TAIL|SG_FLAG_Q_AT_HEAD|0xfffeffc8"
124 	       ", dxferp=%p"
125 	       ", status=%#x"
126 	       ", masked_status=%#x"
127 	       ", msg_status=%#x"
128 	       ", sb_len_wr=%u"
129 	       ", sbp=%p"
130 	       ", host_status=%#x"
131 	       ", driver_status=%#x"
132 	       ", resid=%d"
133 	       ", duration=%u"
134 	       ", info=SG_INFO_CHECK|SG_INFO_DIRECT_IO|SG_INFO_MIXED_IO|0xfffffff8"
135 	       "}) = -1 EBADF (%m)\n",
136 	       sg_io->cmd_len,
137 	       sg_io->cmdp,
138 	       sg_io->mx_sb_len,
139 	       sg_io->iovec_count,
140 	       sg_io->dxfer_len,
141 	       sg_io->timeout,
142 	       sg_io->dxferp,
143 	       sg_io->status,
144 	       sg_io->masked_status,
145 	       sg_io->msg_status,
146 	       sg_io->sb_len_wr,
147 	       sg_io->sbp,
148 	       sg_io->host_status,
149 	       sg_io->driver_status,
150 	       sg_io->resid,
151 	       sg_io->duration);
152 
153 	const struct iovec iov[] = {
154 		{
155 			.iov_base = (void *) efault - 2,
156 			.iov_len = 2
157 		}, {
158 			.iov_base = (void *) efault - 3,
159 			.iov_len = 4
160 		}
161 	};
162 	struct iovec *const t_iov = tail_memdup(iov, sizeof(iov));
163 
164 	sg_io->flags = 0x24;
165 	sg_io->info = 1;
166 	sg_io->dxfer_direction = -2;
167 
168 	sg_io->iovec_count = ARRAY_SIZE(iov);
169 	sg_io->dxfer_len = iov[0].iov_len + iov[1].iov_len - 1;
170 	sg_io->dxferp = t_iov;
171 
172 	ioctl(-1, SG_IO, sg_io);
173 	printf("ioctl(-1, SG_IO, {interface_id='S'"
174 	       ", dxfer_direction=SG_DXFER_TO_DEV"
175 	       ", cmd_len=%u"
176 	       ", cmdp=%p"
177 	       ", mx_sb_len=%u"
178 	       ", iovec_count=%u"
179 	       ", dxfer_len=%u"
180 	       ", timeout=%u"
181 	       ", flags=SG_FLAG_MMAP_IO|SG_FLAG_Q_AT_HEAD"
182 	       ", dxferp=[{iov_base=\"\\%o\\%o\", iov_len=%u}"
183 	       ", {iov_base=\"\\%o\\%o\\%o\", iov_len=%u}]"
184 	       ", status=%#x"
185 	       ", masked_status=%#x"
186 	       ", msg_status=%#x"
187 	       ", sb_len_wr=%u"
188 	       ", sbp=%p"
189 	       ", host_status=%#x"
190 	       ", driver_status=%#x"
191 	       ", resid=%d"
192 	       ", duration=%u"
193 	       ", info=SG_INFO_CHECK"
194 	       "}) = -1 EBADF (%m)\n",
195 	       sg_io->cmd_len,
196 	       sg_io->cmdp,
197 	       sg_io->mx_sb_len,
198 	       sg_io->iovec_count,
199 	       sg_io->dxfer_len,
200 	       sg_io->timeout,
201 	       *(unsigned char *) (iov[0].iov_base + 0),
202 	       *(unsigned char *) (iov[0].iov_base + 1),
203 	       (unsigned int) iov[0].iov_len,
204 	       *(unsigned char *) (iov[1].iov_base + 0),
205 	       *(unsigned char *) (iov[1].iov_base + 1),
206 	       *(unsigned char *) (iov[1].iov_base + 2),
207 	       (unsigned int) iov[1].iov_len,
208 	       sg_io->status,
209 	       sg_io->masked_status,
210 	       sg_io->msg_status,
211 	       sg_io->sb_len_wr,
212 	       sg_io->sbp,
213 	       sg_io->host_status,
214 	       sg_io->driver_status,
215 	       sg_io->resid,
216 	       sg_io->duration);
217 
218 	sg_io->flags = 0x11;
219 	sg_io->dxfer_direction = -3;
220 	sg_io->resid = sg_io->dxfer_len + 1;
221 
222 	ioctl(-1, SG_IO, sg_io);
223 	printf("ioctl(-1, SG_IO, {interface_id='S'"
224 	       ", dxfer_direction=SG_DXFER_FROM_DEV"
225 	       ", cmd_len=%u"
226 	       ", cmdp=%p"
227 	       ", mx_sb_len=%u"
228 	       ", iovec_count=%u"
229 	       ", dxfer_len=%u"
230 	       ", timeout=%u"
231 	       ", flags=SG_FLAG_DIRECT_IO|SG_FLAG_Q_AT_TAIL"
232 	       ", dxferp=[{iov_base=\"\\%o\\%o\", iov_len=%u}"
233 	       ", {iov_base=\"\\%o\\%o\\%o\", iov_len=%u}]"
234 	       ", status=%#x"
235 	       ", masked_status=%#x"
236 	       ", msg_status=%#x"
237 	       ", sb_len_wr=%u"
238 	       ", sbp=%p"
239 	       ", host_status=%#x"
240 	       ", driver_status=%#x"
241 	       ", resid=%d"
242 	       ", duration=%u"
243 	       ", info=SG_INFO_CHECK"
244 	       "}) = -1 EBADF (%m)\n",
245 	       sg_io->cmd_len,
246 	       sg_io->cmdp,
247 	       sg_io->mx_sb_len,
248 	       sg_io->iovec_count,
249 	       sg_io->dxfer_len,
250 	       sg_io->timeout,
251 	       *(unsigned char *) (iov[0].iov_base + 0),
252 	       *(unsigned char *) (iov[0].iov_base + 1),
253 	       (unsigned int) iov[0].iov_len,
254 	       *(unsigned char *) (iov[1].iov_base + 0),
255 	       *(unsigned char *) (iov[1].iov_base + 1),
256 	       *(unsigned char *) (iov[1].iov_base + 2),
257 	       (unsigned int) iov[1].iov_len,
258 	       sg_io->status,
259 	       sg_io->masked_status,
260 	       sg_io->msg_status,
261 	       sg_io->sb_len_wr,
262 	       sg_io->sbp,
263 	       sg_io->host_status,
264 	       sg_io->driver_status,
265 	       sg_io->resid,
266 	       sg_io->duration);
267 
268 	sg_io->flags = 0x10000;
269 	sg_io->info = 0xdeadbeef;
270 	sg_io->iovec_count = 0;
271 	sg_io->dxfer_len = 5;
272 	sg_io->resid = 1;
273 	sg_io->dxferp = (void *) efault - (sg_io->dxfer_len - sg_io->resid);
274 
275 	ioctl(-1, SG_IO, sg_io);
276 	printf("ioctl(-1, SG_IO, {interface_id='S'"
277 	       ", dxfer_direction=SG_DXFER_FROM_DEV"
278 	       ", cmd_len=%u"
279 	       ", cmdp=%p"
280 	       ", mx_sb_len=%u"
281 	       ", iovec_count=%u"
282 	       ", dxfer_len=%u"
283 	       ", timeout=%u"
284 	       ", flags=SG_FLAG_NO_DXFER"
285 	       ", dxferp=\"\\x%x\\x%x\\x%x\\x%x\""
286 	       ", status=%#x"
287 	       ", masked_status=%#x"
288 	       ", msg_status=%#x"
289 	       ", sb_len_wr=%u"
290 	       ", sbp=%p"
291 	       ", host_status=%#x"
292 	       ", driver_status=%#x"
293 	       ", resid=%d"
294 	       ", duration=%u"
295 	       ", info=SG_INFO_CHECK|SG_INFO_DIRECT_IO|SG_INFO_MIXED_IO|0xdeadbee8"
296 	       "}) = -1 EBADF (%m)\n",
297 	       sg_io->cmd_len,
298 	       sg_io->cmdp,
299 	       sg_io->mx_sb_len,
300 	       sg_io->iovec_count,
301 	       sg_io->dxfer_len,
302 	       sg_io->timeout,
303 	       *(unsigned char *) (sg_io->dxferp + 0),
304 	       *(unsigned char *) (sg_io->dxferp + 1),
305 	       *(unsigned char *) (sg_io->dxferp + 2),
306 	       *(unsigned char *) (sg_io->dxferp + 3),
307 	       sg_io->status,
308 	       sg_io->masked_status,
309 	       sg_io->msg_status,
310 	       sg_io->sb_len_wr,
311 	       sg_io->sbp,
312 	       sg_io->host_status,
313 	       sg_io->driver_status,
314 	       sg_io->resid,
315 	       sg_io->duration);
316 
317 	sg_io->flags = 2;
318 	sg_io->dxfer_direction = -4;
319 	sg_io->dxfer_len = 3;
320 	sg_io->resid = 1;
321 	sg_io->dxferp = (void *) efault - sg_io->dxfer_len;
322 
323 	ioctl(-1, SG_IO, sg_io);
324 	printf("ioctl(-1, SG_IO, {interface_id='S'"
325 	       ", dxfer_direction=SG_DXFER_TO_FROM_DEV"
326 	       ", cmd_len=%u"
327 	       ", cmdp=%p"
328 	       ", mx_sb_len=%u"
329 	       ", iovec_count=%u"
330 	       ", dxfer_len=%u"
331 	       ", timeout=%u"
332 	       ", flags=SG_FLAG_UNUSED_LUN_INHIBIT"
333 	       ", dxferp=\"\\x%x\\x%x\\x%x\" => dxferp=\"\\x%x\\x%x\""
334 	       ", status=%#x"
335 	       ", masked_status=%#x"
336 	       ", msg_status=%#x"
337 	       ", sb_len_wr=%u"
338 	       ", sbp=%p"
339 	       ", host_status=%#x"
340 	       ", driver_status=%#x"
341 	       ", resid=%d"
342 	       ", duration=%u"
343 	       ", info=SG_INFO_CHECK|SG_INFO_DIRECT_IO|SG_INFO_MIXED_IO|0xdeadbee8"
344 	       "}) = -1 EBADF (%m)\n",
345 	       sg_io->cmd_len,
346 	       sg_io->cmdp,
347 	       sg_io->mx_sb_len,
348 	       sg_io->iovec_count,
349 	       sg_io->dxfer_len,
350 	       sg_io->timeout,
351 	       *(unsigned char *) (sg_io->dxferp + 0),
352 	       *(unsigned char *) (sg_io->dxferp + 1),
353 	       *(unsigned char *) (sg_io->dxferp + 2),
354 	       *(unsigned char *) (sg_io->dxferp + 0),
355 	       *(unsigned char *) (sg_io->dxferp + 1),
356 	       sg_io->status,
357 	       sg_io->masked_status,
358 	       sg_io->msg_status,
359 	       sg_io->sb_len_wr,
360 	       sg_io->sbp,
361 	       sg_io->host_status,
362 	       sg_io->driver_status,
363 	       sg_io->resid,
364 	       sg_io->duration);
365 
366 	sg_io->flags = 0;
367 	sg_io->resid = sg_io->dxfer_len;
368 
369 	ioctl(-1, SG_IO, sg_io);
370 	printf("ioctl(-1, SG_IO, {interface_id='S'"
371 	       ", dxfer_direction=SG_DXFER_TO_FROM_DEV"
372 	       ", cmd_len=%u"
373 	       ", cmdp=%p"
374 	       ", mx_sb_len=%u"
375 	       ", iovec_count=%u"
376 	       ", dxfer_len=%u"
377 	       ", timeout=%u"
378 	       ", flags=0"
379 	       ", dxferp=\"\\x%x\\x%x\\x%x\""
380 	       ", status=%#x"
381 	       ", masked_status=%#x"
382 	       ", msg_status=%#x"
383 	       ", sb_len_wr=%u"
384 	       ", sbp=%p"
385 	       ", host_status=%#x"
386 	       ", driver_status=%#x"
387 	       ", resid=%d"
388 	       ", duration=%u"
389 	       ", info=SG_INFO_CHECK|SG_INFO_DIRECT_IO|SG_INFO_MIXED_IO|0xdeadbee8"
390 	       "}) = -1 EBADF (%m)\n",
391 	       sg_io->cmd_len,
392 	       sg_io->cmdp,
393 	       sg_io->mx_sb_len,
394 	       sg_io->iovec_count,
395 	       sg_io->dxfer_len,
396 	       sg_io->timeout,
397 	       *(unsigned char *) (sg_io->dxferp + 0),
398 	       *(unsigned char *) (sg_io->dxferp + 1),
399 	       *(unsigned char *) (sg_io->dxferp + 2),
400 	       sg_io->status,
401 	       sg_io->masked_status,
402 	       sg_io->msg_status,
403 	       sg_io->sb_len_wr,
404 	       sg_io->sbp,
405 	       sg_io->host_status,
406 	       sg_io->driver_status,
407 	       sg_io->resid,
408 	       sg_io->duration);
409 
410 	puts("+++ exited with 0 +++");
411 	return 0;
412 }
413 
414 #else
415 
416 SKIP_MAIN_UNDEFINED("HAVE_SCSI_SG_H")
417 
418 #endif
419