github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/cmd/libsnap-confine-private/privs.c (about)

     1  /*
     2   * Copyright (C) 2017 Canonical Ltd
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License version 3 as
     6   * published by the Free Software Foundation.
     7   *
     8   * This program is distributed in the hope that it will be useful,
     9   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11   * GNU General Public License for more details.
    12   *
    13   * You should have received a copy of the GNU General Public License
    14   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15   *
    16   */
    17  
    18  #include "privs.h"
    19  
    20  #define _GNU_SOURCE
    21  
    22  #include <unistd.h>
    23  
    24  #include <grp.h>
    25  #include <stdbool.h>
    26  #include <sys/capability.h>
    27  #include <sys/types.h>
    28  #include <unistd.h>
    29  
    30  #include "utils.h"
    31  
    32  static bool sc_has_capability(const char *cap_name)
    33  {
    34  	// Lookup capability with the given name.
    35  	cap_value_t cap;
    36  	if (cap_from_name(cap_name, &cap) < 0) {
    37  		die("cannot resolve capability name %s", cap_name);
    38  	}
    39  	// Get the capability state of the current process.
    40  	cap_t caps;
    41  	if ((caps = cap_get_proc()) == NULL) {
    42  		die("cannot obtain capability state (cap_get_proc)");
    43  	}
    44  	// Read the effective value of the flag we're dealing with
    45  	cap_flag_value_t cap_flags_value;
    46  	if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &cap_flags_value) < 0) {
    47  		cap_free(caps);	// don't bother checking, we die anyway.
    48  		die("cannot obtain value of capability flag (cap_get_flag)");
    49  	}
    50  	// Free the representation of the capability state of the current process.
    51  	if (cap_free(caps) < 0) {
    52  		die("cannot free capability flag (cap_free)");
    53  	}
    54  	// Check if the effective bit of the capability is set.
    55  	return cap_flags_value == CAP_SET;
    56  }
    57  
    58  void sc_privs_drop(void)
    59  {
    60  	gid_t gid = getgid();
    61  	uid_t uid = getuid();
    62  
    63  	// Drop extra group membership if we can.
    64  	if (sc_has_capability("cap_setgid")) {
    65  		gid_t gid_list[1] = { gid };
    66  		if (setgroups(1, gid_list) < 0) {
    67  			die("cannot set supplementary group identifiers");
    68  		}
    69  	}
    70  	// Switch to real group ID
    71  	if (setgid(getgid()) < 0) {
    72  		die("cannot set group identifier to %d", gid);
    73  	}
    74  	// Switch to real user ID
    75  	if (setuid(getuid()) < 0) {
    76  		die("cannot set user identifier to %d", uid);
    77  	}
    78  }