xref: /freebsd/tests/sys/cam/ctl/opcodes.sh (revision cfec995c87f39e59c80554b85625b4aaa8ddf8db)
1# SPDX-License-Identifier: BSD-2-Clause
2#
3# Copyright (c) 2024 Axcient
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS DOCUMENTATION IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26# Not Tested
27# * Allocation length, because sg3_utils 1.48 does not provide a way to set it.
28# * RCTD bit, because CTL does not support it.
29
30. $(atf_get_srcdir)/ctl.subr
31
32require_sg_opcodes_version()
33{
34	WANT=$1
35	HAVE=$(sg_opcodes -V 2>&1 | cut -w -f 3)
36	if [ `echo "$HAVE >= $WANT" | bc -l` = 0 ]; then
37		atf_skip "This test requires sg_opcodes $WANT or greater"
38	fi
39}
40
41# Query all supported opcodes.
42# NB: the fixture here may need to change frequently, any time CTL gains
43# support for new opcodes or service actions.
44atf_test_case all_opcodes cleanup
45all_opcodes_head()
46{
47	atf_set "descr" "REPORT SUPPORTED OPCODES can report all supported opcodes"
48	atf_set "require.user" "root"
49	atf_set "require.progs" sg_opcodes
50}
51all_opcodes_body()
52{
53	create_ramdisk
54
55	atf_check -o file:$(atf_get_srcdir)/all-supported-opcodes.txt sg_opcodes -p disk -nH /dev/$dev
56}
57all_opcodes_cleanup()
58{
59	cleanup
60}
61
62# Query support for a single opcode.  The REPORTING OPTIONS field will be 1 and
63# REQUESTED SERVICE ACTION will be zero.
64atf_test_case basic cleanup
65basic_head()
66{
67	atf_set "descr" "REPORT SUPPORTED OPCODES can report a single supported opcode"
68	atf_set "require.user" "root"
69	atf_set "require.progs" sg_opcodes
70}
71basic_body()
72{
73	create_ramdisk
74
75	atf_check -o inline:" 00     00 03 00 0a 28 1a ff ff  ff ff 00 ff ff 07\n" sg_opcodes -o 0x28 -p disk -nH /dev/$dev
76}
77basic_cleanup()
78{
79	cleanup
80}
81
82atf_test_case invalid_rep_opts cleanup
83invalid_rep_opts_head()
84{
85	atf_set "descr" "REPORT SUPPORTED OPCODES will fail gracefully if the REPORTING OPTIONS field is set to an invalid value"
86	atf_set "require.user" "root"
87	atf_set "require.progs" sg_opcodes
88}
89invalid_rep_opts_body()
90{
91	require_sg_opcodes_version 1.03
92	create_ramdisk
93
94	atf_check -o ignore -e ignore -s exit:5 sg_opcodes -o 0x28 -p disk -n --rep-opts=4 /dev/$dev
95}
96invalid_rep_opts_cleanup()
97{
98	cleanup
99}
100
101# Try to query support for an opcode that needs a service action, but without
102# specifying a service action.
103atf_test_case missing_service_action cleanup
104missing_service_action_head()
105{
106	atf_set "descr" "REPORT SUPPORTED OPCODES fails gracefully if the service action is omitted"
107	atf_set "require.user" "root"
108	atf_set "require.progs" sg_opcodes
109}
110missing_service_action_body()
111{
112	create_ramdisk
113
114	atf_check -e ignore -s exit:5 sg_opcodes -o 0x3c -p disk -n /dev/$dev
115}
116missing_service_action_cleanup()
117{
118	cleanup
119}
120
121# Regression test for CVE-2024-42416
122atf_test_case out_of_bounds_service_action cleanup
123out_of_bounds_service_action_head()
124{
125	atf_set "descr" "REPORT SUPPORTED OPCODES fails gracefully if the requested service action is out of bounds"
126	atf_set "require.user" "root"
127	atf_set "require.progs" sg_opcodes
128}
129out_of_bounds_service_action_body()
130{
131	require_sg_opcodes_version 1.03
132	create_ramdisk
133
134	# opcode 0 (Test Unit Ready) does not take service actions
135	# opcode 0x3c (Read Buffer(10)) does take service actions
136	for opcode in 0 0x3c; do
137		for ro in 2 3; do
138			for sa in 32 100 255 256 10000 65535; do
139				atf_check -s exit:5 -o ignore -e ignore sg_opcodes --rep-opts=$ro -o $opcode -s $sa -p disk -nH /dev/$dev
140			done
141		done
142	done
143}
144out_of_bounds_service_action_cleanup()
145{
146	cleanup
147}
148
149# Query support for an opcode that needs a service action
150atf_test_case service_action cleanup
151service_action_head()
152{
153	atf_set "descr" "REPORT SUPPORTED OPCODES can query an opcode that needs a service action"
154	atf_set "require.user" "root"
155	atf_set "require.progs" sg_opcodes
156}
157service_action_body()
158{
159	create_ramdisk
160
161	atf_check -o inline:" 00     00 03 00 0a 3c 02 00 ff  ff ff ff ff ff 07\n" sg_opcodes -o 0x3c -s 2 -p disk -nH /dev/$dev
162}
163service_action_cleanup()
164{
165	cleanup
166}
167
168# Try to query support for an opcode that does not need a service action, but
169# provide one anyway.
170atf_test_case unexpected_service_action cleanup
171unexpected_service_action_head()
172{
173	atf_set "descr" "REPORT SUPPORTED OPCODES fails gracefully if an extraneous service action is provided"
174	atf_set "require.user" "root"
175	atf_set "require.progs" sg_opcodes
176}
177unexpected_service_action_body()
178{
179	create_ramdisk
180
181	atf_check -e ignore -s exit:5 sg_opcodes -o 0x28 -s 1 -p disk -n /dev/$dev
182}
183unexpected_service_action_cleanup()
184{
185	cleanup
186}
187
188# Try to query support for an opcode that does not need a service action, but
189# provide one anyway.  Set REPORTING OPTIONS to 3.  This requests that the
190# command be reported as unsupported, but REQUEST SUPPORTED OPCODES will return
191# successfully.
192atf_test_case unexpected_service_action_ro3 cleanup
193unexpected_service_action_ro3_head()
194{
195	atf_set "descr" "REPORT SUPPORTED OPCODES fails gracefully if an extraneous service action is provided, using REPORTING OPTIONS 3"
196	atf_set "require.user" "root"
197	atf_set "require.progs" sg_opcodes
198}
199unexpected_service_action_ro3_body()
200{
201	require_sg_opcodes_version 1.03
202	create_ramdisk
203
204	atf_check -e ignore -o inline:" 00     00 01 00 00\n" sg_opcodes --rep-opts=3 -o 0xb7 -s 1 -p disk -nH /dev/$dev
205}
206unexpected_service_action_ro3_cleanup()
207{
208	cleanup
209}
210
211atf_test_case unsupported_opcode cleanup
212unsupported_opcode_head()
213{
214	atf_set "descr" "REPORT SUPPORTED OPCODES can report a single unsupported opcode"
215	atf_set "require.user" "root"
216	atf_set "require.progs" sg_opcodes
217}
218unsupported_opcode_body()
219{
220	create_ramdisk
221
222	atf_check -o inline:" 00     00 01 00 00\n" sg_opcodes -o 1 -p disk -nH /dev/$dev
223}
224unsupported_opcode_cleanup()
225{
226	cleanup
227}
228
229
230atf_init_test_cases()
231{
232	atf_add_test_case all_opcodes
233	atf_add_test_case basic
234	atf_add_test_case invalid_rep_opts
235	atf_add_test_case missing_service_action
236	atf_add_test_case out_of_bounds_service_action
237	atf_add_test_case service_action
238	atf_add_test_case unsupported_opcode
239	atf_add_test_case unexpected_service_action
240	atf_add_test_case unexpected_service_action_ro3
241}
242