@@ -21,7 +21,8 @@ use sha2::{Digest, Sha256};
21
21
22
22
use crate :: {
23
23
fsverity:: {
24
- compute_verity, enable_verity, ensure_verity_equal, measure_verity, FsVerityHashValue ,
24
+ compute_verity, enable_verity, ensure_verity_equal, measure_verity, CompareVerityError ,
25
+ EnableVerityError , FsVerityHashValue , MeasureVerityError ,
25
26
} ,
26
27
mount:: { composefs_fsmount, mount_at} ,
27
28
splitstream:: { DigestMap , SplitStreamReader , SplitStreamWriter } ,
@@ -57,6 +58,7 @@ fn ensure_dir_and_openat(dirfd: impl AsFd, filename: &str, flags: OFlags) -> Err
57
58
pub struct Repository < ObjectID : FsVerityHashValue > {
58
59
repository : OwnedFd ,
59
60
objects : OnceCell < OwnedFd > ,
61
+ insecure : bool ,
60
62
_data : std:: marker:: PhantomData < ObjectID > ,
61
63
}
62
64
@@ -85,6 +87,7 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
85
87
Ok ( Self {
86
88
repository,
87
89
objects : OnceCell :: new ( ) ,
90
+ insecure : false ,
88
91
_data : std:: marker:: PhantomData ,
89
92
} )
90
93
}
@@ -127,7 +130,23 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
127
130
Ok ( fd) => {
128
131
// measure the existing file to ensure that it's correct
129
132
// TODO: try to replace file if it's broken?
130
- ensure_verity_equal ( fd, & id) ?;
133
+ match ensure_verity_equal ( & fd, & id) {
134
+ Ok ( ( ) ) => { }
135
+ Err ( CompareVerityError :: Measure ( MeasureVerityError :: VerityMissing ) )
136
+ if self . insecure =>
137
+ {
138
+ match enable_verity :: < ObjectID > ( & fd) {
139
+ Ok ( ( ) ) => {
140
+ ensure_verity_equal ( & fd, & id) ?;
141
+ }
142
+ Err ( other) => Err ( other) ?,
143
+ }
144
+ }
145
+ Err ( CompareVerityError :: Measure (
146
+ MeasureVerityError :: FilesystemNotSupported ,
147
+ ) ) if self . insecure => { }
148
+ Err ( other) => Err ( other) ?,
149
+ }
131
150
return Ok ( id) ;
132
151
}
133
152
Err ( Errno :: NOENT ) => {
@@ -151,8 +170,17 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
151
170
) ?;
152
171
drop ( file) ;
153
172
154
- enable_verity :: < ObjectID > ( & ro_fd) . context ( "Enabling verity digest" ) ?;
155
- ensure_verity_equal ( & ro_fd, & id) . context ( "Double-checking verity digest" ) ?;
173
+ match enable_verity :: < ObjectID > ( & ro_fd) {
174
+ Ok ( ( ) ) => match ensure_verity_equal ( & ro_fd, & id) {
175
+ Ok ( ( ) ) => { }
176
+ Err ( CompareVerityError :: Measure (
177
+ MeasureVerityError :: VerityMissing | MeasureVerityError :: FilesystemNotSupported ,
178
+ ) ) if self . insecure => { }
179
+ Err ( other) => Err ( other) . context ( "Double-checking verity digest" ) ?,
180
+ } ,
181
+ Err ( EnableVerityError :: FilesystemNotSupported ) if self . insecure => { }
182
+ Err ( other) => Err ( other) . context ( "Enabling verity digest" ) ?,
183
+ }
156
184
157
185
match linkat (
158
186
CWD ,
@@ -175,10 +203,21 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
175
203
176
204
fn open_with_verity ( & self , filename : & str , expected_verity : & ObjectID ) -> Result < OwnedFd > {
177
205
let fd = self . openat ( filename, OFlags :: RDONLY ) ?;
178
- ensure_verity_equal ( & fd, expected_verity) ?;
206
+ match ensure_verity_equal ( & fd, expected_verity) {
207
+ Ok ( ( ) ) => { }
208
+ Err ( CompareVerityError :: Measure (
209
+ MeasureVerityError :: VerityMissing | MeasureVerityError :: FilesystemNotSupported ,
210
+ ) ) if self . insecure => { }
211
+ Err ( other) => Err ( other) ?,
212
+ }
179
213
Ok ( fd)
180
214
}
181
215
216
+ pub fn set_insecure ( & mut self , insecure : bool ) -> & mut Self {
217
+ self . insecure = insecure;
218
+ self
219
+ }
220
+
182
221
/// Creates a SplitStreamWriter for writing a split stream.
183
222
/// You should write the data to the returned object and then pass it to .store_stream() to
184
223
/// store the result.
@@ -220,9 +259,18 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
220
259
221
260
/// Basically the same as has_stream() except that it performs expensive verification
222
261
pub fn check_stream ( & self , sha256 : & Sha256Digest ) -> Result < Option < ObjectID > > {
223
- match self . openat ( & format ! ( "streams/{}" , hex:: encode( sha256) ) , OFlags :: RDONLY ) {
262
+ let stream_path = format ! ( "streams/{}" , hex:: encode( sha256) ) ;
263
+ match self . openat ( & stream_path, OFlags :: RDONLY ) {
224
264
Ok ( stream) => {
225
- let measured_verity: ObjectID = measure_verity ( & stream) ?;
265
+ let path = readlinkat ( & self . repository , stream_path, [ ] ) ?;
266
+ let measured_verity = match measure_verity ( & stream) {
267
+ Ok ( found) => found,
268
+ Err (
269
+ MeasureVerityError :: VerityMissing
270
+ | MeasureVerityError :: FilesystemNotSupported ,
271
+ ) if self . insecure => FsVerityHashValue :: from_object_pathname ( path. to_bytes ( ) ) ?,
272
+ Err ( other) => Err ( other) ?,
273
+ } ;
226
274
let mut context = Sha256 :: new ( ) ;
227
275
let mut split_stream = SplitStreamReader :: new ( File :: from ( stream) ) ?;
228
276
@@ -383,20 +431,36 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
383
431
self . write_image ( Some ( name) , & data)
384
432
}
385
433
386
- fn open_image ( & self , name : & str ) -> Result < OwnedFd > {
434
+ /// Returns the fd of the image and whether or not verity should be
435
+ /// enabled when mounting it.
436
+ fn open_image ( & self , name : & str ) -> Result < ( OwnedFd , bool ) > {
387
437
let image = self . openat ( & format ! ( "images/{name}" ) , OFlags :: RDONLY ) ?;
388
438
389
- if !name. contains ( "/" ) {
390
- // A name with no slashes in it is taken to be a sha256 fs-verity digest
391
- ensure_verity_equal ( & image, & ObjectID :: from_hex ( name) ?) ?;
439
+ if name. contains ( "/" ) {
440
+ return Ok ( ( image, true ) ) ;
392
441
}
393
442
394
- Ok ( image)
443
+ // A name with no slashes in it is taken to be a sha256 fs-verity digest
444
+ match measure_verity :: < ObjectID > ( & image) {
445
+ Ok ( found) if found == FsVerityHashValue :: from_hex ( name) ? => Ok ( ( image, true ) ) ,
446
+ Ok ( _) => bail ! ( "fs-verity content mismatch" ) ,
447
+ Err ( MeasureVerityError :: VerityMissing | MeasureVerityError :: FilesystemNotSupported )
448
+ if self . insecure =>
449
+ {
450
+ Ok ( ( image, false ) )
451
+ }
452
+ Err ( other) => Err ( other) ?,
453
+ }
395
454
}
396
455
397
456
pub fn mount ( & self , name : & str ) -> Result < OwnedFd > {
398
- let image = self . open_image ( name) ?;
399
- Ok ( composefs_fsmount ( image, name, self . objects_dir ( ) ?, true ) ?)
457
+ let ( image, enable_verity) = self . open_image ( name) ?;
458
+ Ok ( composefs_fsmount (
459
+ image,
460
+ name,
461
+ self . objects_dir ( ) ?,
462
+ enable_verity,
463
+ ) ?)
400
464
}
401
465
402
466
pub fn mount_at ( & self , name : & str , mountpoint : impl AsRef < Path > ) -> Result < ( ) > {
@@ -525,7 +589,7 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
525
589
}
526
590
527
591
pub fn objects_for_image ( & self , name : & str ) -> Result < HashSet < ObjectID > > {
528
- let image = self . open_image ( name) ?;
592
+ let ( image, _ ) = self . open_image ( name) ?;
529
593
let mut data = vec ! [ ] ;
530
594
std:: fs:: File :: from ( image) . read_to_end ( & mut data) ?;
531
595
Ok ( crate :: erofs:: reader:: collect_objects ( & data) ?)
0 commit comments