1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package main
import (
"fmt"
"path/filepath"
"syscall"
"golang.org/x/sys/unix"
)
// fionread is the FIONREAD ioctl request (number of bytes available to read).
// golang.org/x/sys/unix does not export it as a portable constant, so we define
// it here. The value 0x541B is shared by the architectures this project targets
// (amd64, arm64; see scenario_mountfs.go's listns arch table).
const fionread = 0x541B
// ioctlBasic issues a benign, deterministic ioctl on a known fd so the
// enter_ioctl tracepoint fires under our control rather than only implicitly
// (via the Go runtime / terminal). ioctl is FamilyFS / KindFd (fd@arg0), so
// the captured event resolves the fd to the temp file path.
//
// We open a regular temp file and call FIONREAD via unix.IoctlGetInt, which
// reports the number of bytes available to read. On a regular file this is a
// harmless query that does not mutate state; we ignore its result. The file is
// cleaned up via the deferred cleanup.
func ioctlBasic() error {
dir, cleanup, err := makeTempDir("ioctl-basic")
if err != nil {
return err
}
defer cleanup()
path := filepath.Join(dir, "ioctlfile.txt")
fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644)
if err != nil {
return fmt.Errorf("open: %w", err)
}
defer syscall.Close(fd)
// FIONREAD on a regular file is safe and portable. Even if the kernel
// rejects it for this fd type, the enter_ioctl tracepoint fires on syscall
// entry, so coverage holds regardless of the return value.
if _, err := unix.IoctlGetInt(fd, fionread); err != nil {
// Tolerated: the sys_enter_ioctl tracepoint has already fired.
return nil
}
return nil
}
|