Thanks for the suggestion. We’ll look into it.
Did some early investigation and it looks like hdparm
and smartctl
use ioctl(.., SG_IO, ..)
to issue direct requests to the underlying device.
I captured some requests with strace
.
The log for smartctl --all /dev/sda
:
ioctl(3, SG_IO, {interface_id='S', dxfer_direction=SG_DXFER_FROM_DEV, cmd_len=6, cmdp="\x12\x00\x00\x00\x24\x00", mx_sb_len=32, iovec_count=0, dxfer_len=36, timeout=60000, flags=0, dxferp="\x00\x00\x05\x02\x5b\x00\x00\x02\x41\x54\x41\x20\x20\x20\x20\x20\x53\x41\x4d\x53\x55\x4e\x47\x20\x48\x44\x33\x32\x32\x48\x4a\x20"..., status=0, masked_status=$
, msg_status=0, sb_len_wr=0, sbp="", host_status=0, driver_status=0, resid=0, duration=0, info=0}) = 0
ioctl(3, SG_IO, {interface_id='S', dxfer_direction=SG_DXFER_FROM_DEV, cmd_len=16, cmdp="\x85\x08\x0e\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xec\x00", mx_sb_len=32, iovec_count=0, dxfer_len=512, timeout=60000, flags=0, dxferp="\x40\x00\xff\x3f\x37\xc8\x10\x00\x56\x88\x2a\x02\x3f\x00\x00\x00\x00\x00\x00\x00\x31\x53\x41\x37\x39\x4a\x53\x44\x30$
x36\x35\x34"..., status=0, masked_status=0, msg_status=0, sb_len_wr=0, sbp="", host_status=0, driver_status=0, resid=0, duration=7, info=0}) = 0
ioctl(3, SG_IO, {interface_id='S', dxfer_direction=SG_DXFER_FROM_DEV, cmd_len=16, cmdp="\x85\x08\x0e\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xec\x00", mx_sb_len=32, iovec_count=0, dxfer_len=512, timeout=60000, flags=0, dxferp="\x40\x00\xff\x3f\x37\xc8\x10\x00\x56\x88\x2a\x02\x3f\x00\x00\x00\x00\x00\x00\x00\x31\x53\x41\x37\x39\x4a\x53\x44\x30$
x36\x35\x34"..., status=0, masked_status=0, msg_status=0, sb_len_wr=0, sbp="", host_status=0, driver_status=0, resid=0, duration=7, info=0}) = 0
The log for hdparm -S 1 /dev/sda
:
ioctl(3, SG_IO, {interface_id='S', dxfer_direction=SG_DXFER_NONE, cmd_len=16, cmdp="\x85\x06\x20\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x40\xe3\x00", mx_sb_len=32, iovec_count=0, dxfer_len=0, timeout=15000, flags=0, status=0x2, masked_status=0x1, msg_status=0, sb_len_wr=22, sbp="\x72\x01\x00\x1d\x00\x00\x00\x0e\x09\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x40\x50", host_status=0, driver_status=0x8, resid=0, duration=3924, info=SG_INFO_CHECK}) = 0
The struct passed in the request is defined here: https://elixir.bootlin.com/linux/latest/source/include/scsi/sg.h#L44
From some intial brainstorming, AppArmor and seccomp are probably not enough to implement proper mediation. We may need to have a trusted helper to act as a proxy. Though it’s still unclear how to do implement it in a way that’s transparent for the app. Perhaps @jdstrand can offer some ideas.