@@ -21,7 +21,8 @@ use sha2::{Digest, Sha256};
2121
2222use crate :: {
2323 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 ,
2526 } ,
2627 mount:: { composefs_fsmount, mount_at} ,
2728 splitstream:: { DigestMap , SplitStreamReader , SplitStreamWriter } ,
@@ -57,6 +58,7 @@ fn ensure_dir_and_openat(dirfd: impl AsFd, filename: &str, flags: OFlags) -> Err
5758pub struct Repository < ObjectID : FsVerityHashValue > {
5859 repository : OwnedFd ,
5960 objects : OnceCell < OwnedFd > ,
61+ insecure : bool ,
6062 _data : std:: marker:: PhantomData < ObjectID > ,
6163}
6264
@@ -85,6 +87,7 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
8587 Ok ( Self {
8688 repository,
8789 objects : OnceCell :: new ( ) ,
90+ insecure : false ,
8891 _data : std:: marker:: PhantomData ,
8992 } )
9093 }
@@ -127,7 +130,23 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
127130 Ok ( fd) => {
128131 // measure the existing file to ensure that it's correct
129132 // 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+ }
131150 return Ok ( id) ;
132151 }
133152 Err ( Errno :: NOENT ) => {
@@ -151,8 +170,17 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
151170 ) ?;
152171 drop ( file) ;
153172
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+ }
156184
157185 match linkat (
158186 CWD ,
@@ -175,10 +203,21 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
175203
176204 fn open_with_verity ( & self , filename : & str , expected_verity : & ObjectID ) -> Result < OwnedFd > {
177205 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+ }
179213 Ok ( fd)
180214 }
181215
216+ pub fn set_insecure ( & mut self , insecure : bool ) -> & mut Self {
217+ self . insecure = insecure;
218+ self
219+ }
220+
182221 /// Creates a SplitStreamWriter for writing a split stream.
183222 /// You should write the data to the returned object and then pass it to .store_stream() to
184223 /// store the result.
@@ -220,9 +259,18 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
220259
221260 /// Basically the same as has_stream() except that it performs expensive verification
222261 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 ) {
224264 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+ } ;
226274 let mut context = Sha256 :: new ( ) ;
227275 let mut split_stream = SplitStreamReader :: new ( File :: from ( stream) ) ?;
228276
@@ -383,20 +431,36 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
383431 self . write_image ( Some ( name) , & data)
384432 }
385433
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 ) > {
387437 let image = self . openat ( & format ! ( "images/{name}" ) , OFlags :: RDONLY ) ?;
388438
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 ) ) ;
392441 }
393442
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+ }
395454 }
396455
397456 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+ ) ?)
400464 }
401465
402466 pub fn mount_at ( & self , name : & str , mountpoint : impl AsRef < Path > ) -> Result < ( ) > {
@@ -525,7 +589,7 @@ impl<ObjectID: FsVerityHashValue> Repository<ObjectID> {
525589 }
526590
527591 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) ?;
529593 let mut data = vec ! [ ] ;
530594 std:: fs:: File :: from ( image) . read_to_end ( & mut data) ?;
531595 Ok ( crate :: erofs:: reader:: collect_objects ( & data) ?)
0 commit comments