@@ -6,9 +6,11 @@ use libcryptsetup_rs::consts::vals::{CryptKdf, EncryptionFormat, KeyslotInfo};
66use libcryptsetup_rs:: {
77 CryptDevice , CryptInit , CryptParamsLuks2Ref , CryptSettingsHandle , CryptTokenInfo , TokenInput ,
88} ;
9+ use prometheus:: Registry ;
910use serde:: { Deserialize , Serialize } ;
1011use std:: fs;
11- use std:: fs:: File ;
12+ use std:: fs:: { File , OpenOptions } ;
13+ use std:: io:: { Read , Write } ;
1214use std:: os:: unix:: fs:: PermissionsExt ;
1315use std:: path:: Path ;
1416use tracing:: { info, warn} ;
@@ -141,7 +143,7 @@ pub fn activate_crypt_device(
141143 passphrase : & [ u8 ] ,
142144 flags : CryptActivate ,
143145 verify_luks_params : bool ,
144- metrics_file : Option < & Path > ,
146+ metrics_registry : Option < & Registry > ,
145147) -> Result < ( CryptDevice , u32 ) > {
146148 let mut crypt_device = open_luks2_device ( device_path, header_location) ?;
147149
@@ -153,9 +155,9 @@ pub fn activate_crypt_device(
153155 . activate_by_passphrase ( Some ( name) , None , passphrase, flags)
154156 . context ( "Failed to activate cryptographic device" ) ?;
155157
156- if let Some ( metrics_file ) = metrics_file {
158+ if let Some ( registry ) = metrics_registry {
157159 let log_result = luks_parameters. and_then ( |luks_parameters| {
158- export_luks_parameters ( metrics_file , & luks_parameters, device_path, active_keyslot)
160+ export_luks_parameters ( registry , & luks_parameters, device_path, active_keyslot)
159161 } ) ;
160162 if let Err ( e) = log_result {
161163 warn ! ( "Failed to export LUKS parameters: {e:#}" ) ;
@@ -210,6 +212,10 @@ pub fn format_crypt_device(
210212 . context ( "Failed to create detached LUKS header file" ) ?
211213 . set_len ( 16 * 1024 * 1024 )
212214 . context ( "Failed to set size of detached LUKS header file" ) ?;
215+ // The replica (running as user ic-replica) needs read access to the detached header so
216+ // that it can share it during an upgrade.
217+ fs:: set_permissions ( header_path, fs:: Permissions :: from_mode ( 0o644 ) )
218+ . context ( "Failed to set permissions on detached LUKS header file" ) ?;
213219 }
214220
215221 let mut crypt_device = obtain_crypt_device_handle ( device_path, header_location) ?;
@@ -311,6 +317,60 @@ pub fn backup_luks_header_to_file(device_path: &Path, header_path: &Path) -> Res
311317 Ok ( ( ) )
312318}
313319
320+ /// Checks whether the device at `device_path` contains a valid LUKS2 header in the attached
321+ /// (on-device) position.
322+ pub fn has_attached_luks_header ( device_path : & Path ) -> Result < bool > {
323+ const LUKS_MAGIC : & [ u8 ; 4 ] = b"LUKS" ;
324+
325+ let mut start = vec ! [ ] ;
326+ std:: fs:: File :: open ( device_path)
327+ . context ( "Failed to open device for header check" ) ?
328+ . take ( LUKS_MAGIC . len ( ) as u64 )
329+ . read_to_end ( & mut start)
330+ . context ( "Failed to read first few bytes for header check" ) ?;
331+
332+ Ok ( start == LUKS_MAGIC )
333+ }
334+
335+ /// Wipes (zeroizes) the header area of the device at `device_path`, removing any attached LUKS
336+ /// header.
337+ ///
338+ /// This is used when the Store partition is opened with a detached header: if the data device still
339+ /// carries a legacy attached header (from an older GuestOS that wrote both), we wipe it so that
340+ /// only the detached header remains going forward.
341+ pub fn wipe_attached_luks_header ( device_path : & Path ) -> Result < ( ) > {
342+ let mut crypt_device = open_luks2_device ( device_path, LuksHeaderLocation :: Attached )
343+ . context ( "Failed to open LUKS device to determine header size" ) ?;
344+ // `get_data_offset` returns the offset in 512-byte sectors; convert to bytes.
345+ let data_offset_sectors = crypt_device. status_handle ( ) . get_data_offset ( ) ;
346+ let header_size_bytes = data_offset_sectors * 512 ;
347+
348+ let mut device = OpenOptions :: new ( )
349+ . write ( true )
350+ . open ( device_path)
351+ . with_context ( || {
352+ format ! (
353+ "Failed to open device {} for writing" ,
354+ device_path. display( )
355+ )
356+ } ) ?;
357+ device
358+ . write_all ( & vec ! [ 0_u8 ; header_size_bytes as usize ] )
359+ . with_context ( || {
360+ format ! (
361+ "Failed to wipe LUKS header on device {}" ,
362+ device_path. display( )
363+ )
364+ } ) ?;
365+ device. flush ( ) . with_context ( || {
366+ format ! (
367+ "Failed to flush LUKS header wipe on device {}" ,
368+ device_path. display( )
369+ )
370+ } ) ?;
371+ Ok ( ( ) )
372+ }
373+
314374/// Checks if the LUKS parameters match the expected values set in format_crypt_device.
315375/// If verify_luks_params is false, it will only log a warning if the verification fails.
316376fn maybe_verify_luks_parameters (
0 commit comments