summaryrefslogtreecommitdiff
path: root/vendor/github.com/sarnowski/mitigation/mitigation.go
blob: a1110e462bbea379555406af0e575b76f0f08bc1 (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
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
/*
Package mitigation provides the possibility to prevent damage through bugs or exploits.

The package uses multiple techniques to mitigate damage:
	- privilege revocation: switch to an unprivileged user
	- chroot jail: restrict filesystem access
	- defined environment: reset all environment variables

The following prerequisites are nessecary:
	- The application must run as root
	- You need to provide a valid user id
	- You need to provide a valid group id
	- You need to provide an existing path

Activate() will not return any error. It will panic as soon as anything
goes wrong because there is no good way to recover. To provide a sensible
fallback you can use the CanActivate() function.

WARNING: Windows is not supported. Windows has no equivalents for the used
techniques.

WARNING: Linux is not POSIX compatible and therefor setuid() only changes the
user ID of the current thread. At the time, there is no way to safely use
this within go as there may already be other threads spawned at the time
this library is called. More about this issue here:
	http://code.google.com/p/go/issues/detail?id=1435
	http://groups.google.com/group/golang-nuts/browse_thread/thread/059597aafdd84a0e

The following table summarizes the behaviours:
	openbsd: safe
	freebsd: safe
	darwin:  safe
	linux:   unsafe
	windows: not supported

*/
package mitigation

import (
	"os"
	"runtime"
	"syscall"
)

// Checks if it is possible to activate the mitigation.
func CanActivate() bool {
	if runtime.GOOS == "windows" || runtime.GOARCH == "arm" {
		return false
	}

	uid := syscall.Getuid()
	return uid == 0
}

// Activates the mitigation measurements.
func Activate(uid int, gid int, path string) {
	if !CanActivate() {
		panic("Cannot activate mitigation measurements!")
	}

	// chroot directory
	err := syscall.Chroot(path)
	if err != nil {
		panic(err)
	}

	// change directory to new /
	err = syscall.Chdir("/")
	if err != nil {
		panic(err)
	}

	// drop all other groups
	err = syscall.Setgroups([]int{gid})
	if err != nil {
		panic(err)
	}

	// verify the empty group list
	gids, err := syscall.Getgroups()
	if err != nil {
		panic("Could not read groups!")
	}
	if len(gids) > 1 {
		panic("Could not drop groups!")
	} else if len(gids) == 1 {
		if gids[0] != gid {
			panic("Could not drop foreign groups!")
		}
	}

	// change group
	err = syscall.Setgid(gid)
	if err != nil {
		panic(err)
	}

	// verify the group change
	ngid := syscall.Getgid()
	if ngid != gid {
		panic("Could not change group id!")
	}

	// change user
	err = syscall.Setuid(uid)
	if err != nil {
		panic(err)
	}

	// verify the user change
	nuid := syscall.Getuid()
	if nuid != uid {
		panic("Could not change user id!")
	}

	// now drop all environment variables
	os.Clearenv()
}