forked from snapcore/snapd
/
backend.go
131 lines (117 loc) · 4.42 KB
/
backend.go
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
119
120
121
122
123
124
125
126
127
128
129
130
131
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2016 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
// Package seccomp implements integration between snappy and
// ubuntu-core-launcher around seccomp.
//
// Snappy creates so-called seccomp profiles for each application (for each
// snap) present in the system. Upon each execution of ubuntu-core-launcher,
// the profile is read and "compiled" to an eBPF program and injected into the
// kernel for the duration of the execution of the process.
//
// There is no binary cache for seccomp, each time the launcher starts an
// application the profile is parsed and re-compiled.
//
// The actual profiles are stored in /var/lib/snappy/seccomp/profiles.
// This directory is hard-coded in ubuntu-core-launcher.
package seccomp
import (
"bytes"
"fmt"
"os"
"github.com/snapcore/snapd/dirs"
"github.com/snapcore/snapd/interfaces"
"github.com/snapcore/snapd/osutil"
"github.com/snapcore/snapd/snap"
)
// Backend is responsible for maintaining seccomp profiles for ubuntu-core-launcher.
type Backend struct{}
// Name returns the name of the backend.
func (b *Backend) Name() string {
return "seccomp"
}
// Setup creates seccomp profiles specific to a given snap.
// The snap can be in developer mode to make security violations non-fatal to
// the offending application process.
//
// This method should be called after changing plug, slots, connections between
// them or application present in the snap.
func (b *Backend) Setup(snapInfo *snap.Info, devMode bool, repo *interfaces.Repository) error {
snapName := snapInfo.Name()
// Get the snippets that apply to this snap
snippets, err := repo.SecuritySnippetsForSnap(snapInfo.Name(), interfaces.SecuritySecComp)
if err != nil {
return fmt.Errorf("cannot obtain security snippets for snap %q: %s", snapName, err)
}
// Get the files that this snap should have
content, err := b.combineSnippets(snapInfo, devMode, snippets)
if err != nil {
return fmt.Errorf("cannot obtain expected security files for snap %q: %s", snapName, err)
}
glob := interfaces.SecurityTagGlob(snapName)
dir := dirs.SnapSeccompDir
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("cannot create directory for seccomp profiles %q: %s", dir, err)
}
_, _, err = osutil.EnsureDirState(dir, glob, content)
if err != nil {
return fmt.Errorf("cannot synchronize security files for snap %q: %s", snapName, err)
}
return nil
}
// Remove removes seccomp profiles of a given snap.
func (b *Backend) Remove(snapName string) error {
glob := interfaces.SecurityTagGlob(snapName)
_, _, err := osutil.EnsureDirState(dirs.SnapSeccompDir, glob, nil)
if err != nil {
return fmt.Errorf("cannot synchronize security files for snap %q: %s", snapName, err)
}
return nil
}
// combineSnippets combines security snippets collected from all the interfaces
// affecting a given snap into a content map applicable to EnsureDirState.
func (b *Backend) combineSnippets(snapInfo *snap.Info, devMode bool, snippets map[string][][]byte) (content map[string]*osutil.FileState, err error) {
for _, appInfo := range snapInfo.Apps {
if content == nil {
content = make(map[string]*osutil.FileState)
}
addContent(appInfo.SecurityTag(), devMode, snippets, content)
}
for _, hookInfo := range snapInfo.Hooks {
if content == nil {
content = make(map[string]*osutil.FileState)
}
addContent(hookInfo.SecurityTag(), devMode, snippets, content)
}
return content, nil
}
func addContent(securityTag string, devMode bool, snippets map[string][][]byte, content map[string]*osutil.FileState) {
var buffer bytes.Buffer
if devMode {
// NOTE: This is understood by ubuntu-core-launcher
buffer.WriteString("@complain\n")
}
buffer.Write(defaultTemplate)
for _, snippet := range snippets[securityTag] {
buffer.Write(snippet)
buffer.WriteRune('\n')
}
content[securityTag] = &osutil.FileState{
Content: buffer.Bytes(),
Mode: 0644,
}
}