@@ -740,31 +740,23 @@ static bool test_arm64_pauth_cp_reg_update(uc_engine *uc, const uint32_t cpregid
740740 return (((reg .val & setmask ) == setmask ) && ((reg .val & clearmask ) == 0 ));
741741}
742742
743- static void test_arm64_pauth ( void )
743+ static void test_arm64_pauth_check_cpu_feat ( uc_engine * uc )
744744{
745- uc_engine * uc ;
746- const char code_paciza_x1 [] = "\xe1\x23\xc1\xda" ; // paciza x1
747-
748- // We expect a PAC added somewhere in pac_mask bits in order to make the
749- // test agnostic of TxSZ and TBI.
750-
751- const uint64_t some_unsigned_pointer = 0x0000aaaabbbbccccULL ;
752- const uint64_t pac_mask = 0xffff000000000000ULL & ~(1ULL << 55 );
753-
754- OK (uc_open (UC_ARCH_ARM64 , UC_MODE_ARM , & uc ));
755- OK (uc_ctl_set_cpu_model (uc , UC_CPU_ARM64_MAX ));
756-
757745 // Check the CPU actually supports any form of PAuth, i.e. any APA or API
758746 // bits are set. At the time of writing, UC_CPU_ARM64_A72 does not support
759- // PAuth, but UC_CPU_ARM64_MAX does. This is not required for the test,
760- // but helps with diagnostics when the selected CPU does not support PAuth.
747+ // PAuth, but UC_CPU_ARM64_MAX does. This check is not required for any of
748+ // the PAuth tests to work, but helps with diagnostics when the selected
749+ // CPU does not support PAuth.
761750
762751 const uint32_t ID_AA64ISAR1_EL1 [5 ] = { 0b11 , 0b000 , 0b0000 , 0b0110 , 0b001 };
763752 const uint64_t ID_AA64ISAR1_EL1_APA_API_MASK = (0b1111ULL << 4 ) | (0b1111ULL << 8 );
764753 uint64_t ID_AA64ISAR1_EL1_bits = test_arm64_pauth_cp_reg_read (uc , ID_AA64ISAR1_EL1 );
765754 TEST_CHECK ((ID_AA64ISAR1_EL1_bits & ID_AA64ISAR1_EL1_APA_API_MASK ) != 0 );
755+ }
766756
767- // Minimal PAuth setup, enabling only IA and IB. The test is agnostic to
757+ static void test_arm64_pauth_setup (uc_engine * uc )
758+ {
759+ // Minimal PAuth setup, enabling only IA and IB. The tests are agnostic to
768760 // VA size and MTE config, so don't bother touching TCR_EL1 for now.
769761
770762 const uint32_t SCR_EL3 [5 ] = { 0b11 , 0b110 , 0b0001 , 0b0001 , 0b000 };
@@ -791,44 +783,149 @@ static void test_arm64_pauth(void)
791783 test_arm64_pauth_cp_reg_write (uc , APIBKeyHi_EL1 , 0xDDDDDDDDDDDDDDDDULL );
792784 test_arm64_pauth_cp_reg_write (uc , APDAKeyLo_EL1 , 0xAAAAAAAAAAAAAAAAULL ); // == IA
793785 test_arm64_pauth_cp_reg_write (uc , APDAKeyHi_EL1 , 0xBBBBBBBBBBBBBBBBULL );
786+ }
787+
788+ static void test_arm64_pauth_vanilla (void ) {
789+ // PAuth test w/o using any uc_ctl interfaces, just PAuth on the CPU.
790+
791+ uc_engine * uc ;
792+ const char code_paciza_x1 [] = "\xe1\x23\xc1\xda" ; // paciza x1
793+ const char code_autiza_x1 [] = "\xe1\x33\xc1\xda" ; // autiza x1
794+ const char code_autizb_x1 [] = "\xe1\x37\xc1\xda" ; // autizb x1
795+ const char code_autdza_x1 [] = "\xe1\x3b\xc1\xda" ; // autdza x1
796+ const char code_autia_x1_x0 [] = "\x01\x10\xc1\xda" ; // autia x1, x0
797+ const char code_xpaci_x1 [] = "\xe1\x43\xc1\xda" ; // xpaci x1
798+
799+ // We expect a PAC added somewhere in pac_mask bits in order to make the
800+ // test agnostic of TxSZ and TBI.
801+
802+ const uint64_t some_unsigned_pointer = 0x0000aaaabbbbccccULL ;
803+ const uint64_t pac_mask = 0xffff000000000000ULL & ~(1ULL << 55 );
804+
805+ OK (uc_open (UC_ARCH_ARM64 , UC_MODE_ARM , & uc ));
806+ OK (uc_ctl_set_cpu_model (uc , UC_CPU_ARM64_MAX ));
807+ OK (uc_mem_map (uc , code_start , code_len , UC_PROT_ALL ));
808+
809+ test_arm64_pauth_check_cpu_feat (uc );
810+ test_arm64_pauth_setup (uc );
811+
812+ // Verify that paciza signs a pointer.
813+
814+ OK (uc_reg_write (uc , UC_ARM64_REG_X1 , & some_unsigned_pointer ));
815+ OK (uc_mem_write (uc , code_start , code_paciza_x1 , sizeof (code_paciza_x1 )));
816+ OK (uc_emu_start (uc , code_start , code_start + sizeof (code_paciza_x1 ) - 1 , 0 , 0 ));
817+ uint64_t signed_pointer = 0 ;
818+ OK (uc_reg_read (uc , UC_ARM64_REG_X1 , & signed_pointer ));
819+ TEST_CHECK (signed_pointer != some_unsigned_pointer );
820+ TEST_CHECK ((signed_pointer & pac_mask ) != 0 );
821+
822+ // Verify that xpaci results in original pointer.
823+
824+ OK (uc_mem_write (uc , code_start , code_xpaci_x1 , sizeof (code_xpaci_x1 )));
825+ OK (uc_emu_start (uc , code_start , code_start + sizeof (code_xpaci_x1 ) - 1 , 0 , 0 ));
826+ uint64_t stripped_pointer = 0 ;
827+ OK (uc_reg_read (uc , UC_ARM64_REG_X1 , & stripped_pointer ));
828+ TEST_CHECK (stripped_pointer == some_unsigned_pointer );
829+
830+ // Verify autia behaviour.
831+
832+ OK (uc_reg_write (uc , UC_ARM64_REG_X1 , & some_unsigned_pointer ));
833+ OK (uc_mem_write (uc , code_start , code_autiza_x1 , sizeof (code_autiza_x1 )));
834+ OK (uc_emu_start (uc , code_start , code_start + sizeof (code_autiza_x1 ) - 1 , 0 , 0 ));
835+ uint64_t authenticated_pointer = 0 ;
836+ OK (uc_reg_read (uc , UC_ARM64_REG_X1 , & authenticated_pointer ));
837+ TEST_CHECK ((authenticated_pointer & pac_mask ) != 0 ); // unsigned pointer is invalid
838+
839+ OK (uc_reg_write (uc , UC_ARM64_REG_X1 , & signed_pointer ));
840+ OK (uc_mem_write (uc , code_start , code_autiza_x1 , sizeof (code_autiza_x1 )));
841+ OK (uc_emu_start (uc , code_start , code_start + sizeof (code_autiza_x1 ) - 1 , 0 , 0 ));
842+ authenticated_pointer = 0 ;
843+ OK (uc_reg_read (uc , UC_ARM64_REG_X1 , & authenticated_pointer ));
844+ TEST_CHECK ((authenticated_pointer & pac_mask ) == 0 ); // signed pointer is valid
845+
846+ uint64_t diversifier = 1337 ;
847+ OK (uc_reg_write (uc , UC_ARM64_REG_X1 , & signed_pointer ));
848+ OK (uc_reg_write (uc , UC_ARM64_REG_X0 , & diversifier ));
849+ OK (uc_mem_write (uc , code_start , code_autia_x1_x0 , sizeof (code_autia_x1_x0 )));
850+ OK (uc_emu_start (uc , code_start , code_start + sizeof (code_autia_x1_x0 ) - 1 , 0 , 0 ));
851+ authenticated_pointer = 0 ;
852+ OK (uc_reg_read (uc , UC_ARM64_REG_X1 , & authenticated_pointer ));
853+ TEST_CHECK ((authenticated_pointer & pac_mask ) != 0 ); // wrong diversifier is invalid
854+
855+ OK (uc_reg_write (uc , UC_ARM64_REG_X1 , & signed_pointer ));
856+ OK (uc_mem_write (uc , code_start , code_autizb_x1 , sizeof (code_autizb_x1 )));
857+ OK (uc_emu_start (uc , code_start , code_start + sizeof (code_autizb_x1 ) - 1 , 0 , 0 ));
858+ authenticated_pointer = 0 ;
859+ OK (uc_reg_read (uc , UC_ARM64_REG_X1 , & authenticated_pointer ));
860+ TEST_CHECK ((authenticated_pointer & pac_mask ) != 0 ); // wrong but enabled key is invalid
861+
862+ OK (uc_reg_write (uc , UC_ARM64_REG_X1 , & signed_pointer ));
863+ OK (uc_mem_write (uc , code_start , code_autdza_x1 , sizeof (code_autdza_x1 )));
864+ OK (uc_emu_start (uc , code_start , code_start + sizeof (code_autdza_x1 ) - 1 , 0 , 0 ));
865+ authenticated_pointer = 0 ;
866+ OK (uc_reg_read (uc , UC_ARM64_REG_X1 , & authenticated_pointer ));
867+ TEST_CHECK ((authenticated_pointer & pac_mask ) != 0 ); // disabled but same value key is invalid
868+
869+ OK (uc_close (uc ));
870+ }
871+
872+ static void test_arm64_pauth_ctl (void )
873+ {
874+ // PAuth test for the uc_ctl interfaces.
875+
876+ uc_engine * uc ;
877+ const char code_paciza_x1 [] = "\xe1\x23\xc1\xda" ; // paciza x1
878+
879+ // We expect a PAC added somewhere in pac_mask bits in order to make the
880+ // test agnostic of TxSZ and TBI.
881+
882+ const uint64_t some_unsigned_pointer = 0x0000aaaabbbbccccULL ;
883+ const uint64_t pac_mask = 0xffff000000000000ULL & ~(1ULL << 55 );
884+
885+ OK (uc_open (UC_ARCH_ARM64 , UC_MODE_ARM , & uc ));
886+ OK (uc_ctl_set_cpu_model (uc , UC_CPU_ARM64_MAX ));
887+ OK (uc_mem_map (uc , code_start , code_len , UC_PROT_ALL ));
888+
889+ test_arm64_pauth_check_cpu_feat (uc );
890+ test_arm64_pauth_setup (uc );
794891
795892 // Verify that paciza and uc_ctl_pauth_sign() result in the same signed
796893 // pointer.
797894
798- uint64_t x1 = some_unsigned_pointer ;
799- OK (uc_mem_map (uc , code_start , code_len , UC_PROT_ALL ));
800895 OK (uc_mem_write (uc , code_start , code_paciza_x1 , sizeof (code_paciza_x1 )));
801- OK (uc_reg_write (uc , UC_ARM64_REG_X1 , & x1 ));
896+ OK (uc_reg_write (uc , UC_ARM64_REG_X1 , & some_unsigned_pointer ));
802897 OK (uc_emu_start (uc , code_start , code_start + sizeof (code_paciza_x1 ) - 1 , 0 , 0 ));
803- OK (uc_reg_read (uc , UC_ARM64_REG_X1 , & x1 ));
804- TEST_CHECK (x1 != some_unsigned_pointer );
805- TEST_CHECK ((x1 & pac_mask ) != 0 );
898+ uint64_t signed_pointer_paciza = 0 ;
899+ OK (uc_reg_read (uc , UC_ARM64_REG_X1 , & signed_pointer_paciza ));
900+ TEST_CHECK (signed_pointer_paciza != some_unsigned_pointer );
901+ TEST_CHECK ((signed_pointer_paciza & pac_mask ) != 0 );
806902
807- uint64_t ptr = some_unsigned_pointer ;
808- OK (uc_ctl_pauth_sign (uc , ptr , UC_ARM64_PAUTH_KEY_IA , 0 , & ptr ));
809- TEST_CHECK (ptr == x1 );
903+ uint64_t signed_pointer = 0 ;
904+ OK (uc_ctl_pauth_sign (uc , some_unsigned_pointer , UC_ARM64_PAUTH_KEY_IA , 0 , & signed_pointer ));
905+ TEST_CHECK (signed_pointer == signed_pointer_paciza );
810906
811907 // Verify that stripping the PAC results in the original pointer.
812908
813- OK (uc_ctl_pauth_strip (uc , ptr , UC_ARM64_PAUTH_KEY_IA , & ptr ));
814- TEST_CHECK (ptr == some_unsigned_pointer );
909+ uint64_t stripped_pointer = 0 ;
910+ OK (uc_ctl_pauth_strip (uc , signed_pointer , UC_ARM64_PAUTH_KEY_IA , & stripped_pointer ));
911+ TEST_CHECK (stripped_pointer == some_unsigned_pointer );
815912
816913 // Verify that authenticating works as expected.
817914
818915 bool valid = true;
819- OK (uc_ctl_pauth_auth (uc , ptr , UC_ARM64_PAUTH_KEY_IA , 0 , & valid ));
916+ OK (uc_ctl_pauth_auth (uc , some_unsigned_pointer , UC_ARM64_PAUTH_KEY_IA , 0 , & valid ));
820917 TEST_CHECK (!valid ); // unsigned pointer
821918 valid = false;
822- OK (uc_ctl_pauth_auth (uc , x1 , UC_ARM64_PAUTH_KEY_IA , 0 , & valid ));
919+ OK (uc_ctl_pauth_auth (uc , signed_pointer , UC_ARM64_PAUTH_KEY_IA , 0 , & valid ));
823920 TEST_CHECK (valid ); // signed pointer
824921 valid = true;
825- OK (uc_ctl_pauth_auth (uc , x1 , UC_ARM64_PAUTH_KEY_IA , 1337 , & valid ));
922+ OK (uc_ctl_pauth_auth (uc , signed_pointer , UC_ARM64_PAUTH_KEY_IA , 1337 , & valid ));
826923 TEST_CHECK (!valid ); // wrong diversifier
827924 valid = true;
828- OK (uc_ctl_pauth_auth (uc , x1 , UC_ARM64_PAUTH_KEY_IB , 0 , & valid ));
925+ OK (uc_ctl_pauth_auth (uc , signed_pointer , UC_ARM64_PAUTH_KEY_IB , 0 , & valid ));
829926 TEST_CHECK (!valid ); // wrong but enabled key
830927 valid = true;
831- OK (uc_ctl_pauth_auth (uc , x1 , UC_ARM64_PAUTH_KEY_DA , 0 , & valid ));
928+ OK (uc_ctl_pauth_auth (uc , signed_pointer , UC_ARM64_PAUTH_KEY_DA , 0 , & valid ));
832929 TEST_CHECK (!valid ); // disabled but same value key
833930
834931 OK (uc_close (uc ));
@@ -853,5 +950,6 @@ TEST_LIST = {{"test_arm64_until", test_arm64_until},
853950 {"test_arm64_mem_prot_regress" , test_arm64_mem_prot_regress },
854951 {"test_arm64_mem_hook_read_write" , test_arm64_mem_hook_read_write },
855952 {"test_arm64_pc_guarantee" , test_arm64_pc_guarantee },
856- {"test_arm64_pauth" , test_arm64_pauth },
953+ {"test_arm64_pauth_vanilla" , test_arm64_pauth_vanilla },
954+ {"test_arm64_pauth_ctl" , test_arm64_pauth_ctl },
857955 {NULL , NULL }};
0 commit comments