Manual review found missing bounds checks in print_scn_pdu and qry_rsp_handle; no saved analyzer diagnostic directly reports these bugs. Both handlers read a TLV header before proving it is present. Clamping an oversized value can underflow the remaining length or accept a truncated attribute. Query handling also reads a missing status word and can discard the old ACL before noticing bad input. Validate every TLV header, value length and alignment before processing any attributes. Check and decode the response status in host byte order. Reject malformed tails before modifying names or replacing the ACL. Add an isolated Ginkgo probe of both production handlers with payloads ending at a guard page. Cover short headers/status, oversized and unaligned values, malformed tails, delimiters and valid ACL replacement.
SCST component tests
Ginkgo/Gomega tests exercise management through scstadmin, SCSI commands
through sg3_utils, and data verification through fio. Transports are
scst_local and TCP iSCSI with a separate initiator controlled over SSH.
For GitHub Actions, see CI.
Setup and run
Use a disposable Linux target with root access, an empty SCST configuration,
Go as specified in go.mod, Perl and kmod utilities. Building requires
SCST build dependencies, Perl ExtUtils::MakeMaker and running-kernel headers.
Install dependencies separately; do not run another SCST manager concurrently.
From the repository root:
cp tests/ginkgo/config.example.json tests/ginkgo/config.local.json
Set disposable_host=true and choose admin_command. ["scstadmin"] uses the
installed utility, including with ginkgo-test-build. To test this checkout:
"admin_command": [
"/usr/bin/perl",
"-I/absolute/checkout/scstadmin/scstadmin.sysfs/scst-1.0.0/lib",
"/absolute/checkout/scstadmin/scstadmin.sysfs/scstadmin"
]
Validate the config, then run as root:
make ginkgo-config GINKGO_CONFIG=tests/ginkgo/config.local.json
make ginkgo-test-build GINKGO_CONFIG=tests/ginkgo/config.local.json
# Reuse modules already built for the running kernel:
make ginkgo-test GINKGO_CONFIG=tests/ginkgo/config.local.json
Use KDIR=/absolute/kernel/build for headers elsewhere. Both live targets
load checkout modules, replacing existing SCST modules only if unconfigured.
Successful cleanup unloads SCST modules; standard kernel dependencies and
runtime directories under /var/lib/scst remain.
Select tests
The default is GINKGO_LABEL='local && basic'. Combine local or iscsi
with basic (management), scsi or io; add fileio or blockio to narrow
the backend. For example, local && io && fileio needs no physical disk.
GINKGO_FOCUS additionally filters spec names by regexp.
GitHub pull requests use the ci-pr label set; pushes to master use ci-push.
Their definitions live in labels.json, shared
by the local runner and VM supervisor:
| Label set | Ginkgo expression |
|---|---|
ci-pr |
`(basic |
ci-push |
!race && !manual |
Each set aliases a whole filter; its definition combines ordinary Ginkgo labels.
Pass either a set name or a Ginkgo expression as GINKGO_LABEL. Manual workflow
runs use an empty filter and select all specs, including manual and
timing-dependent race scenarios. The manual label excludes a spec from
both automatic CI sets. Other stress tests remain in ci-push.
# List the pull-request selection:
make ginkgo-list GINKGO_LABEL=ci-pr
# List the master push selection:
make ginkgo-list GINKGO_LABEL=ci-push
# List every spec and its labels without accessing either host:
make ginkgo-list GINKGO_LABEL=''
# All specs; prepare both hosts and a block device first:
make ginkgo-test-build GINKGO_CONFIG=tests/ginkgo/config.local.json GINKGO_LABEL=''
An empty label filter selects all specs. clear-config tests invoke global
scstadmin -clear_config -force. Only selected transport groups access hosts.
Local teardown finishes before iSCSI setup; an empty selection or suite
failure stops the run. Parallel runs are unsupported: use the same
lock_file and runner user on each host.
Configuration
config.example.json lists defaults; ginkgo-config
validates and prints the effective config. The named JSON file overrides
defaults without implicit user overrides. GINKGO_CONFIG is relative to the
Make invocation directory; relative config paths resolve against the JSON
file, except interpreter arguments, which need absolute paths. Local profiles
are ignored by Git; the initiator lock path must be absolute.
backing_dir selects an existing directory for temporary fileio images;
empty uses the artifact directory. Tests never adopt existing backing files.
Avoid whitespace, commas, semicolons, quotes, braces and backslashes in backing
paths. Set fileio_thin_provisioning=false if the filesystem cannot support
the TP-enabled cases, including UNMAP. stress_iterations and scale_luns
control lifecycle repetition and many-LUN coverage.
Two-host iSCSI
Run Ginkgo on the target. Add iscsi from
config.iscsi.example.json, replace its addresses
and set both disposable_host flags to true.
- Target: OpenSSH client,
pgrep, no runningiscsi-scstd, and a local IPv4 address with a free TCP port reachable from the initiator. SHA256/SHA3-256 CHAP requires kernel AF_ALG hash support. - Initiator: OpenSSH server, Python 3,
pgrep, Open-iSCSI with SHA3-256node.session.auth.chap_algssupport, runningiscsid, loadediscsi_tcpand no existing sessions. SCST is not needed here. - Set up noninteractive root SSH from target to initiator with a verified host
key.
identity_fileis on the target; empty uses normal SSH key selection.iscsi.login_timeoutmust be whole seconds belowcommand_timeout.
The suite owns its target daemon and initiator sessions/node/iface records. It preserves existing records and leaves initiator services and modules loaded.
CHAP configuration tests require Python 3 on the target and the ability to run file-access checks under an unprivileged UID/GID.
The isolated internal/chap suite tests the production CHAP implementation
with deterministic entropy I/O: length bounds, short reads, interruptions and
failure cleanup. It runs through ginkgo-check and requires cc. Interface
headers are prepared in a temporary directory; no daemon or storage is used.
Run it separately with go test ./internal/chap from this directory.
The isolated internal/isns suite checks production iSNS handlers against
malformed payloads ending at a guard page, including preservation of existing
ACLs. It also runs through ginkgo-check; use go test ./internal/isns to
run it separately. It requires cc and opens no sockets.
SCSI and I/O
Install Python 3, util-linux and sg3_utils on the command host: the target for
local, the initiator for iscsi. I/O also needs fio and kernel io_uring
support there, plus lsblk and wipefs on the target for blockio preflight.
Fio verifies CRC32C data using three concurrent 4K, 64K and 128K jobs in disjoint regions; see the shared profile. It checks completed I/O, not performance. Readback checks do not verify data persistence across a crash or power loss.
The user specs run usr/fileio/fileio_tgt over scst_local with a fault
hook preloaded: the handler either forks or returns an invalid READ CAPACITY
block length. READ CAPACITY, reads and writes must stay correct afterwards.
Before Linux 5.9, the fork fixture applies the required MADV_DONTFORK to all
active data buffers and checks that protection was applied before forking.
On Linux 5.9 and later it uses no such protection, exercising page pinning.
Both paths require correct geometry and data; neither depends on selecting a
particular cached buffer to produce an error. The invalid-capacity cases
require CHECK CONDITION with sense 0b/44/00 on every kernel.
The specs need a C compiler on the target to build the hook;
ginkgo-test-build also builds usr, and the local suite loads scst_user.
The fork spec is labelled manual; the invalid-capacity specs remain in
smoke. To select only the fork spec on a disposable local target:
make ginkgo-list GINKGO_LABEL='user && manual'
make ginkgo-test-build GINKGO_CONFIG=tests/ginkgo/config.local.json GINKGO_LABEL='user && manual'
For manual VM runs on Linux 5.8 or 5.9, see CI reproduction.
The unmap specs exercise temporary thin-provisioned fileio exports over
scst_local and TCP iSCSI. They require util-linux fallocate on the target
and a backing filesystem that supports hole punching.
Setting fileio_thin_provisioning=false skips these specs.
# Both scst_local and TCP iSCSI, using previously built modules:
make ginkgo-test GINKGO_CONFIG=tests/ginkgo/config.local.json GINKGO_LABEL='unmap'
| fio backend | Sector size | Access |
|---|---|---|
vdisk_fileio |
512 bytes | direct=0, backend o_direct=0, temporary file |
vdisk_blockio |
4096 bytes | direct=1, configured target block device |
Buffered runs flush and verify again with direct I/O. io.region_mb sets MiB
per job (default 64); io.timeout limits each fio invocation (default 3m).
Blockio overwrites the first 3 * io.region_mb MiB (default 192 MiB) of
io.block_device on the target, with no data restoration. Set this device
explicitly, preferably by /dev/disk/by-id/; missing configuration fails the
selected tests. It must be writable, large enough, 4 KiB aligned in size and
free of partitions, holders, mounts and signatures. No loop device is created.
Checks and recovery
make ginkgo-check runs framework unit tests, vet and suite compilation;
it does not access SCST or remote hosts. Neither it nor ginkgo-list proves
live behavior. Use the Make targets for live runs: plain go test skips specs
without SCST_TEST_CONFIG and needs -count=1 -timeout=0 when running them.
Cleanup removes owned sessions/configuration before closing devices, deleting backing files and unloading modules. A failure or interrupted command stops the run and may retain modules, files and the daemon. Inspect and recover the affected hosts before retrying; never remove a lock file to bypass a held lock.
The printed artifact directory under report_dir contains effective config,
command logs, JSON/JUnit reports and scenario inputs. I/O adds rendered jobs
and fio results; iSCSI adds SSH, initiator and daemon logs, which may contain
test CHAP credentials. Kernel-log collection depends on the selected specs;
retain kernel logs separately when investigating failures.