-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathcontainer.go
More file actions
180 lines (158 loc) · 6.87 KB
/
container.go
File metadata and controls
180 lines (158 loc) · 6.87 KB
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2025 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 secboot
import (
"context"
"errors"
"fmt"
"io"
)
var (
ErrStorageContainerClosed = errors.New("storage container reader/writer is already closed")
ErrKeyslotNotFound = errors.New("keyslot not found")
ErrStorageContainerNotActive = errors.New("storage container is not active")
ErrNoStorageContainer = errors.New("no storage container for path")
)
// KeyslotType describes the type of a keyslot.
type KeyslotType string
const (
KeyslotTypePlatform KeyslotType = "platform"
KeyslotTypeRecovery KeyslotType = "recovery"
KeyslotTypeUnknown KeyslotType = ""
)
// Keyslot provides information about a keyslot.
type Keyslot interface {
Type() KeyslotType
Name() string
Priority() int
Data() KeyDataReader // TODO: This will eventually just be a io.Reader.
}
// StorageContainerReader provides a mechanism to perform read-only
// operations on keyslots on a storage container.
//
// The implementation does not need to be threadsafe - it should be
// used from a single goroutine. If access is needed on another
// goroutine, use the associated [StorageContainer] to open a new one.
//
// The backend should permit as many of these to be opened as required,
// but should never permit one to be opened at the same time as a
// [StorageContainerReadWriter].
type StorageContainerReader interface {
// Container returns the StorageContainer that this reader
// was opened from. It can return nil once Close is called.
Container() StorageContainer
// io.Closer is used to close this reader.
io.Closer
// ListKeyslotNames returns a sorted list of keyslot names.
ListKeyslotNames(ctx context.Context) ([]string, error)
// ReadKeyslot returns information about the keyslot with
// the specified name.
ReadKeyslot(ctx context.Context, name string) (Keyslot, error)
}
// StorageContainer represents some type of storage container that
// can store keyslots, making the core code in secboot agnostic to
// the storage backend. Implementation of this should be safe to
// access from multiple goroutines.
type StorageContainer interface {
Path() string // The path of this storage container.
// BackendName is the name of the backend that created this
// StorageContainer instance.
//
// XXX: See the comment for RegisterStorageContainerBackend about
// using something other than a string for identifying the storage
// backend.
BackendName() string
// CredentialName returns a string that can be used to identify
// a credential associated with this container that is passed from
// the early boot environment
CredentialName() string
// Activate unlocks this container with the specified key.
// The caller can choose to supply the Keyslot instance
// related to the keyslot from which the supplied key is
// associated with (obtained from StorageContainerReader.ReadKeyslot).
// If supplied, the backend can use this to target the supplied
// key at a specific keyslot. If keyslotInfo nil is supplied, the
// backend will have to test all keyslots with the supplied key.
// The caller can specify a configuration, which is a map of keys
// or arbitrary types to values of arbitrary types.
Activate(ctx context.Context, ks Keyslot, key []byte, cfg ActivateConfigGetter) error
// Deactivate locks this storage container.
Deactivate(ctx context.Context) error
// OpenRead opens this storage container in order to perform
// operations to keyslots that only require read access. The backend
// should permit as many of these to be opened as is requested, but
// must not allow a combination of StorageContainerReader and
// StorageContainerReadWriter (when it exists) to be open at the same
// time (and the backend should only permit one StorageContainerReadWriter
// to be open at a time).
OpenRead(ctx context.Context) (StorageContainerReader, error)
}
// FindStorageContainer returns a StorageContainer associated with the specified
// path to a storage container source, probing each of the registered backends
// to obtain an appropriate instance. The path may or may not be a path to a
// block device, depending on the backends that are registered, because not all
// backends that may exist in the future will make use of block devices for a
// storage container.
//
// This will always return the same StorageContainer instance for any path that
// points to the same storage container source, and will return the same
// StorageContainer that [FindActivatedStorageContainer] returns when
// it is supplied with the path of any container that is backed by this one.
//
// If no StorageContainer is found, a ErrNoStorageContainer error is returned.
//
// This is safe to call from multiple goroutines.
func FindStorageContainer(ctx context.Context, path string) (StorageContainer, error) {
for name, backend := range storageContainerHandlers {
container, err := backend.Probe(ctx, path)
if err != nil {
return nil, fmt.Errorf("cannot probe %q backend for path %q: %w", name, path, err)
}
if container != nil {
return container, nil
}
}
return nil, ErrNoStorageContainer
}
// FindActivatedStorageContainer returns a StorageContainer associated
// with the supplied path to some storage that is backed by a source storage
// container, probing each of the registered backend to obtain an appropriate
// instance. The path may or may not be a path to a block device, depending on
// the backends that are registered, because not all backends that may exist in
// the future will make use of block devices for a storage container.
//
// This will always return the same StorageContainer instance for any path that
// points to the same activated storage container, and will return the same
// StorageContainer that [FindStorageContainer] returns when it is supplied with
// a path to the source container.
//
// If no StorageContainer is found, a ErrNoStorageContainer error is returned.
//
// This is safe to call from multiple goroutines.
func FindActivatedStorageContainer(ctx context.Context, path string) (StorageContainer, error) {
for name, backend := range storageContainerHandlers {
container, err := backend.ProbeActivated(ctx, path)
if err != nil {
return nil, fmt.Errorf("cannot probe %q backend for path %q: %w", name, path, err)
}
if container != nil {
return container, nil
}
}
return nil, ErrNoStorageContainer
}