LCOV - code coverage report
Current view: top level - app/fdctl/run/tiles - fd_sign.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 9 174 5.2 %
Date: 2025-01-08 12:08:44 Functions: 2 12 16.7 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "../../../../disco/tiles.h"
       3             : 
       4             : #include "generated/sign_seccomp.h"
       5             : 
       6             : #include "../../../../disco/keyguard/fd_keyguard.h"
       7             : #include "../../../../disco/keyguard/fd_keyload.h"
       8             : #include "../../../../ballet/base58/fd_base58.h"
       9             : 
      10             : #include <errno.h>
      11             : #include <sys/mman.h>
      12             : 
      13           0 : #define MAX_IN (32UL)
      14             : 
      15             : /* fd_sign_in_ctx_t is a context object for each in (producer) mcache
      16             :    connected to the sign tile. */
      17             : 
      18             : typedef struct {
      19             :   ulong            seq;
      20             :   fd_frag_meta_t * mcache;
      21             :   uchar *          data;
      22             : } fd_sign_out_ctx_t;
      23             : 
      24             : typedef struct {
      25             :   uchar             _data[ FD_KEYGUARD_SIGN_REQ_MTU ];
      26             : 
      27             :   /* Pre-staged with the public key base58 encoded, followed by "-" in the first bytes */
      28             :   ulong public_key_base58_sz;
      29             :   uchar concat[ FD_BASE58_ENCODED_32_SZ+1UL+9UL ];
      30             : 
      31             :   uchar event_concat[ 18UL+32UL ];
      32             : 
      33             :   int               in_role[ MAX_IN ];
      34             :   uchar *           in_data[ MAX_IN ];
      35             :   ushort            in_mtu [ MAX_IN ];
      36             : 
      37             :   fd_sign_out_ctx_t out[ MAX_IN ];
      38             : 
      39             :   fd_sha512_t       sha512 [ 1 ];
      40             : 
      41             :   uchar const *     public_key;
      42             :   uchar const *     private_key;
      43             : } fd_sign_ctx_t;
      44             : 
      45             : FD_FN_CONST static inline ulong
      46           3 : scratch_align( void ) {
      47           3 :   return alignof( fd_sign_ctx_t );
      48           3 : }
      49             : 
      50             : FD_FN_PURE static inline ulong
      51           3 : scratch_footprint( fd_topo_tile_t const * tile ) {
      52           3 :   (void)tile;
      53           3 :   ulong l = FD_LAYOUT_INIT;
      54           3 :   l = FD_LAYOUT_APPEND( l, alignof( fd_sign_ctx_t ), sizeof( fd_sign_ctx_t ) );
      55           3 :   return FD_LAYOUT_FINI( l, scratch_align() );
      56           3 : }
      57             : 
      58             : /* during_frag is called between pairs for sequence number checks, as
      59             :    we are reading incoming frags.  We don't actually need to copy the
      60             :    fragment here, see fd_dedup.c for why we do this.*/
      61             : 
      62             : static void FD_FN_SENSITIVE
      63             : during_frag_sensitive( void * _ctx,
      64             :                        ulong  in_idx,
      65             :                        ulong  seq,
      66             :                        ulong  sig,
      67             :                        ulong  chunk,
      68           0 :                        ulong  sz ) {
      69           0 :   (void)seq;
      70           0 :   (void)sig;
      71           0 :   (void)chunk;
      72           0 :   (void)sz;
      73             : 
      74           0 :   fd_sign_ctx_t * ctx = (fd_sign_ctx_t *)_ctx;
      75           0 :   FD_TEST( in_idx<MAX_IN );
      76             : 
      77           0 :   int  role = ctx->in_role[ in_idx ];
      78           0 :   uint mtu  = ctx->in_mtu [ in_idx ];
      79             : 
      80           0 :   if( sz>mtu ) {
      81           0 :     FD_LOG_EMERG(( "oversz signing request (role=%d sz=%lu mtu=%u)", role, sz, mtu ));
      82           0 :   }
      83           0 :   fd_memcpy( ctx->_data, ctx->in_data[ in_idx ], sz );
      84           0 : }
      85             : 
      86             : 
      87             : static void
      88             : during_frag( void * _ctx,
      89             :              ulong  in_idx,
      90             :              ulong  seq,
      91             :              ulong  sig,
      92             :              ulong  chunk,
      93           0 :              ulong  sz ) {
      94           0 :   during_frag_sensitive( _ctx, in_idx, seq, sig, chunk, sz );
      95           0 : }
      96             : 
      97             : static void FD_FN_SENSITIVE
      98             : after_frag_sensitive( void *              _ctx,
      99             :                       ulong               in_idx,
     100             :                       ulong               seq,
     101             :                       ulong               sig,
     102             :                       ulong               sz,
     103             :                       ulong               tsorig,
     104           0 :                       fd_stem_context_t * stem ) {
     105           0 :   (void)seq;
     106           0 :   (void)tsorig;
     107           0 :   (void)stem;
     108             : 
     109           0 :   fd_sign_ctx_t * ctx = (fd_sign_ctx_t *)_ctx;
     110             : 
     111           0 :   int sign_type = (int)(uint)sig;
     112             : 
     113           0 :   FD_TEST( in_idx<MAX_IN );
     114             : 
     115           0 :   int role = ctx->in_role[ in_idx ];
     116             : 
     117           0 :   fd_keyguard_authority_t authority = {0};
     118           0 :   memcpy( authority.identity_pubkey, ctx->public_key, 32 );
     119             : 
     120           0 :   if( FD_UNLIKELY( !fd_keyguard_payload_authorize( &authority, ctx->_data, sz, role, sign_type ) ) ) {
     121           0 :     FD_LOG_EMERG(( "fd_keyguard_payload_authorize failed (role=%d sign_type=%d)", role, sign_type ));
     122           0 :   }
     123             : 
     124           0 :   switch( sign_type ) {
     125           0 :   case FD_KEYGUARD_SIGN_TYPE_ED25519: {
     126           0 :     fd_ed25519_sign( ctx->out[ in_idx ].data, ctx->_data, sz, ctx->public_key, ctx->private_key, ctx->sha512 );
     127           0 :     break;
     128           0 :   }
     129           0 :   case FD_KEYGUARD_SIGN_TYPE_SHA256_ED25519: {
     130           0 :     uchar hash[ 32 ];
     131           0 :     fd_sha256_hash( ctx->_data, sz, hash );
     132           0 :     fd_ed25519_sign( ctx->out[ in_idx ].data, hash, 32UL, ctx->public_key, ctx->private_key, ctx->sha512 );
     133           0 :     break;
     134           0 :   }
     135           0 :   case FD_KEYGUARD_SIGN_TYPE_PUBKEY_CONCAT_ED25519: {
     136           0 :     memcpy( ctx->concat+ctx->public_key_base58_sz+1UL, ctx->_data, 9UL );
     137           0 :     fd_ed25519_sign( ctx->out[ in_idx ].data, ctx->concat, ctx->public_key_base58_sz+1UL+9UL, ctx->public_key, ctx->private_key, ctx->sha512 );
     138           0 :     break;
     139           0 :   }
     140           0 :   case FD_KEYGUARD_SIGN_TYPE_FD_METRICS_REPORT_CONCAT_ED25519: {
     141           0 :     memcpy( ctx->event_concat+18UL, ctx->_data, 32UL );
     142           0 :     fd_ed25519_sign( ctx->out[ in_idx ].data, ctx->event_concat, 18UL+32UL, ctx->public_key, ctx->private_key, ctx->sha512 );
     143           0 :     break;
     144           0 :   }
     145           0 :   default:
     146           0 :     FD_LOG_EMERG(( "invalid sign type: %d", sign_type ));
     147           0 :   }
     148             : 
     149           0 :   fd_mcache_publish( ctx->out[ in_idx ].mcache, 128UL, ctx->out[ in_idx ].seq, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL );
     150           0 :   ctx->out[ in_idx ].seq = fd_seq_inc( ctx->out[ in_idx ].seq, 1UL );
     151           0 : }
     152             : 
     153             : static void
     154             : after_frag( void *              _ctx,
     155             :             ulong               in_idx,
     156             :             ulong               seq,
     157             :             ulong               sig,
     158             :             ulong               sz,
     159             :             ulong               tsorig,
     160           0 :             fd_stem_context_t * stem ) {
     161           0 :   after_frag_sensitive( _ctx, in_idx, seq, sig, sz, tsorig, stem );
     162           0 : }
     163             : 
     164             : static void FD_FN_SENSITIVE
     165             : privileged_init_sensitive( fd_topo_t *      topo,
     166           0 :                            fd_topo_tile_t * tile ) {
     167           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     168             : 
     169           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     170           0 :   fd_sign_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_sign_ctx_t ), sizeof( fd_sign_ctx_t ) );
     171             : 
     172           0 :   uchar const * identity_key = fd_keyload_load( tile->sign.identity_key_path, /* pubkey only: */ 0 );
     173           0 :   ctx->private_key = identity_key;
     174           0 :   ctx->public_key  = identity_key + 32UL;
     175             : 
     176             :     /* The stack can be taken over and reorganized by under AddressSanitizer,
     177             :      which causes this code to fail.  */
     178             : #if FD_HAS_ASAN
     179             :   FD_LOG_WARNING(( "!!! SECURITY WARNING !!! YOU ARE RUNNING THE SIGNING TILE "
     180             :                    "WITH ADDRESS SANITIZER ENABLED. THIS CAN LEAK SENSITIVE "
     181             :                    "DATA INCLUDING YOUR PRIVATE KEYS INTO CORE DUMPS IF THIS "
     182             :                    "PROCESS ABORTS. IT IS HIGHLY ADVISED TO NOT TO RUN IN THIS "
     183             :                    "MODE IN PRODUCTION!" ));
     184             : #else
     185             :   /* Prevent the stack from showing up in core dumps just in case the
     186             :      private key somehow ends up in there. */
     187           0 :   FD_TEST( fd_tile_stack0() );
     188           0 :   FD_TEST( fd_tile_stack_sz() );
     189           0 :   if( FD_UNLIKELY( madvise( (void*)fd_tile_stack0(), fd_tile_stack_sz(), MADV_DONTDUMP ) ) )
     190           0 :     FD_LOG_ERR(( "madvise failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     191           0 : #endif
     192           0 : }
     193             : 
     194             : static void
     195             : privileged_init( fd_topo_t *      topo,
     196           0 :                  fd_topo_tile_t * tile ) {
     197           0 :   privileged_init_sensitive( topo, tile );
     198           0 : }
     199             : 
     200             : static void FD_FN_SENSITIVE
     201             : unprivileged_init_sensitive( fd_topo_t *      topo,
     202           0 :                              fd_topo_tile_t * tile ) {
     203           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     204             : 
     205           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     206           0 :   fd_sign_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_sign_ctx_t ), sizeof( fd_sign_ctx_t ) );
     207           0 :   FD_TEST( fd_sha512_join( fd_sha512_new( ctx->sha512 ) ) );
     208             : 
     209           0 :   uchar check_public_key[ 32 ];
     210           0 :   fd_ed25519_public_from_private( check_public_key, ctx->private_key, ctx->sha512 );
     211           0 :   if( FD_UNLIKELY( memcmp( check_public_key, ctx->public_key, 32 ) ) )
     212           0 :     FD_LOG_EMERG(( "The public key in the identity key file does not match the public key derived from the private key. "
     213           0 :                    "Firedancer will not use the key pair to sign as it might leak the private key." ));
     214             : 
     215           0 :   FD_TEST( tile->in_cnt<=MAX_IN );
     216           0 :   FD_TEST( tile->in_cnt==tile->out_cnt );
     217             : 
     218           0 :   fd_base58_encode_32( ctx->public_key, &ctx->public_key_base58_sz, (char *)ctx->concat );
     219           0 :   ctx->concat[ ctx->public_key_base58_sz ] = '-';
     220             : 
     221           0 :   memcpy( ctx->event_concat, "FD_METRICS_REPORT-", 18UL );
     222             : 
     223           0 :   for( ulong i=0; i<MAX_IN; i++ ) ctx->in_role[ i ] = -1;
     224             : 
     225           0 :   for( ulong i=0; i<tile->in_cnt; i++ ) {
     226           0 :     fd_topo_link_t * in_link = &topo->links[ tile->in_link_id[ i ] ];
     227           0 :     fd_topo_link_t * out_link = &topo->links[ tile->out_link_id[ i ] ];
     228             : 
     229           0 :     if( in_link->mtu > FD_KEYGUARD_SIGN_REQ_MTU ) FD_LOG_CRIT(( "oversz link[%lu].mtu=%lu", i, in_link->mtu ));
     230           0 :     ctx->in_data[ i ] = in_link->dcache;
     231           0 :     ctx->in_mtu [ i ] = (ushort)in_link->mtu;
     232             : 
     233           0 :     ctx->out[ i ].mcache = out_link->mcache;
     234           0 :     ctx->out[ i ].data   = out_link->dcache;
     235           0 :     ctx->out[ i ].seq    = 0UL;
     236             : 
     237           0 :     if( !strcmp( in_link->name, "shred_sign" ) ) {
     238           0 :       ctx->in_role[ i ] = FD_KEYGUARD_ROLE_LEADER;
     239           0 :       FD_TEST( !strcmp( out_link->name, "sign_shred" ) );
     240           0 :       FD_TEST( in_link->mtu==32UL );
     241           0 :       FD_TEST( out_link->mtu==64UL );
     242           0 :     } else if ( !strcmp( in_link->name, "gossip_sign" ) ) {
     243           0 :       ctx->in_role[ i ] = FD_KEYGUARD_ROLE_GOSSIP;
     244           0 :       FD_TEST( !strcmp( out_link->name, "sign_gossip" ) );
     245           0 :       FD_TEST( in_link->mtu==2048UL );
     246           0 :       FD_TEST( out_link->mtu==64UL );
     247           0 :     } else if ( !strcmp( in_link->name, "repair_sign")) {
     248           0 :       ctx->in_role[ i ] = FD_KEYGUARD_ROLE_REPAIR;
     249           0 :       FD_TEST( !strcmp( out_link->name, "sign_repair" ) );
     250           0 :       FD_TEST( in_link->mtu==2048UL );
     251           0 :       FD_TEST( out_link->mtu==64UL );
     252           0 :     } else if ( !strcmp(in_link->name, "voter_sign" ) ) {
     253           0 :       ctx->in_role[ i ] = FD_KEYGUARD_ROLE_VOTER;
     254           0 :       FD_TEST( !strcmp( out_link->name, "sign_voter"  ) );
     255           0 :       FD_TEST( in_link->mtu==FD_TXN_MTU  );
     256           0 :       FD_TEST( out_link->mtu==64UL );
     257           0 :     } else if( !strcmp(in_link->name, "bundle_sign" ) ) {
     258           0 :       ctx->in_role[ i ] = FD_KEYGUARD_ROLE_BUNDLE;
     259           0 :       FD_TEST( !strcmp( out_link->name, "sign_bundle" ) );
     260           0 :       FD_TEST( in_link->mtu==9UL );
     261           0 :       FD_TEST( out_link->mtu==64UL );
     262           0 :     } else if( !strcmp(in_link->name, "event_sign" ) ) {
     263           0 :       ctx->in_role[ i ] = FD_KEYGUARD_ROLE_EVENT;
     264           0 :       FD_TEST( !strcmp( out_link->name, "sign_event" ) );
     265           0 :       FD_TEST( in_link->mtu==32UL );
     266           0 :       FD_TEST( out_link->mtu==64UL );
     267           0 :     } else {
     268           0 :       FD_LOG_CRIT(( "unexpected link %s", in_link->name ));
     269           0 :     }
     270           0 :   }
     271             : 
     272           0 :   ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     273           0 :   if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
     274           0 :     FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
     275           0 : }
     276             : 
     277             : static void
     278             : unprivileged_init( fd_topo_t *      topo,
     279           0 :                    fd_topo_tile_t * tile ) {
     280           0 :   unprivileged_init_sensitive( topo, tile );
     281           0 : }
     282             : 
     283             : static ulong
     284             : populate_allowed_seccomp( fd_topo_t const *      topo,
     285             :                           fd_topo_tile_t const * tile,
     286             :                           ulong                  out_cnt,
     287           0 :                           struct sock_filter *   out ) {
     288           0 :   (void)topo;
     289           0 :   (void)tile;
     290             : 
     291           0 :   populate_sock_filter_policy_sign( out_cnt, out, (uint)fd_log_private_logfile_fd() );
     292           0 :   return sock_filter_policy_sign_instr_cnt;
     293           0 : }
     294             : 
     295             : static ulong
     296             : populate_allowed_fds( fd_topo_t const *      topo,
     297             :                       fd_topo_tile_t const * tile,
     298             :                       ulong                  out_fds_cnt,
     299           0 :                       int *                  out_fds ) {
     300           0 :   (void)topo;
     301           0 :   (void)tile;
     302             : 
     303           0 :   if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
     304             : 
     305           0 :   ulong out_cnt = 0;
     306           0 :   out_fds[ out_cnt++ ] = 2; /* stderr */
     307           0 :   if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
     308           0 :     out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
     309           0 :   return out_cnt;
     310           0 : }
     311             : 
     312           0 : #define STEM_BURST (1UL)
     313             : 
     314             : /* See explanation in fd_pack */
     315           0 : #define STEM_LAZY  (128L*3000L)
     316             : 
     317           0 : #define STEM_CALLBACK_CONTEXT_TYPE  fd_sign_ctx_t
     318           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_sign_ctx_t)
     319             : 
     320           0 : #define STEM_CALLBACK_DURING_FRAG during_frag
     321           0 : #define STEM_CALLBACK_AFTER_FRAG  after_frag
     322             : 
     323             : #include "../../../../disco/stem/fd_stem.c"
     324             : 
     325             : fd_topo_run_tile_t fd_tile_sign = {
     326             :   .name                     = "sign",
     327             :   .populate_allowed_seccomp = populate_allowed_seccomp,
     328             :   .populate_allowed_fds     = populate_allowed_fds,
     329             :   .scratch_align            = scratch_align,
     330             :   .scratch_footprint        = scratch_footprint,
     331             :   .privileged_init          = privileged_init,
     332             :   .unprivileged_init        = unprivileged_init,
     333             :   .run                      = stem_run,
     334             : };

Generated by: LCOV version 1.14