carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux
2
3package hostenv
4
5import (
6 "os"
7 "path/filepath"
8 "strings"
9 "testing"
10)
11
12// U3 (census condition 2 on runHostEnv): write's path is fixed, and the
13// file is written only through etc and etc/carlos held by descriptor,
14// each a real directory this user owns and nobody else can write.
15func TestWriteGoesOnlyThroughDirectoriesRootAloneCanWrite(t *testing.T) {
16 read := func(root string) string {
17 b, _ := os.ReadFile(filepath.Join(root, "etc", "carlos", "host.env"))
18 return string(b)
19 }
20 t.Run("lands whole, and replaces whole", func(t *testing.T) {
21 root := withHostEnvRoot(t)
22 if err := writeHostEnv(root, []byte("CARLOS_REGION=ie\n")); err != nil {
23 t.Fatal(err)
24 }
25 fi, err := os.Stat(filepath.Join(root, "etc", "carlos"))
26 if err != nil || fi.Mode().Perm()&0o022 != 0 || !fi.IsDir() {
27 t.Fatalf("created directory %v %v", fi, err)
28 }
29 first, err := os.Stat(filepath.Join(root, "etc", "carlos", "host.env"))
30 if err != nil {
31 t.Fatal(err)
32 }
33 if err := writeHostEnv(root, []byte("CARLOS_REGION=uk\n")); err != nil {
34 t.Fatal(err)
35 }
36 f, err := os.Stat(filepath.Join(root, "etc", "carlos", "host.env"))
37 if err != nil || f.Mode().Perm() != 0o600 || read(root) != "CARLOS_REGION=uk\n" {
38 t.Fatalf("host.env %v %v %q", f, err, read(root))
39 }
40 // Replaced by rename, not rewritten in place: a reader holding the
41 // old file never sees part of the new one.
42 if os.SameFile(first, f) {
43 t.Fatal("host.env was rewritten in place")
44 }
45 ents, _ := os.ReadDir(filepath.Join(root, "etc", "carlos"))
46 if len(ents) != 1 {
47 t.Fatalf("left behind: %v", ents)
48 }
49 })
50 for name, spoil := range map[string]func(t *testing.T, root string){
51 "a group-writable etc/carlos": func(t *testing.T, root string) {
52 dir := filepath.Join(root, "etc", "carlos")
53 if err := os.Mkdir(dir, 0o755); err != nil {
54 t.Fatal(err)
55 }
56 if err := os.Chmod(dir, 0o775); err != nil {
57 t.Fatal(err)
58 }
59 },
60 "a world-writable etc": func(t *testing.T, root string) {
61 if err := os.Chmod(filepath.Join(root, "etc"), 0o757); err != nil {
62 t.Fatal(err)
63 }
64 },
65 "an etc/carlos another user owns": func(t *testing.T, root string) {
66 if err := os.Mkdir(filepath.Join(root, "etc", "carlos"), 0o755); err != nil {
67 t.Fatal(err)
68 }
69 was := hostEnvOwner
70 hostEnvOwner = func() int { return was() + 1 }
71 t.Cleanup(func() { hostEnvOwner = was })
72 },
73 "a symlinked etc/carlos": func(t *testing.T, root string) {
74 elsewhere := safeDir(t)
75 if err := os.Symlink(elsewhere, filepath.Join(root, "etc", "carlos")); err != nil {
76 t.Fatal(err)
77 }
78 },
79 "a symlinked etc, an ancestor": func(t *testing.T, root string) {
80 elsewhere := safeDir(t)
81 if err := os.Mkdir(filepath.Join(elsewhere, "carlos"), 0o755); err != nil {
82 t.Fatal(err)
83 }
84 if err := os.Remove(filepath.Join(root, "etc")); err != nil {
85 t.Fatal(err)
86 }
87 if err := os.Symlink(elsewhere, filepath.Join(root, "etc")); err != nil {
88 t.Fatal(err)
89 }
90 },
91 } {
92 t.Run(name, func(t *testing.T) {
93 root := withHostEnvRoot(t)
94 spoil(t, root)
95 err := writeHostEnv(root, []byte("CARLOS_REGION=ie\n"))
96 if err == nil || !strings.Contains(err.Error(), "is not a directory only root can write") {
97 t.Fatalf("%v", err)
98 }
99 if got := read(root); got != "" {
100 t.Fatalf("wrote %q", got)
101 }
102 })
103 }
104}
105
106// safeDir is a directory that passes every check but the one under test:
107// this user's, 0755 whatever the umask, so a symlink to it is refused only
108// for being a symlink.
109func safeDir(t *testing.T) string {
110 t.Helper()
111 dir := t.TempDir()
112 if err := os.Chmod(dir, 0o755); err != nil {
113 t.Fatal(err)
114 }
115 return dir
116}
117