LCOV - code coverage report
Current view: top level - app/fdctl - caps.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 139 0.0 %
Date: 2024-11-13 11:58:15 Functions: 0 7 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "caps.h"
       3             : 
       4             : #include "configure/configure.h"
       5             : 
       6             : #include <stdio.h>
       7             : #include <stdarg.h>
       8             : #include <unistd.h>
       9             : #include <sys/syscall.h>
      10             : #include <linux/capability.h>
      11             : 
      12             : __attribute__ ((format (printf, 2, 3)))
      13             : static void
      14             : fd_caps_private_add_error( fd_caps_ctx_t * ctx,
      15             :                            char const *    fmt,
      16           0 :                            ... ) {
      17           0 :   if( FD_UNLIKELY( ctx->err_cnt >= MAX_ERROR_ENTRIES ) )
      18           0 :     FD_LOG_ERR(( "too many capability checks failed" ));
      19             : 
      20           0 :   va_list ap;
      21           0 :   va_start( ap, fmt );
      22           0 :   int result = vsnprintf( ctx->err[ ctx->err_cnt++ ], MAX_ERROR_MSG_LEN, fmt, ap );
      23           0 :   if( FD_UNLIKELY( result < 0 ) ) FD_LOG_ERR(( "vsnprintf failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      24           0 :   else if ( FD_UNLIKELY( (ulong)result >= MAX_ERROR_MSG_LEN ) ) FD_LOG_ERR(( "vsnprintf truncated message" ));
      25           0 :   va_end( ap );
      26           0 : }
      27             : 
      28             : void
      29             : fd_caps_check_root( fd_caps_ctx_t * ctx,
      30             :                     char const *    name,
      31           0 :                     char const *    reason ) {
      32           0 :   if( FD_LIKELY( !getuid() ) ) return;
      33             : 
      34           0 :   fd_caps_private_add_error( ctx, "%s ... process requires root to %s", name, reason );
      35           0 : }
      36             : 
      37             : static int
      38           0 : has_capability( uint capability ) {
      39           0 :   struct __user_cap_data_struct   capdata[2];
      40           0 :   struct __user_cap_header_struct capheader = {
      41           0 :     .pid = 0,
      42           0 :     .version = _LINUX_CAPABILITY_VERSION_3
      43           0 :   };
      44             : 
      45           0 :   if( FD_UNLIKELY( syscall( SYS_capget, &capheader, capdata ) ) )
      46           0 :     FD_LOG_ERR(( "capget syscall failed (%i-%s)", errno, fd_io_strerror( errno ) ) );
      47           0 :   return !!(capdata[ 0 ].effective & (1U << capability));
      48           0 : }
      49             : 
      50             : FD_FN_CONST static char *
      51           0 : fd_caps_str( uint capability ) {
      52           0 :   switch( capability ) {
      53           0 :     case CAP_CHOWN:              return "CAP_CHOWN";
      54           0 :     case CAP_DAC_OVERRIDE:       return "CAP_DAC_OVERRIDE";
      55           0 :     case CAP_DAC_READ_SEARCH:    return "CAP_DAC_READ_SEARCH";
      56           0 :     case CAP_FOWNER:             return "CAP_FOWNER";
      57           0 :     case CAP_FSETID:             return "CAP_FSETID";
      58           0 :     case CAP_KILL:               return "CAP_KILL";
      59           0 :     case CAP_SETGID:             return "CAP_SETGID";
      60           0 :     case CAP_SETUID:             return "CAP_SETUID";
      61           0 :     case CAP_SETPCAP:            return "CAP_SETPCAP";
      62           0 :     case CAP_LINUX_IMMUTABLE:    return "CAP_LINUX_IMMUTABLE";
      63           0 :     case CAP_NET_BIND_SERVICE:   return "CAP_NET_BIND_SERVICE";
      64           0 :     case CAP_NET_BROADCAST:      return "CAP_NET_BROADCAST";
      65           0 :     case CAP_NET_ADMIN:          return "CAP_NET_ADMIN";
      66           0 :     case CAP_NET_RAW:            return "CAP_NET_RAW";
      67           0 :     case CAP_IPC_LOCK:           return "CAP_IPC_LOCK";
      68           0 :     case CAP_IPC_OWNER:          return "CAP_IPC_OWNER";
      69           0 :     case CAP_SYS_MODULE:         return "CAP_SYS_MODULE";
      70           0 :     case CAP_SYS_RAWIO:          return "CAP_SYS_RAWIO";
      71           0 :     case CAP_SYS_CHROOT:         return "CAP_SYS_CHROOT";
      72           0 :     case CAP_SYS_PTRACE:         return "CAP_SYS_PTRACE";
      73           0 :     case CAP_SYS_PACCT:          return "CAP_SYS_PACCT";
      74           0 :     case CAP_SYS_ADMIN:          return "CAP_SYS_ADMIN";
      75           0 :     case CAP_SYS_BOOT:           return "CAP_SYS_BOOT";
      76           0 :     case CAP_SYS_NICE:           return "CAP_SYS_NICE";
      77           0 :     case CAP_SYS_RESOURCE:       return "CAP_SYS_RESOURCE";
      78           0 :     case CAP_SYS_TIME:           return "CAP_SYS_TIME";
      79           0 :     case CAP_SYS_TTY_CONFIG:     return "CAP_SYS_TTY_CONFIG";
      80           0 :     case CAP_MKNOD:              return "CAP_MKNOD";
      81           0 :     case CAP_LEASE:              return "CAP_LEASE";
      82           0 :     case CAP_AUDIT_WRITE:        return "CAP_AUDIT_WRITE";
      83           0 :     case CAP_AUDIT_CONTROL:      return "CAP_AUDIT_CONTROL";
      84           0 :     case CAP_SETFCAP:            return "CAP_SETFCAP";
      85           0 :     case CAP_MAC_OVERRIDE:       return "CAP_MAC_OVERRIDE";
      86           0 :     case CAP_MAC_ADMIN:          return "CAP_MAC_ADMIN";
      87           0 :     case CAP_SYSLOG:             return "CAP_SYSLOG";
      88           0 :     case CAP_WAKE_ALARM:         return "CAP_WAKE_ALARM";
      89           0 :     case CAP_BLOCK_SUSPEND:      return "CAP_BLOCK_SUSPEND";
      90           0 :     case CAP_AUDIT_READ:         return "CAP_AUDIT_READ";
      91           0 : #ifdef CAP_PERFMON
      92           0 :     case CAP_PERFMON:            return "CAP_PERFMON";
      93           0 : #endif
      94           0 : #ifdef CAP_BPF
      95           0 :     case CAP_BPF:                return "CAP_BPF";
      96           0 : #endif
      97           0 : #ifdef CAP_CHECKPOINT_RESTORE
      98           0 :     case CAP_CHECKPOINT_RESTORE: return "CAP_CHECKPOINT_RESTORE";
      99           0 : #endif
     100           0 :     default:                     return "UNKNOWN";
     101           0 :   }
     102           0 : }
     103             : 
     104             : void
     105             : fd_caps_check_capability( fd_caps_ctx_t * ctx,
     106             :                           char const *    name,
     107             :                           uint            capability,
     108           0 :                           char const *    reason ) {
     109           0 :   if( FD_LIKELY( has_capability( capability ) ) ) return;
     110             : 
     111           0 :   fd_caps_private_add_error( ctx, "%s ... process requires capability `%s` to %s", name, fd_caps_str( capability ), reason );
     112           0 : }
     113             : 
     114             : FD_FN_CONST static char *
     115           0 : fd_caps_resource_str( fd_rlimit_res_t resource ) {
     116           0 :   switch( resource ) {
     117           0 :     case RLIMIT_CPU:        return "RLIMIT_CPU";
     118           0 :     case RLIMIT_FSIZE:      return "RLIMIT_FSIZE";
     119           0 :     case RLIMIT_DATA:       return "RLIMIT_DATA";
     120           0 :     case RLIMIT_STACK:      return "RLIMIT_STACK";
     121           0 :     case RLIMIT_CORE:       return "RLIMIT_CORE";
     122           0 :     case RLIMIT_RSS:        return "RLIMIT_RSS";
     123           0 :     case RLIMIT_NOFILE:     return "RLIMIT_NOFILE";
     124           0 :     case RLIMIT_AS:         return "RLIMIT_AS";
     125           0 :     case RLIMIT_NPROC:      return "RLIMIT_NPROC";
     126           0 :     case RLIMIT_MEMLOCK:    return "RLIMIT_MEMLOCK";
     127           0 :     case RLIMIT_LOCKS:      return "RLIMIT_LOCKS";
     128           0 :     case RLIMIT_SIGPENDING: return "RLIMIT_SIGPENDING";
     129           0 :     case RLIMIT_MSGQUEUE:   return "RLIMIT_MSGQUEUE";
     130           0 :     case RLIMIT_NICE:       return "RLIMIT_NICE";
     131           0 :     case RLIMIT_RTPRIO:     return "RLIMIT_RTPRIO";
     132           0 :     case RLIMIT_RTTIME:     return "RLIMIT_RTTIME";
     133           0 :     case RLIMIT_NLIMITS:    return "RLIMIT_NLIMITS";
     134           0 :     default:                return "UNKNOWN";
     135           0 :   }
     136           0 : }
     137             : 
     138             : void
     139             : fd_caps_check_resource( fd_caps_ctx_t * ctx,
     140             :                         char const *    name,
     141             :                         fd_rlimit_res_t resource,
     142             :                         ulong           limit,
     143           0 :                         char const *    reason ) {
     144           0 :   struct rlimit rlim;
     145           0 :   if( FD_UNLIKELY( getrlimit( resource, &rlim ) ) )
     146           0 :     FD_LOG_ERR(( "getrlimit failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     147           0 :   if( FD_LIKELY( rlim.rlim_cur >= limit ) ) return;
     148             : 
     149           0 :   if( FD_LIKELY( !has_capability( CAP_SYS_RESOURCE ) ) ) {
     150           0 :     if( FD_LIKELY( resource == RLIMIT_NICE && has_capability( CAP_SYS_NICE ) ) ) {
     151             :         /* special case, if we have CAP_SYS_NICE we can set any nice
     152             :            value without raising the limit with CAP_SYS_RESOURCE. */
     153           0 :         return;
     154           0 :     }
     155             : 
     156           0 :     if( FD_UNLIKELY( resource == RLIMIT_NICE ) )
     157           0 :       fd_caps_private_add_error( ctx,
     158           0 :                                 "%s ... process requires capability `%s` or `%s` to %s",
     159           0 :                                 name,
     160           0 :                                 fd_caps_str( CAP_SYS_RESOURCE ),
     161           0 :                                 fd_caps_str( CAP_SYS_NICE ),
     162           0 :                                 reason );
     163           0 :     else
     164           0 :       fd_caps_private_add_error( ctx,
     165           0 :                                 "%s ... process requires capability `%s` to %s",
     166           0 :                                 name,
     167           0 :                                 fd_caps_str( CAP_SYS_RESOURCE ),
     168           0 :                                 reason );
     169           0 :   } else {
     170           0 :     if( FD_UNLIKELY( resource==RLIMIT_NOFILE ) ) {
     171             :       /* If we have CAP_SYS_RESOURCE, it may not be enough to increase
     172             :          RLIMIT_NOFILE.  Will still result in EPERM if /proc/sys/fs/nr_open
     173             :          is below the desired number. */
     174           0 :       uint file_nr = read_uint_file( "/proc/sys/fs/nr_open", "system might not support configuring sysctl," );
     175           0 :       if( FD_UNLIKELY( file_nr < limit ) )
     176           0 :         FD_LOG_ERR(( "Firedancer requires `/proc/sys/fs/nr_open` to be at least %lu "
     177           0 :                      "to raise RLIMIT_NOFILE, but it is %u. Please either increase "
     178           0 :                      "the sysctl or run `fdctl configure init sysctl` which will do "
     179           0 :                      "it for you.", limit, file_nr ));
     180           0 :     }
     181           0 :     rlim.rlim_cur = limit;
     182           0 :     rlim.rlim_max = limit;
     183           0 :     if( FD_UNLIKELY( setrlimit( resource, &rlim ) ) )
     184           0 :       FD_LOG_ERR(( "setrlimit failed (%i-%s) for resource %s", errno, fd_io_strerror( errno ), fd_caps_resource_str( resource ) ));
     185           0 :   }
     186           0 : }

Generated by: LCOV version 1.14