aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/app/shim.go
blob: 00f711a1a347a90099f00544746abc06fc3be266 (plain)
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
package app

import (
	"bytes"
	"encoding/base64"
	"encoding/gob"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"
)

const shimPayload = "FORTIFY_SHIM_PAYLOAD"

func (a *app) shimPayloadEnv() string {
	r := &bytes.Buffer{}
	enc := base64.NewEncoder(base64.StdEncoding, r)

	if err := gob.NewEncoder(enc).Encode(a.seal.command); err != nil {
		// should be unreachable
		panic(err)
	}

	_ = enc.Close()
	return shimPayload + "=" + r.String()
}

// TryShim attempts the early hidden launcher shim path
func TryShim() {
	// environment variable contains encoded argv
	if r, ok := os.LookupEnv(shimPayload); ok {
		// everything beyond this point runs as target user
		// proceed with caution!

		// parse base64 revealing underlying gob stream
		dec := base64.NewDecoder(base64.StdEncoding, strings.NewReader(r))

		// decode argv gob stream
		var argv []string
		if err := gob.NewDecoder(dec).Decode(&argv); err != nil {
			fmt.Println("fortify-shim: cannot decode shim payload:", err)
			os.Exit(1)
		}

		// remove payload variable since the child does not need to see it
		if err := os.Unsetenv(shimPayload); err != nil {
			fmt.Println("fortify-shim: cannot unset shim payload:", err)
			// not fatal, do not fail
		}

		// look up argv0
		var argv0 string

		if len(argv) > 0 {
			// look up program from $PATH
			if p, err := exec.LookPath(argv[0]); err != nil {
				fmt.Printf("%s not found: %s\n", argv[0], err)
				os.Exit(1)
			} else {
				argv0 = p
			}
		} else {
			// no argv, look up shell instead
			if argv0, ok = os.LookupEnv("SHELL"); !ok {
				fmt.Println("fortify-shim: no command was specified and $SHELL was unset")
				os.Exit(1)
			}

			argv = []string{argv0}
		}

		// exec target process
		if err := syscall.Exec(argv0, argv, os.Environ()); err != nil {
			fmt.Println("fortify-shim: cannot execute shim payload:", err)
			os.Exit(1)
		}

		// unreachable
		os.Exit(1)
		return
	}
}