Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
bgColor#ccccff
/*  Drop superuser privileges in correct order */

if (setgid(getgid()) == -1) {
  /* handle error condition */
}
if (setuid(getuid()) == -1) {
  /* handle error condition */
}

/*
 * Not possible to regain group privileges due to correct relinquishment order 
 */

...

Supplementary Group

...

IDs

A process may have a number of supplementary group IDs in addition to its effective group ID, and the supplementary groups can allow privileged access to filesAny user, including root, may belong to multiple groups; these are handled by supplemental group privileges. The getgroups() function returns an array of which contains the supplementary group IDs , and may also contain the effective group ID. The setgroups() function can set the array to an arbitrary array, but usually only if the user has root set the supplementary group IDs and may also set the effective group ID on some systems. Using setgroups() usually requires privileges. While POSIX defines the getgroups() function, it does not define setgroups().

Under normal circumstances setuid() and related calls do not alter the supplemental supplementary group privilegesIDs. However, a setuid-root program can grant itself supplemental group ids alter its supplementary group IDs and then relinquish root privileges, in which icase case it maintains the supplemental supplementary group idsIDs, but lacks the privilege necessary to relinquish them. Consequently, it is recommended that a program relinquish supplemental supplementary group privileges IDs immediately before relinquishing root privileges. The following code defines a set_sups() function that will portably set the supplemental group privileges IDs to a specific array on systems that support the setgroups() function.

Code Block
bgColor#ccccff
/* Returns nonzero if the two group lists are equivalent (taking into
   account that the lists may differ wrt the egid */
int eql_sups(const int cursups_size, const gid_t* const cursups_list,
	     const int targetsups_size, const gid_t* const targetsups_list) {
  int i;
  int j;
  const int n = targetsups_size;
  const int diff = cursups_size - targetsups_size;
  const gid_t egid = getegid();
  if (diff > 1 || diff < 0 ) {
    return 0;
  }
  for (i=0, j=0; i < n; i++, j++) {
    if (cursups_list[j] != targetsups_list[i]) {
      if (cursups_list[j] == egid) {
	i--; /* skipping j */
      } else {
	return 0;
      }
    }
  }
  /* If reached here, we're sure i==targetsups_size. Now, either
     j==cursups_size (skipped the egid or it wasn't there), or we didn't
     get to the egid yet because it's the last entry in cursups */
  return j == cursups_size ||
    (j+1 == cursups_size && cursups_list[j] == egid);
}


/* Sets the suplimentary group list, returns 0 if successful  */
int set_sups(const int target_sups_size,const gid_t* const target_sups_list) {
#ifdef __FreeBSD__
  const int targetsups_size = target_sups_size + 1;
  gid_t* const targetsups_list = (gid_t* const) malloc(sizeof(gid_t) * targetsups_size);
  if (targetsups_list == NULL) {
    /* handle error */
  }
  memcpy(targetsups_list+1, target_sups_list, target_sups_size * sizeof(gid_t) );
  targetsups_list[0] = getegid();
#else
  const int targetsups_size = target_sups_size;
  const gid_t* const targetsups_list = target_sups_list;
#endif
  if (geteuid() == 0) { /* allowed to setgroups, let's not take any chances */
    if (-1 == setgroups(targetsups_size, targetsups_list)) {
      /* handle error */
    }
  } else {
    int cursups_size = getgroups( 0, NULL);
    gid_t* cursups_list = (gid_t*) malloc( sizeof(gid_t) * cursups_size);
    if (cursups_list == NULL) {
      /* handle error */
    }
    if (-1 == getgroups( cursups_size, cursups_list)) {
      /* handle error */
    }
    if (!eql_sups(cursups_size, cursups_list, targetsups_size, targetsups_list)) {
      if (-1 == setgroups(targetsups_size, targetsups_list)) { /* will probably fail... :( */
	/* handle error */
      }
    }
    free( cursups_list);
  }

#ifdef __FreeBSD__
  free( targetsups_list);
#endif
  return 0;
}

...