mrrl

Minimal Reliable Reproducible Linux
git clone https://ccx.te2000.cz/git/mrrl
Log | Files | Refs | Submodules | README

applyuidgid-caps.c (3140B)


      1 /* ISC license. */
      2 
      3 #include <unistd.h>
      4 #include <grp.h>
      5 #include <limits.h>
      6 #include <stdlib.h>
      7 #include <sys/prctl.h>
      8 #include <sys/capability.h>
      9 #include <linux/securebits.h>
     10 
     11 #include <skalibs/types.h>
     12 #include <skalibs/setgroups.h>
     13 #include <skalibs/strerr2.h>
     14 #include <skalibs/sgetopt.h>
     15 #include <skalibs/djbunix.h>
     16 #include <skalibs/exec.h>
     17 
     18 #define USAGE "applyuidgid-caps [ -z ] [ -u uid ] [ -g gid ] [ -G gidlist ] [ -U ] iab_caps prog..."
     19 #define dieusage() strerr_dieusage(100, USAGE)
     20 
     21 int main (int argc, char const *const *argv)
     22 {
     23   uid_t uid = 0 ;
     24   gid_t gid = 0 ;
     25   gid_t gids[NGROUPS_MAX+1] ;
     26   size_t gidn = (size_t)-1 ;
     27   int unexport = 0 ;
     28   PROG = "s6-applyuidgid" ;
     29   {
     30     subgetopt l = SUBGETOPT_ZERO ;
     31     for (;;)
     32     {
     33       int opt = subgetopt_r(argc, argv, "zUu:g:G:", &l) ;
     34       if (opt == -1) break ;
     35       switch (opt)
     36       {
     37         case 'z' : unexport = 1 ; break ;
     38         case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ;
     39         case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ;
     40         case 'G' : if (!gid_scanlist(gids, NGROUPS_MAX, l.arg, &gidn) && *l.arg) dieusage() ; break ;
     41         case 'U' :
     42         {
     43           char const *x = getenv("UID") ;
     44           if (!x) strerr_dienotset(100, "UID") ;
     45           if (!uid0_scan(x, &uid)) strerr_dieinvalid(100, "UID") ;
     46           x = getenv("GID") ;
     47           if (!x) strerr_dienotset(100, "GID") ;
     48           if (!gid0_scan(x, &gid)) strerr_dieinvalid(100, "GID") ;
     49           x = getenv("GIDLIST") ;
     50           if (!x) strerr_dienotset(100, "GIDLIST") ;
     51           if (!gid_scanlist(gids, NGROUPS_MAX+1, x, &gidn) && *x)
     52             strerr_dieinvalid(100, "GIDLIST") ;
     53           break ;
     54         }
     55         default : dieusage() ;
     56       }
     57     }
     58     argc -= l.ind ; argv += l.ind ;
     59   }
     60   if (argc < 2) dieusage() ;
     61 
     62   /*
     63    The IAB 3-tuple of capability vectors (Inh, Amb and Bound),
     64    captured in type cap_iab_t combine to pass capabilities
     65    from one process to another through execve(2) system calls.
     66    */
     67 
     68   /* parse the first argument to obtain a set of capabilities */
     69   cap_iab_t new_iab;
     70   new_iab = cap_iab_from_text(argv[0]);
     71   if (new_iab == NULL) {
     72     strerr_dieinvalid(100, "caps") ;
     73     // strerr_dief1sys(100, "requested capabilities were not recognized");
     74   }
     75 
     76   if (prctl(PR_SET_SECUREBITS,
     77       SECBIT_KEEP_CAPS | /* unneeded as NO_SETUID_FIXUP is superset */
     78       SECBIT_NO_SETUID_FIXUP |
     79       SECBIT_NOROOT | /* disables suid and filecap privilege gain */
     80       SECBIT_NOROOT_LOCKED) < 0) {
     81     strerr_dief1sys(111, "Failed to set securebits via prctl()");
     82   }
     83   /* set these capabilities for the current process */
     84   if (cap_iab_set_proc(new_iab) != 0) {
     85     strerr_dief1sys(111, "Failed to set capabilities via cap_set_proc()");
     86   }
     87 
     88   if (gidn != (size_t)-1 && setgroups_and_gid(gid ? gid : getegid(), gidn, gids) < 0)
     89     strerr_diefu1sys(111, "set supplementary group list") ;
     90   if (gid && setgid(gid) < 0)
     91     strerr_diefu1sys(111, "setgid") ;
     92   if (uid && setuid(uid) < 0)
     93     strerr_diefu1sys(111, "setuid") ;
     94 
     95   if (unexport) xmexec_n(argv, "UID\0GID\0GIDLIST", 16, 3) ;
     96   else xexec(&argv[1]) ;
     97 }