1212//! 2. VSock - via QGS (Quote Generation Service) over vsock
1313//! 3. TDVMCALL - via `/dev/tdx_guest` ioctl (legacy)
1414
15+ use std:: ffi:: OsStr ;
1516use std:: fs:: { self , File , OpenOptions } ;
1617use std:: io:: { Read , Write } ;
1718use std:: os:: unix:: io:: AsRawFd ;
18- use std:: path:: Path ;
19+ use std:: path:: { Path , PathBuf } ;
1920use std:: sync:: Mutex ;
2021use std:: thread;
2122use std:: time:: { Duration , Instant } ;
@@ -188,15 +189,39 @@ fn should_try_configfs() -> bool {
188189 || Path :: new ( CONFIGFS_BASE ) . is_dir ( )
189190}
190191
192+ /// Parse an environment path override.
193+ ///
194+ /// Overrides must be non-empty absolute paths so a mis-set relative value like
195+ /// `"."` cannot silently operate on the process working directory.
196+ fn absolute_env_path ( var : & str , value : impl AsRef < OsStr > ) -> Result < PathBuf > {
197+ let value = value. as_ref ( ) ;
198+ if value. is_empty ( ) {
199+ return Err ( TdxAttestError :: NotSupported ( format ! (
200+ "empty path override from {var}"
201+ ) ) ) ;
202+ }
203+ let path = PathBuf :: from ( value) ;
204+ if !path. is_absolute ( ) {
205+ return Err ( TdxAttestError :: NotSupported ( format ! (
206+ "path override from {var} must be absolute: {}" ,
207+ path. display( )
208+ ) ) ) ;
209+ }
210+ Ok ( path)
211+ }
212+
191213/// Return whether a TDX guest provider is available through either the legacy
192214/// misc device or the standard TSM report interface.
193215pub fn is_tdx_available ( ) -> bool {
194216 if Path :: new ( TDX_GUEST_DEVICE ) . exists ( ) {
195217 return true ;
196218 }
197219
198- if let Some ( path) = std:: env:: var_os ( CONFIGFS_PATH_ENV ) {
199- return verify_configfs_provider ( Path :: new ( & path) ) . unwrap_or ( false ) ;
220+ if let Some ( value) = std:: env:: var_os ( CONFIGFS_PATH_ENV ) {
221+ let Ok ( path) = absolute_env_path ( CONFIGFS_PATH_ENV , & value) else {
222+ return false ;
223+ } ;
224+ return verify_configfs_provider ( & path) . unwrap_or ( false ) ;
200225 }
201226
202227 if verify_configfs_provider ( Path :: new ( CONFIGFS_DEFAULT ) ) . unwrap_or ( false ) {
@@ -264,9 +289,9 @@ pub fn extend_rtmr(index: u32, _event_type: u32, digest: [u8; 48]) -> Result<()>
264289 ) )
265290}
266291
267- fn rtmr_sysfs_base ( ) -> Result < Option < std :: path :: PathBuf > > {
268- if let Some ( path ) = std:: env:: var_os ( RTMR_SYSFS_PATH_ENV ) {
269- let path = std :: path :: PathBuf :: from ( path ) ;
292+ fn rtmr_sysfs_base ( ) -> Result < Option < PathBuf > > {
293+ if let Some ( value ) = std:: env:: var_os ( RTMR_SYSFS_PATH_ENV ) {
294+ let path = absolute_env_path ( RTMR_SYSFS_PATH_ENV , & value ) ? ;
270295 if path. as_os_str ( ) . len ( ) < 240 && path. is_dir ( ) {
271296 return Ok ( Some ( path) ) ;
272297 }
@@ -278,7 +303,7 @@ fn rtmr_sysfs_base() -> Result<Option<std::path::PathBuf>> {
278303
279304 Ok ( Path :: new ( RTMR_SYSFS_BASE )
280305 . is_dir ( )
281- . then ( || std :: path :: PathBuf :: from ( RTMR_SYSFS_BASE ) ) )
306+ . then ( || PathBuf :: from ( RTMR_SYSFS_BASE ) ) )
282307}
283308
284309fn extend_rtmr_via_sysfs ( base : & Path , index : u32 , digest : & [ u8 ; 48 ] ) -> Result < ( ) > {
@@ -374,15 +399,14 @@ fn get_quote_via_configfs(report_data: &TdxReportData) -> Result<Vec<u8>> {
374399}
375400
376401fn prepare_configfs ( ) -> Result < String > {
377- if let Ok ( path) = std:: env:: var ( CONFIGFS_PATH_ENV ) {
378- if path. len ( ) < 240
379- && Path :: new ( & path) . is_dir ( )
380- && verify_configfs_provider ( Path :: new ( & path) ) ?
381- {
382- return Ok ( path) ;
402+ if let Ok ( value) = std:: env:: var ( CONFIGFS_PATH_ENV ) {
403+ let path = absolute_env_path ( CONFIGFS_PATH_ENV , & value) ?;
404+ if path. as_os_str ( ) . len ( ) < 240 && path. is_dir ( ) && verify_configfs_provider ( & path) ? {
405+ return Ok ( path. display ( ) . to_string ( ) ) ;
383406 }
384407 return Err ( TdxAttestError :: NotSupported ( format ! (
385- "invalid configfs path from env: {path}"
408+ "invalid configfs path from env: {}" ,
409+ path. display( )
386410 ) ) ) ;
387411 }
388412
@@ -727,4 +751,44 @@ mod tests {
727751 if message. contains( "invalid configfs path from env" )
728752 ) ) ;
729753 }
754+
755+ #[ test]
756+ fn absolute_env_path_rejects_empty_and_relative ( ) {
757+ assert ! ( absolute_env_path( "TEST_PATH" , "" ) . is_err( ) ) ;
758+ assert ! ( absolute_env_path( "TEST_PATH" , "." ) . is_err( ) ) ;
759+ assert ! ( absolute_env_path( "TEST_PATH" , "relative/path" ) . is_err( ) ) ;
760+ assert_eq ! (
761+ absolute_env_path( "TEST_PATH" , "/abs/path" ) . unwrap( ) ,
762+ PathBuf :: from( "/abs/path" )
763+ ) ;
764+ }
765+
766+ #[ test]
767+ fn relative_configfs_override_is_not_available ( ) {
768+ let previous = std:: env:: var_os ( CONFIGFS_PATH_ENV ) ;
769+ std:: env:: set_var ( CONFIGFS_PATH_ENV , "." ) ;
770+ let available = is_tdx_available ( ) ;
771+ match previous {
772+ Some ( value) => std:: env:: set_var ( CONFIGFS_PATH_ENV , value) ,
773+ None => std:: env:: remove_var ( CONFIGFS_PATH_ENV ) ,
774+ }
775+ // relative overrides are ignored; only a real guest device can still pass
776+ assert_eq ! ( available, Path :: new( TDX_GUEST_DEVICE ) . exists( ) ) ;
777+ }
778+
779+ #[ test]
780+ fn relative_rtmr_override_is_rejected ( ) {
781+ let previous = std:: env:: var_os ( RTMR_SYSFS_PATH_ENV ) ;
782+ std:: env:: set_var ( RTMR_SYSFS_PATH_ENV , "." ) ;
783+ let result = rtmr_sysfs_base ( ) ;
784+ match previous {
785+ Some ( value) => std:: env:: set_var ( RTMR_SYSFS_PATH_ENV , value) ,
786+ None => std:: env:: remove_var ( RTMR_SYSFS_PATH_ENV ) ,
787+ }
788+ assert ! ( matches!(
789+ result,
790+ Err ( TdxAttestError :: NotSupported ( message) )
791+ if message. contains( "must be absolute" )
792+ ) ) ;
793+ }
730794}
0 commit comments