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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
package main
import (
"fmt"
"path/filepath"
"syscall"
)
// dupBasic opens a file, dups the fd, writes via the dup, closes both.
func dupBasic() error {
dir, cleanup, err := makeTempDir("dup-basic")
if err != nil {
return err
}
defer cleanup()
path := filepath.Join(dir, "dupfile.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)
newFd, err := syscall.Dup(fd)
if err != nil {
return fmt.Errorf("dup: %w", err)
}
defer syscall.Close(newFd)
if _, err := syscall.Write(newFd, []byte("via dup")); err != nil {
return fmt.Errorf("write via dup: %w", err)
}
return nil
}
// dupDup2 opens a file and duplicates the fd onto a specific target fd via dup2.
func dupDup2() error {
dir, cleanup, err := makeTempDir("dup-dup2")
if err != nil {
return err
}
defer cleanup()
path := filepath.Join(dir, "dup2file.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)
// Use a high fd number to avoid collisions.
targetFd := 500
if err := syscall.Dup2(fd, targetFd); err != nil {
return fmt.Errorf("dup2: %w", err)
}
defer syscall.Close(targetFd)
if _, err := syscall.Write(targetFd, []byte("via dup2")); err != nil {
return fmt.Errorf("write via dup2: %w", err)
}
return nil
}
// dupDup3 opens a file and duplicates the fd onto a specific target fd via dup3
// with O_CLOEXEC flag.
func dupDup3() error {
dir, cleanup, err := makeTempDir("dup-dup3")
if err != nil {
return err
}
defer cleanup()
path := filepath.Join(dir, "dup3file.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)
// Use a high fd number to avoid collisions.
targetFd := 501
if err := syscall.Dup3(fd, targetFd, syscall.O_CLOEXEC); err != nil {
return fmt.Errorf("dup3: %w", err)
}
defer syscall.Close(targetFd)
if _, err := syscall.Write(targetFd, []byte("via dup3")); err != nil {
return fmt.Errorf("write via dup3: %w", err)
}
return nil
}
// dupInvalidFd attempts to dup a very high invalid fd number.
// The syscall fails with EBADF, but ior should capture the enter_dup
// tracepoint because arguments are read on syscall entry.
func dupInvalidFd() error {
_, err := syscall.Dup(99999)
if err == nil {
return fmt.Errorf("expected dup of invalid fd to fail")
}
return nil
}
// dup2SameFd calls dup2 with the same fd for both oldfd and newfd.
// Per POSIX, dup2(fd, fd) is a no-op that returns fd without closing
// and reopening. ior should capture the enter_dup2 tracepoint.
func dup2SameFd() error {
dir, cleanup, err := makeTempDir("dup2-same-fd")
if err != nil {
return err
}
defer cleanup()
path := filepath.Join(dir, "dup2samefile.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)
if err := syscall.Dup2(fd, fd); err != nil {
return fmt.Errorf("dup2 same fd: %w", err)
}
return nil
}
// dup3InvalidFlags calls dup3 with an invalid flags value.
// dup3 only accepts O_CLOEXEC; any other flag causes EINVAL.
// ior should capture the enter_dup3 tracepoint.
func dup3InvalidFlags() error {
dir, cleanup, err := makeTempDir("dup3-invalid-flags")
if err != nil {
return err
}
defer cleanup()
path := filepath.Join(dir, "dup3flagsfile.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)
targetFd := 502
_, _, errno := syscall.Syscall(syscall.SYS_DUP3, uintptr(fd), uintptr(targetFd), 0xBAD)
if errno == 0 {
syscall.Close(targetFd)
return fmt.Errorf("expected dup3 with invalid flags to fail")
}
return nil
}
|