carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package rootstate
2
3import (
4 "os"
5 "path/filepath"
6 "strings"
7
8 "golang.org/x/sys/unix"
9)
10
11func ReadTrustedLink(path string) (string, error) {
12 if !filepath.IsAbs(path) || filepath.Clean(path) != path {
13 return "", os.ErrPermission
14 }
15 s, err := Open(filepath.Dir(path), false, true)
16 if err != nil {
17 return "", err
18 }
19 defer s.Close()
20 return s.(*directory).readLink(filepath.Base(path))
21}
22
23func (d *directory) readLink(name string) (string, error) {
24 if !component(strings.ReplaceAll(name, "@", "_")) {
25 return "", os.ErrPermission
26 }
27 if err := d.check(); err != nil {
28 return "", err
29 }
30 fd, err := unix.Openat(int(d.file.Fd()), name, unix.O_PATH|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
31 if err != nil {
32 return "", err
33 }
34 defer unix.Close(fd)
35 var st unix.Stat_t
36 if err := unix.Fstat(fd, &st); err != nil {
37 return "", err
38 }
39 if st.Uid != d.owner || st.Mode&unix.S_IFMT != unix.S_IFLNK || st.Nlink != 1 {
40 return "", os.ErrPermission
41 }
42 var buf [4096]byte
43 n, err := unix.Readlinkat(fd, "", buf[:])
44 if err != nil {
45 return "", err
46 }
47 if n == len(buf) {
48 return "", os.ErrPermission
49 }
50 return string(buf[:n]), nil
51}
52