@@ -117,6 +117,7 @@ static int set_up_wolfssl_linuxkm_pie_redirect_table(void);
117117#ifdef HAVE_FIPS
118118extern const unsigned int wolfCrypt_FIPS_ro_start [];
119119extern const unsigned int wolfCrypt_FIPS_ro_end [];
120+ extern char verifyCore [WC_SHA256_DIGEST_SIZE * 2 + 1 ];
120121#endif
121122
122123#endif /* HAVE_LINUXKM_PIE_SUPPORT */
@@ -372,7 +373,20 @@ int wc_linuxkm_GenerateSeed_IntelRD(struct OS_Seed* os, byte* output, word32 sz)
372373#endif
373374
374375#ifdef FIPS_OPTEST
375- extern int linuxkm_op_test_wrapper (void );
376+ #ifndef HAVE_FIPS
377+ #error FIPS_OPTEST requires HAVE_FIPS.
378+ #endif
379+ #ifdef LINUXKM_LKCAPI_REGISTER
380+ #error FIPS_OPTEST is not allowed with LINUXKM_LKCAPI_REGISTER.
381+ #endif
382+ extern int linuxkm_op_test_1 (int argc , const char * argv []);
383+ extern int linuxkm_op_test_wrapper (void );
384+ static void * my_kallsyms_lookup_name (const char * name );
385+ static wolfSSL_Atomic_Int * conTestFailure_ptr = NULL ;
386+ static ssize_t FIPS_optest_trig_handler (struct kobject * kobj , struct kobj_attribute * attr ,
387+ const char * buf , size_t count );
388+ static struct kobj_attribute FIPS_optest_trig_attr = __ATTR (FIPS_optest_run_code , 0220 , NULL , FIPS_optest_trig_handler );
389+ static int installed_sysfs_FIPS_optest_trig_files = 0 ;
376390#endif
377391
378392#if LINUX_VERSION_CODE >= KERNEL_VERSION (5 , 0 , 0 )
@@ -383,6 +397,19 @@ static int wolfssl_init(void)
383397{
384398 int ret ;
385399
400+ #ifdef HAVE_FIPS
401+ /* The compiled-in verifycore must be the right length, else the module
402+ * geometry will change when the correct value is passed in, destabilizing
403+ * wc_linuxkm_pie_reloc_tab. It also must be the right length for the
404+ * module-update-fips-hash recipe (in-place overwrite) to work, and for
405+ * updateFipsHash() (WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE) to be safe from
406+ * overruns.
407+ */
408+ if (strlen (verifyCore ) != WC_SHA256_DIGEST_SIZE * 2 ) {
409+ pr_err ("ERROR: compile-time FIPS hash is the wrong length (expected %d hex digits).\n" , WC_SHA256_DIGEST_SIZE * 2 );
410+ return - ECANCELED ;
411+ }
412+
386413#ifdef WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE
387414#ifdef CONFIG_MODULE_SIG
388415 if (THIS_MODULE -> sig_ok == false) {
@@ -395,7 +422,9 @@ static int wolfssl_init(void)
395422 pr_err ("ERROR: wolfSSL module load aborted -- updateFipsHash: %s\n" ,wc_GetErrorString (ret ));
396423 return - ECANCELED ;
397424 }
398- #endif
425+ #endif /* WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE */
426+
427+ #endif /* HAVE_FIPS */
399428
400429#ifdef USE_WOLFSSL_LINUXKM_PIE_REDIRECT_TABLE
401430 ret = set_up_wolfssl_linuxkm_pie_redirect_table ();
@@ -592,8 +621,35 @@ static int wolfssl_init(void)
592621#endif /* HAVE_FIPS && FIPS_VERSION3_GT(5,2,0) */
593622
594623#ifdef FIPS_OPTEST
624+ conTestFailure_ptr = (wolfSSL_Atomic_Int * )my_kallsyms_lookup_name ("conTestFailure" );
625+ if (conTestFailure_ptr == NULL ) {
626+ pr_err ("ERROR: couldn't obtain conTestFailure_ptr.\n" );
627+ return - ECANCELED ;
628+ }
629+
630+ ret = linuxkm_lkcapi_sysfs_install_node (& FIPS_optest_trig_attr , & installed_sysfs_FIPS_optest_trig_files );
631+ if (ret != 0 ) {
632+ pr_err ("ERROR: linuxkm_lkcapi_sysfs_install_node() failed for %s (code %d).\n" , FIPS_optest_trig_attr .attr .name , ret );
633+ return - ECANCELED ;
634+ }
635+
636+ #ifdef FIPS_OPTEST_FULL_RUN_AT_MODULE_INIT
595637 (void )linuxkm_op_test_wrapper ();
638+ WOLFSSL_ATOMIC_STORE (* conTestFailure_ptr , 0 );
639+ for (i = 0 ; i < FIPS_CAST_COUNT ; ++ i )
640+ fipsCastStatus_put (i , FIPS_CAST_STATE_INIT );
641+ /* note, must call fipsEntry() here, not wolfCrypt_IntegrityTest_fips(),
642+ * because wc_GetCastStatus_fips(FIPS_CAST_HMAC_SHA2_256) isn't available
643+ * anymore.
644+ */
645+ fipsEntry ();
646+ ret = wolfCrypt_GetStatus_fips ();
647+ if (ret != 0 ) {
648+ pr_err ("ERROR: wolfCrypt_GetStatus_fips() after reset failed with code %d: %s\n" , ret , wc_GetErrorString (ret ));
649+ return - ECANCELED ;
650+ }
596651#endif
652+ #endif /* FIPS_OPTEST */
597653
598654#ifndef NO_CRYPT_TEST
599655 ret = wolfcrypt_test (NULL );
@@ -679,6 +735,9 @@ static void wolfssl_exit(void)
679735 int ret ;
680736
681737 (void )linuxkm_lkcapi_sysfs_deinstall_node (& FIPS_rerun_self_test_attr , & installed_sysfs_FIPS_files );
738+ #ifdef FIPS_OPTEST
739+ (void )linuxkm_lkcapi_sysfs_deinstall_node (& FIPS_optest_trig_attr , & installed_sysfs_FIPS_optest_trig_files );
740+ #endif
682741#endif
683742
684743#ifdef LINUXKM_LKCAPI_REGISTER
@@ -1278,7 +1337,6 @@ PRAGMA_GCC("GCC diagnostic ignored \"-Wunused-parameter\"")
12781337#include <crypto/hash.h>
12791338PRAGMA_GCC_DIAG_POP
12801339
1281- extern char verifyCore [WC_SHA256_DIGEST_SIZE * 2 + 1 ];
12821340extern const char coreKey [WC_SHA256_DIGEST_SIZE * 2 + 1 ];
12831341extern const unsigned int wolfCrypt_FIPS_ro_start [];
12841342extern const unsigned int wolfCrypt_FIPS_ro_end [];
@@ -1525,14 +1583,18 @@ static int updateFipsHash(void)
15251583static ssize_t FIPS_rerun_self_test_handler (struct kobject * kobj , struct kobj_attribute * attr ,
15261584 const char * buf , size_t count )
15271585{
1528- int arg ;
15291586 int ret ;
15301587
15311588 (void )kobj ;
15321589 (void )attr ;
15331590
1534- if (kstrtoint (buf , 10 , & arg ) || arg != 1 )
1591+ /* only recognize "1" and "1\n". */
1592+ if ((count < 1 ) || (count > 2 ) ||
1593+ (buf [0 ] != '1' ) ||
1594+ ((count == 2 ) && (buf [1 ] != '\n' )))
1595+ {
15351596 return - EINVAL ;
1597+ }
15361598
15371599 pr_info ("wolfCrypt: rerunning FIPS self-test on command." );
15381600
@@ -1562,4 +1624,99 @@ static ssize_t FIPS_rerun_self_test_handler(struct kobject *kobj, struct kobj_at
15621624 return count ;
15631625}
15641626
1627+ #ifdef FIPS_OPTEST
1628+
1629+ static void * my_kallsyms_lookup_name (const char * name ) {
1630+ static typeof (kallsyms_lookup_name ) * kallsyms_lookup_name_ptr = NULL ;
1631+ static struct kprobe kallsyms_lookup_name_kp = {
1632+ .symbol_name = "kallsyms_lookup_name"
1633+ };
1634+ unsigned long a ;
1635+
1636+ if (! kallsyms_lookup_name_ptr ) {
1637+ int ret ;
1638+ kallsyms_lookup_name_kp .addr = NULL ;
1639+ if ((ret = register_kprobe (& kallsyms_lookup_name_kp )) != 0 ) {
1640+ pr_err_once ("ERROR: register_kprobe(&kallsyms_lookup_name_kp) failed: %d" , ret );
1641+ return 0 ;
1642+ }
1643+ kallsyms_lookup_name_ptr = (typeof (kallsyms_lookup_name_ptr ))kallsyms_lookup_name_kp .addr ;
1644+ unregister_kprobe (& kallsyms_lookup_name_kp );
1645+ if (! kallsyms_lookup_name_ptr ) {
1646+ pr_err_once ("ERROR: kallsyms_lookup_name_kp.addr is null." );
1647+ return 0 ;
1648+ }
1649+ }
1650+
1651+ a = kallsyms_lookup_name_ptr (name );
1652+ return (void * )a ;
1653+ }
1654+
1655+ typedef struct test_func_args {
1656+ int return_code ;
1657+ } test_func_args ;
1658+
1659+ static ssize_t FIPS_optest_trig_handler (struct kobject * kobj , struct kobj_attribute * attr ,
1660+ const char * buf , const size_t count )
1661+ {
1662+ int ret ;
1663+ int argc ;
1664+ const char * argv [3 ];
1665+ char code_buf [5 ];
1666+ size_t corrected_count ;
1667+ int i ;
1668+
1669+ (void )kobj ;
1670+ (void )attr ;
1671+
1672+ /* buf may or may not have an LF at end -- tolerate both. there is no
1673+ * terminating null in either case.
1674+ */
1675+ if (count < 1 )
1676+ return - EINVAL ;
1677+ if (buf [count - 1 ] == '\n' )
1678+ corrected_count = count - 1 ;
1679+ else
1680+ corrected_count = count ;
1681+ if ((corrected_count < 1 ) || (corrected_count > 4 ))
1682+ return - EINVAL ;
1683+ memcpy (code_buf , buf , corrected_count );
1684+ code_buf [corrected_count ] = 0 ;
1685+
1686+ if (strspn (code_buf , "-0123456789" ) != corrected_count )
1687+ return - EINVAL ;
1688+
1689+ argv [0 ] = "./optest" ;
1690+ argv [1 ] = "0" ;
1691+ argv [2 ] = code_buf ;
1692+ argc = 3 ;
1693+
1694+ printf ("OK, testing code %s\n" , code_buf );
1695+
1696+ ret = linuxkm_op_test_1 (argc , & argv [0 ]);
1697+
1698+ printf ("ret of op_test = %d\n" , ret );
1699+
1700+ /* reload the library in memory and re-init state */
1701+ printf ("Reloading the module in memory (equivalent to power "
1702+ "cycle)\n" );
1703+ WOLFSSL_ATOMIC_STORE (* conTestFailure_ptr , 0 );
1704+ for (i = 0 ; i < FIPS_CAST_COUNT ; ++ i )
1705+ fipsCastStatus_put (i , FIPS_CAST_STATE_INIT );
1706+ /* note, must call fipsEntry() here, not wolfCrypt_IntegrityTest_fips(),
1707+ * because wc_GetCastStatus_fips(FIPS_CAST_HMAC_SHA2_256) isn't available
1708+ * anymore.
1709+ */
1710+ fipsEntry ();
1711+ ret = wolfCrypt_GetStatus_fips ();
1712+ printf ("Status indicator of library reload/powercycle: %d\n" ,
1713+ ret );
1714+ printf ("Module status is: %d\n" , wolfCrypt_GetStatus_fips ());
1715+ printf ("Module mode is: %d\n" , wolfCrypt_GetMode_fips ());
1716+
1717+ return count ;
1718+ }
1719+
1720+ #endif /* FIPS_OPTEST */
1721+
15651722#endif /* HAVE_FIPS */
0 commit comments