@@ -150,8 +150,26 @@ pub struct TDAttributes {
150150
151151 /// OTHER attributes that do not impact the security of the TD (bits 63:32)
152152 pub other : OTHERFlags ,
153+
154+ /// Bits that the TDX 1.5 ABI requires attestation verifiers to reject.
155+ pub reserved : u64 ,
156+ }
157+
158+ const fn ones ( range : core:: ops:: RangeInclusive < u32 > ) -> u64 {
159+ let start = * range. start ( ) ;
160+ let end = * range. end ( ) ;
161+ let right_shift = match 63_u32 . checked_sub ( end) {
162+ Some ( shift) => shift,
163+ None => panic ! ( "bit range exceeds u64" ) ,
164+ } ;
165+ ( u64:: MAX << start) & ( u64:: MAX >> right_shift)
153166}
154167
168+ // Intel TDX Module ABI Specification 348551-008US, Table 3.23:
169+ // https://www.intel.com/content/www/us/en/content-details/865802/intel-tdx-module-abi-specification.html
170+ const TD_ATTRIBUTES_RESERVED_MBZ_MASK : u64 =
171+ ones ( 1 ..=3 ) | ones ( 7 ..=15 ) | ones ( 23 ..=26 ) | ones ( 32 ..=61 ) ;
172+
155173/// TUD (TD Under Debug) flags (bits 7:0)
156174#[ derive( Debug , Clone ) ]
157175pub struct TUDFlags {
@@ -166,68 +184,125 @@ pub struct TUDFlags {
166184/// SEC attributes that may impact the security of the TD (bits 31:8)
167185#[ derive( Debug , Clone ) ]
168186pub struct SECFlags {
169- /// Reserved for future SEC flags - must be 0 (bits 27:8)
170- pub reserved_lower : u32 ,
187+ /// ICSSD: Enable instruction-count based single-step defense
188+ pub icssd : bool ,
189+
190+ /// SERVTD_EXT: Include a hash of SERVTD_EXT_STRUCT in TDREPORT_STRUCT
191+ pub servtd_ext : bool ,
192+
193+ /// Positive reserved flags that attestation verifiers may accept (bits 22:18)
194+ pub reserved_positive : u64 ,
195+
196+ /// LASS: TD is allowed to use Linear Address Space Separation
197+ pub lass : bool ,
171198
172199 /// SEPT_VE_DISABLE: Disable EPT violation conversion to #VE on TD access of PENDING pages
173200 pub sept_ve_disable : bool ,
174201
175- /// Reserved for future SEC flags - must be 0 (bit 29)
176- pub reserved_bit29 : bool ,
202+ /// MIGRATABLE: TD is migratable using a Migration TD
203+ pub migratable : bool ,
177204
178205 /// PKS: TD is allowed to use Supervisor Protection Keys
179206 pub pks : bool ,
180207
181- /// KL: TD is allowed to use Key Locker
182- pub kl : bool ,
208+ /// Positive reserved bit (formerly KL)
209+ pub reserved_positive_bit31 : bool ,
183210}
184211
185212/// OTHER attributes that do not impact the security of the TD (bits 63:32)
186213#[ derive( Debug , Clone ) ]
187214pub struct OTHERFlags {
188- /// Reserved for future OTHER flags - must be 0 (bits 62:32)
189- pub reserved : u32 ,
215+ /// TPA: TD is a TDX Connect Provisioning Agent
216+ pub tpa : bool ,
190217
191218 /// PERFMON: TD is allowed to use Perfmon and PERF_METRICS capabilities
192219 pub perfmon : bool ,
193220}
194221
195222impl TDAttributes {
196223 pub fn parse ( input : [ u8 ; 8 ] ) -> Result < Self , scale:: Error > {
224+ let attributes = u64:: from_le_bytes ( input) ;
225+ let is_set = |bit : u32 | attributes & ones ( bit..=bit) != 0 ;
197226 let tud = input[ 0 ] ;
198- // Extract SEC flags (27:8 bits, bytes 1-3 and part of byte 4)
199- let reserved_lower =
200- ( ( ( input[ 3 ] & 0x0f ) as u32 ) << 16 ) | ( ( input[ 2 ] as u32 ) << 8 ) | ( input[ 1 ] as u32 ) ;
201- let sept_ve_disable = ( input[ 3 ] & 0x10 ) != 0 ; // Bit 28
202- let reserved_bit29 = ( input[ 3 ] & 0x20 ) != 0 ; // Bit 29
203- let pks = ( input[ 3 ] & 0x40 ) != 0 ; // Bit 30
204- let kl = ( input[ 3 ] & 0x80 ) != 0 ; // Bit 31
205-
206- // Extract OTHER flags (bytes 4-7)
207- // Mask bit 7 of input[7] (= PERFMON, bit 63) out of reserved_other.
208- let reserved_other = ( ( ( input[ 7 ] as u32 ) & 0x7F ) << 24 )
209- | ( ( input[ 6 ] as u32 ) << 16 )
210- | ( ( input[ 5 ] as u32 ) << 8 )
211- | ( input[ 4 ] as u32 ) ;
212- let perfmon = ( input[ 7 ] & 0x80 ) != 0 ; // Bit 63
227+ let icssd = is_set ( 16 ) ;
228+ let servtd_ext = is_set ( 17 ) ;
229+ let reserved_positive = attributes & ones ( 18 ..=22 ) ;
230+ let lass = is_set ( 27 ) ;
231+ let sept_ve_disable = is_set ( 28 ) ;
232+ let migratable = is_set ( 29 ) ;
233+ let pks = is_set ( 30 ) ;
234+ let reserved_positive_bit31 = is_set ( 31 ) ;
235+
236+ let tpa = is_set ( 62 ) ;
237+ let perfmon = is_set ( 63 ) ;
213238
214239 Ok ( TDAttributes {
215240 tud,
216241 sec : SECFlags {
217- reserved_lower,
242+ icssd,
243+ servtd_ext,
244+ reserved_positive,
245+ lass,
218246 sept_ve_disable,
219- reserved_bit29 ,
247+ migratable ,
220248 pks,
221- kl,
222- } ,
223- other : OTHERFlags {
224- reserved : reserved_other,
225- perfmon,
249+ reserved_positive_bit31,
226250 } ,
251+ other : OTHERFlags { tpa, perfmon } ,
252+ reserved : attributes & TD_ATTRIBUTES_RESERVED_MBZ_MASK ,
227253 } )
228254 }
229255}
230256
257+ #[ cfg( test) ]
258+ mod td_attributes_tests {
259+ use super :: { ones, TDAttributes } ;
260+
261+ #[ test]
262+ fn accepts_all_non_mbz_bits_from_tdx_1_5 ( ) {
263+ let allowed = [
264+ 0_u32 , 4 , 5 , 6 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 27 , 28 , 29 , 30 , 31 , 62 , 63 ,
265+ ] ;
266+
267+ for bit in allowed {
268+ let attributes = TDAttributes :: parse ( ones ( bit..=bit) . to_le_bytes ( ) ) . unwrap ( ) ;
269+ assert_eq ! ( attributes. reserved, 0 , "bit {bit} must be accepted" ) ;
270+ }
271+ }
272+
273+ #[ test]
274+ fn rejects_all_mbz_bits_from_tdx_1_5 ( ) {
275+ let allowed_mask = [
276+ 0_u32 , 4 , 5 , 6 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 27 , 28 , 29 , 30 , 31 , 62 , 63 ,
277+ ]
278+ . into_iter ( )
279+ . fold ( 0_u64 , |mask, bit| mask | ones ( bit..=bit) ) ;
280+
281+ for bit in 0 ..64 {
282+ if allowed_mask & ones ( bit..=bit) == 0 {
283+ let attributes = TDAttributes :: parse ( ones ( bit..=bit) . to_le_bytes ( ) ) . unwrap ( ) ;
284+ assert_ne ! ( attributes. reserved, 0 , "bit {bit} must be rejected" ) ;
285+ }
286+ }
287+ }
288+
289+ #[ test]
290+ fn parses_new_tdx_1_5_flags ( ) {
291+ let value = ones ( 16 ..=22 ) | ones ( 27 ..=27 ) | ones ( 29 ..=29 ) | ones ( 31 ..=31 ) | ones ( 62 ..=63 ) ;
292+ let attributes = TDAttributes :: parse ( value. to_le_bytes ( ) ) . unwrap ( ) ;
293+
294+ assert ! ( attributes. sec. icssd) ;
295+ assert ! ( attributes. sec. servtd_ext) ;
296+ assert_eq ! ( attributes. sec. reserved_positive, ones( 18 ..=22 ) ) ;
297+ assert ! ( attributes. sec. lass) ;
298+ assert ! ( attributes. sec. migratable) ;
299+ assert ! ( attributes. sec. reserved_positive_bit31) ;
300+ assert ! ( attributes. other. tpa) ;
301+ assert ! ( attributes. other. perfmon) ;
302+ assert_eq ! ( attributes. reserved, 0 ) ;
303+ }
304+ }
305+
231306#[ derive(
232307 Decode , Encode , Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Debug , Serialize , Deserialize ,
233308) ]
0 commit comments