...
1 package utils
2
3 import (
4 "encoding/binary"
5 "encoding/json"
6 "fmt"
7 "io"
8 "os"
9 "path/filepath"
10 "strconv"
11 "strings"
12 "unsafe"
13
14 securejoin "github.com/cyphar/filepath-securejoin"
15 "golang.org/x/sys/unix"
16 )
17
18 const (
19 exitSignalOffset = 128
20 )
21
22
23 var NativeEndian binary.ByteOrder
24
25 func init() {
26
27 i := uint32(1)
28 b := (*[4]byte)(unsafe.Pointer(&i))
29 if b[0] == 1 {
30 NativeEndian = binary.LittleEndian
31 } else {
32 NativeEndian = binary.BigEndian
33 }
34 }
35
36
37
38 func ExitStatus(status unix.WaitStatus) int {
39 if status.Signaled() {
40 return exitSignalOffset + int(status.Signal())
41 }
42 return status.ExitStatus()
43 }
44
45
46 func WriteJSON(w io.Writer, v interface{}) error {
47 data, err := json.Marshal(v)
48 if err != nil {
49 return err
50 }
51 _, err = w.Write(data)
52 return err
53 }
54
55
56
57
58
59
60
61 func CleanPath(path string) string {
62
63 if path == "" {
64 return ""
65 }
66
67
68
69 path = filepath.Clean(path)
70
71
72
73
74 if !filepath.IsAbs(path) {
75 path = filepath.Clean(string(os.PathSeparator) + path)
76
77 path, _ = filepath.Rel(string(os.PathSeparator), path)
78 }
79
80
81 return filepath.Clean(path)
82 }
83
84
85
86
87
88 func stripRoot(root, path string) string {
89
90 root, path = CleanPath("/"+root), CleanPath("/"+path)
91 switch {
92 case path == root:
93 path = "/"
94 case root == "/":
95
96 case strings.HasPrefix(path, root+"/"):
97 path = strings.TrimPrefix(path, root+"/")
98 }
99 return CleanPath("/" + path)
100 }
101
102
103
104
105
106
107
108 func WithProcfd(root, unsafePath string, fn func(procfd string) error) error {
109
110 unsafePath = stripRoot(root, unsafePath)
111 path, err := securejoin.SecureJoin(root, unsafePath)
112 if err != nil {
113 return fmt.Errorf("resolving path inside rootfs failed: %w", err)
114 }
115
116
117 fh, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC, 0)
118 if err != nil {
119 return fmt.Errorf("open o_path procfd: %w", err)
120 }
121 defer fh.Close()
122
123
124 procfd := "/proc/self/fd/" + strconv.Itoa(int(fh.Fd()))
125 if realpath, err := os.Readlink(procfd); err != nil {
126 return fmt.Errorf("procfd verification failed: %w", err)
127 } else if realpath != path {
128 return fmt.Errorf("possibly malicious path detected -- refusing to operate on %s", realpath)
129 }
130
131
132 return fn(procfd)
133 }
134
135
136
137 func SearchLabels(labels []string, query string) string {
138 for _, l := range labels {
139 parts := strings.SplitN(l, "=", 2)
140 if len(parts) < 2 {
141 continue
142 }
143 if parts[0] == query {
144 return parts[1]
145 }
146 }
147 return ""
148 }
149
150
151
152
153 func Annotations(labels []string) (bundle string, userAnnotations map[string]string) {
154 userAnnotations = make(map[string]string)
155 for _, l := range labels {
156 parts := strings.SplitN(l, "=", 2)
157 if len(parts) < 2 {
158 continue
159 }
160 if parts[0] == "bundle" {
161 bundle = parts[1]
162 } else {
163 userAnnotations[parts[0]] = parts[1]
164 }
165 }
166 return
167 }
168
View as plain text