newuidmap and newgidmap: support passing pid as fd
Closes #635 newuidmap and newgidmap currently take an integner pid as the first argument, determining the process id on which to act. Accept also "fd:N", where N must be an open file descriptor to the /proc/pid directory for the process to act upon. This way, if you exec 10</proc/99 newuidmap fd:10 100000 0 65536 and pid 99 dies and a new process happens to take pid 99 before newuidmap happens to do its work, then since newuidmap will use openat() using fd 10, it won't change the mapping for the new process. Example: // terminal 1: serge@jerom ~/src/nsexec$ ./nsexec -W -s 0 -S 0 -U about to unshare with 10000000 Press any key to exec (I am 129176) // terminal 2: serge@jerom ~/src/shadow$ exec 10</proc/129176 serge@jerom ~/src/shadow$ sudo chown root src/newuidmap src/newgidmap serge@jerom ~/src/shadow$ sudo chmod u+s src/newuidmap serge@jerom ~/src/shadow$ sudo chmod u+s src/newgidmap serge@jerom ~/src/shadow$ ./src/newuidmap fd:10 0 100000 10 serge@jerom ~/src/shadow$ ./src/newgidmap fd:10 0 100000 10 // Terminal 1: uid=0(root) gid=0(root) groups=0(root) Signed-off-by: Serge Hallyn <serge@hallyn.com>
This commit is contained in:
@@ -69,7 +69,7 @@ static void verify_ranges(struct passwd *pw, int ranges,
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, _("usage: %s <pid> <gid> <lowergid> <count> [ <gid> <lowergid> <count> ] ... \n"), Prog);
|
||||
fprintf(stderr, _("usage: %s [<pid|fd:<pidfd>] <gid> <lowergid> <count> [ <gid> <lowergid> <count> ] ... \n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -143,15 +143,12 @@ out:
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char proc_dir_name[32];
|
||||
char *target_str;
|
||||
pid_t target;
|
||||
int proc_dir_fd;
|
||||
int ranges;
|
||||
struct map_range *mappings;
|
||||
struct stat st;
|
||||
struct passwd *pw;
|
||||
int written;
|
||||
bool allow_setgroups = false;
|
||||
|
||||
Prog = Basename (argv[0]);
|
||||
@@ -168,25 +165,19 @@ int main(int argc, char **argv)
|
||||
/* Find the process that needs its user namespace
|
||||
* gid mapping set.
|
||||
*/
|
||||
|
||||
target_str = argv[1];
|
||||
if (!get_pid(target_str, &target))
|
||||
usage();
|
||||
|
||||
/* max string length is 6 + 10 + 1 + 1 = 18, allocate 32 bytes */
|
||||
written = snprintf(proc_dir_name, sizeof(proc_dir_name), "/proc/%u/",
|
||||
target);
|
||||
if ((written <= 0) || ((size_t)written >= sizeof(proc_dir_name))) {
|
||||
fprintf(stderr, "%s: snprintf of proc path failed: %s\n",
|
||||
Prog, strerror(errno));
|
||||
if (strlen(target_str) > 3 && strncmp(target_str, "fd:", 3) == 0) {
|
||||
/* the user passed in a /proc/pid fd for the process */
|
||||
target_str = &target_str[3];
|
||||
proc_dir_fd = get_pidfd_from_fd(target_str);
|
||||
if (proc_dir_fd < 0)
|
||||
usage();
|
||||
} else {
|
||||
proc_dir_fd = open_pidfd(target_str);
|
||||
if (proc_dir_fd < 0)
|
||||
usage();
|
||||
}
|
||||
|
||||
proc_dir_fd = open(proc_dir_name, O_DIRECTORY);
|
||||
if (proc_dir_fd < 0) {
|
||||
fprintf(stderr, _("%s: Could not open proc directory for target %u\n"),
|
||||
Prog, target);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Who am i? */
|
||||
pw = get_my_pwent ();
|
||||
if (NULL == pw) {
|
||||
@@ -200,8 +191,8 @@ int main(int argc, char **argv)
|
||||
|
||||
/* Get the effective uid and effective gid of the target process */
|
||||
if (fstat(proc_dir_fd, &st) < 0) {
|
||||
fprintf(stderr, _("%s: Could not stat directory for target %u\n"),
|
||||
Prog, target);
|
||||
fprintf(stderr, _("%s: Could not stat directory for process\n"),
|
||||
Prog);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -213,8 +204,8 @@ int main(int argc, char **argv)
|
||||
(!getdef_bool("GRANT_AUX_GROUP_SUBIDS") && (getgid() != pw->pw_gid)) ||
|
||||
(pw->pw_uid != st.st_uid) ||
|
||||
(getgid() != st.st_gid)) {
|
||||
fprintf(stderr, _( "%s: Target %u is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ),
|
||||
Prog, target,
|
||||
fprintf(stderr, _( "%s: Target process is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ),
|
||||
Prog,
|
||||
(unsigned long int)getuid(), (unsigned long int)pw->pw_uid, (unsigned long int)st.st_uid,
|
||||
(unsigned long int)getgid(), (unsigned long int)pw->pw_gid, (unsigned long int)st.st_gid);
|
||||
return EXIT_FAILURE;
|
||||
|
@@ -64,7 +64,7 @@ static void verify_ranges(struct passwd *pw, int ranges,
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, _("usage: %s <pid> <uid> <loweruid> <count> [ <uid> <loweruid> <count> ] ... \n"), Prog);
|
||||
fprintf(stderr, _("usage: %s [<pid>|fd:<pidfd>] <uid> <loweruid> <count> [ <uid> <loweruid> <count> ] ... \n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -73,15 +73,12 @@ static void usage(void)
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char proc_dir_name[32];
|
||||
char *target_str;
|
||||
pid_t target;
|
||||
int proc_dir_fd;
|
||||
int ranges;
|
||||
struct map_range *mappings;
|
||||
struct stat st;
|
||||
struct passwd *pw;
|
||||
int written;
|
||||
|
||||
Prog = Basename (argv[0]);
|
||||
log_set_progname(Prog);
|
||||
@@ -94,26 +91,20 @@ int main(int argc, char **argv)
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
target_str = argv[1];
|
||||
/* Find the process that needs its user namespace
|
||||
* uid mapping set.
|
||||
*/
|
||||
target_str = argv[1];
|
||||
if (!get_pid(target_str, &target))
|
||||
usage();
|
||||
|
||||
/* max string length is 6 + 10 + 1 + 1 = 18, allocate 32 bytes */
|
||||
written = snprintf(proc_dir_name, sizeof(proc_dir_name), "/proc/%u/",
|
||||
target);
|
||||
if ((written <= 0) || ((size_t)written >= sizeof(proc_dir_name))) {
|
||||
fprintf(stderr, "%s: snprintf of proc path failed: %s\n",
|
||||
Prog, strerror(errno));
|
||||
}
|
||||
|
||||
proc_dir_fd = open(proc_dir_name, O_DIRECTORY);
|
||||
if (proc_dir_fd < 0) {
|
||||
fprintf(stderr, _("%s: Could not open proc directory for target %u\n"),
|
||||
Prog, target);
|
||||
return EXIT_FAILURE;
|
||||
if (strlen(target_str) > 3 && strncmp(target_str, "fd:", 3) == 0) {
|
||||
/* the user passed in a /proc/pid fd for the process */
|
||||
target_str = &target_str[3];
|
||||
proc_dir_fd = get_pidfd_from_fd(target_str);
|
||||
if (proc_dir_fd < 0)
|
||||
usage();
|
||||
} else {
|
||||
proc_dir_fd = open_pidfd(target_str);
|
||||
if (proc_dir_fd < 0)
|
||||
usage();
|
||||
}
|
||||
|
||||
/* Who am i? */
|
||||
@@ -129,8 +120,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* Get the effective uid and effective gid of the target process */
|
||||
if (fstat(proc_dir_fd, &st) < 0) {
|
||||
fprintf(stderr, _("%s: Could not stat directory for target %u\n"),
|
||||
Prog, target);
|
||||
fprintf(stderr, _("%s: Could not stat directory for target process\n"), Prog);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -142,8 +132,8 @@ int main(int argc, char **argv)
|
||||
(!getdef_bool("GRANT_AUX_GROUP_SUBIDS") && (getgid() != pw->pw_gid)) ||
|
||||
(pw->pw_uid != st.st_uid) ||
|
||||
(getgid() != st.st_gid)) {
|
||||
fprintf(stderr, _( "%s: Target process %u is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ),
|
||||
Prog, target,
|
||||
fprintf(stderr, _( "%s: Target process is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ),
|
||||
Prog,
|
||||
(unsigned long int)getuid(), (unsigned long int)pw->pw_uid, (unsigned long int)st.st_uid,
|
||||
(unsigned long int)getgid(), (unsigned long int)pw->pw_gid, (unsigned long int)st.st_gid);
|
||||
return EXIT_FAILURE;
|
||||
|
Reference in New Issue
Block a user