rootless: use auto cleanup functions

simplify code using auto cleanup functions

[NO NEW TESTS NEEDED] it is a refactoring of existing code

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano 2021-11-17 10:26:26 +01:00
parent c661664878
commit 277d526869
No known key found for this signature in database
GPG Key ID: 67E38F7A8BA21772
1 changed files with 97 additions and 106 deletions

View File

@ -19,6 +19,33 @@
#include <sys/select.h> #include <sys/select.h>
#include <stdio.h> #include <stdio.h>
#define cleanup_free __attribute__ ((cleanup (cleanup_freep)))
#define cleanup_close __attribute__ ((cleanup (cleanup_closep)))
#define cleanup_dir __attribute__ ((cleanup (cleanup_dirp)))
static inline void
cleanup_freep (void *p)
{
void **pp = (void **) p;
free (*pp);
}
static inline void
cleanup_closep (void *p)
{
int *pp = p;
if (*pp >= 0)
TEMP_FAILURE_RETRY (close (*pp));
}
static inline void
cleanup_dirp (DIR **p)
{
DIR *dir = *p;
if (dir)
closedir (dir);
}
int rename_noreplace (int olddirfd, const char *oldpath, int newdirfd, const char *newpath) int rename_noreplace (int olddirfd, const char *oldpath, int newdirfd, const char *newpath)
{ {
int ret; int ret;
@ -114,8 +141,8 @@ do_pause ()
static char ** static char **
get_cmd_line_args () get_cmd_line_args ()
{ {
int fd; cleanup_free char *buffer = NULL;
char *buffer; cleanup_close int fd = -1;
size_t allocated; size_t allocated;
size_t used = 0; size_t used = 0;
int ret; int ret;
@ -134,10 +161,7 @@ get_cmd_line_args ()
{ {
ret = TEMP_FAILURE_RETRY (read (fd, buffer + used, allocated - used)); ret = TEMP_FAILURE_RETRY (read (fd, buffer + used, allocated - used));
if (ret < 0) if (ret < 0)
{ return NULL;
free (buffer);
return NULL;
}
if (ret == 0) if (ret == 0)
break; break;
@ -148,30 +172,21 @@ get_cmd_line_args ()
allocated += 512; allocated += 512;
char *tmp = realloc (buffer, allocated); char *tmp = realloc (buffer, allocated);
if (tmp == NULL) if (tmp == NULL)
{ return NULL;
free (buffer);
return NULL;
}
buffer = tmp; buffer = tmp;
} }
} }
close (fd);
for (i = 0; i < used; i++) for (i = 0; i < used; i++)
if (buffer[i] == '\0') if (buffer[i] == '\0')
argc++; argc++;
if (argc == 0) if (argc == 0)
{ return NULL;
free (buffer);
return NULL;
}
argv = malloc (sizeof (char *) * (argc + 1)); argv = malloc (sizeof (char *) * (argc + 1));
if (argv == NULL) if (argv == NULL)
{ return NULL;
free (buffer);
return NULL;
}
argc = 0; argc = 0;
argv[argc++] = buffer; argv[argc++] = buffer;
@ -181,15 +196,19 @@ get_cmd_line_args ()
argv[argc] = NULL; argv[argc] = NULL;
/* Move ownership. */
buffer = NULL;
return argv; return argv;
} }
static bool static bool
can_use_shortcut () can_use_shortcut ()
{ {
int argc; cleanup_free char **argv = NULL;
char **argv; cleanup_free char *argv0 = NULL;
bool ret = true; bool ret = true;
int argc;
#ifdef DISABLE_JOIN_SHORTCUT #ifdef DISABLE_JOIN_SHORTCUT
return false; return false;
@ -199,12 +218,10 @@ can_use_shortcut ()
if (argv == NULL) if (argv == NULL)
return false; return false;
argv0 = argv[0];
if (strstr (argv[0], "podman") == NULL) if (strstr (argv[0], "podman") == NULL)
{ return false;
free (argv[0]);
free (argv);
return false;
}
for (argc = 0; argv[argc]; argc++) for (argc = 0; argv[argc]; argc++)
{ {
@ -229,8 +246,6 @@ can_use_shortcut ()
} }
} }
free (argv[0]);
free (argv);
return ret; return ret;
} }
@ -250,8 +265,7 @@ static void __attribute__((constructor)) init()
const char *listen_pid; const char *listen_pid;
const char *listen_fds; const char *listen_fds;
const char *listen_fdnames; const char *listen_fdnames;
cleanup_dir DIR *d = NULL;
DIR *d;
pause = getenv ("_PODMAN_PAUSE"); pause = getenv ("_PODMAN_PAUSE");
if (pause && pause[0]) if (pause && pause[0])
@ -299,7 +313,6 @@ static void __attribute__((constructor)) init()
FD_SET (fd % FD_SETSIZE, &(open_files_set[fd / FD_SETSIZE])); FD_SET (fd % FD_SETSIZE, &(open_files_set[fd / FD_SETSIZE]));
} }
closedir (d);
} }
listen_pid = getenv("LISTEN_PID"); listen_pid = getenv("LISTEN_PID");
@ -327,19 +340,22 @@ static void __attribute__((constructor)) init()
xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR");
if (geteuid () != 0 && xdg_runtime_dir && xdg_runtime_dir[0] && can_use_shortcut ()) if (geteuid () != 0 && xdg_runtime_dir && xdg_runtime_dir[0] && can_use_shortcut ())
{ {
int r; cleanup_free char *cwd = NULL;
int fd; cleanup_close int userns_fd = -1;
cleanup_close int mntns_fd = -1;
cleanup_close int fd = -1;
long pid; long pid;
char buf[12]; char buf[12];
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
char path[PATH_MAX]; char path[PATH_MAX];
const char *const suffix = "/libpod/tmp/pause.pid"; const char *const suffix = "/libpod/tmp/pause.pid";
char *cwd = getcwd (NULL, 0);
char uid_fmt[16]; char uid_fmt[16];
char gid_fmt[16]; char gid_fmt[16];
size_t len; size_t len;
int r;
cwd = getcwd (NULL, 0);
if (cwd == NULL) if (cwd == NULL)
{ {
fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); fprintf (stderr, "error getting current working directory: %s\n", strerror (errno));
@ -355,45 +371,40 @@ static void __attribute__((constructor)) init()
fd = open (path, O_RDONLY); fd = open (path, O_RDONLY);
if (fd < 0) if (fd < 0)
{ return;
free (cwd);
return;
}
r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf) - 1)); r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf) - 1));
close (fd);
if (r < 0) if (r < 0)
{ return;
free (cwd);
return;
}
buf[r] = '\0'; buf[r] = '\0';
pid = strtol (buf, NULL, 10); pid = strtol (buf, NULL, 10);
if (pid == LONG_MAX) if (pid == LONG_MAX)
{ return;
free (cwd);
return;
}
uid = geteuid (); uid = geteuid ();
gid = getegid (); gid = getegid ();
sprintf (path, "/proc/%ld/ns/user", pid); sprintf (path, "/proc/%ld/ns/user", pid);
fd = open (path, O_RDONLY); userns_fd = open (path, O_RDONLY);
if (fd < 0 || setns (fd, 0) < 0) if (userns_fd < 0)
{ return;
free (cwd);
return;
}
close (fd);
/* Errors here cannot be ignored as we already joined a ns. */
sprintf (path, "/proc/%ld/ns/mnt", pid); sprintf (path, "/proc/%ld/ns/mnt", pid);
fd = open (path, O_RDONLY); mntns_fd = open (path, O_RDONLY);
if (fd < 0) if (mntns_fd < 0)
return;
if (setns (userns_fd, 0) < 0)
return;
/* The user namespace was joined, after this point errors are
not recoverable anymore. */
if (setns (mntns_fd, 0) < 0)
{ {
fprintf (stderr, "cannot open %s: %s", path, strerror (errno)); fprintf (stderr, "cannot join mount namespace for %ld: %s", pid, strerror (errno));
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
@ -404,14 +415,6 @@ static void __attribute__((constructor)) init()
setenv ("_CONTAINERS_ROOTLESS_UID", uid_fmt, 1); setenv ("_CONTAINERS_ROOTLESS_UID", uid_fmt, 1);
setenv ("_CONTAINERS_ROOTLESS_GID", gid_fmt, 1); setenv ("_CONTAINERS_ROOTLESS_GID", gid_fmt, 1);
r = setns (fd, 0);
if (r < 0)
{
fprintf (stderr, "cannot join mount namespace for %ld: %s", pid, strerror (errno));
exit (EXIT_FAILURE);
}
close (fd);
if (syscall_setresgid (0, 0, 0) < 0) if (syscall_setresgid (0, 0, 0) < 0)
{ {
fprintf (stderr, "cannot setresgid: %s\n", strerror (errno)); fprintf (stderr, "cannot setresgid: %s\n", strerror (errno));
@ -430,7 +433,6 @@ static void __attribute__((constructor)) init()
_exit (EXIT_FAILURE); _exit (EXIT_FAILURE);
} }
free (cwd);
rootless_uid_init = uid; rootless_uid_init = uid;
rootless_gid_init = gid; rootless_gid_init = gid;
} }
@ -619,15 +621,17 @@ join_namespace_or_die (const char *name, int ns_fd)
int int
reexec_userns_join (int pid_to_join, char *pause_pid_file_path) reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
{ {
cleanup_close int userns_fd = -1;
cleanup_close int mntns_fd = -1;
cleanup_free char *cwd = NULL;
char uid[16]; char uid[16];
char gid[16]; char gid[16];
char **argv; cleanup_free char *argv0 = NULL;
cleanup_free char **argv = NULL;
int pid; int pid;
int mnt_ns = -1;
int user_ns = -1;
char *cwd = getcwd (NULL, 0);
sigset_t sigset, oldsigset; sigset_t sigset, oldsigset;
cwd = getcwd (NULL, 0);
if (cwd == NULL) if (cwd == NULL)
{ {
fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); fprintf (stderr, "error getting current working directory: %s\n", strerror (errno));
@ -644,15 +648,14 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
_exit (EXIT_FAILURE); _exit (EXIT_FAILURE);
} }
user_ns = open_namespace (pid_to_join, "user"); argv0 = argv[0];
if (user_ns < 0)
return user_ns; userns_fd = open_namespace (pid_to_join, "user");
mnt_ns = open_namespace (pid_to_join, "mnt"); if (userns_fd < 0)
if (mnt_ns < 0) return userns_fd;
{ mntns_fd = open_namespace (pid_to_join, "mnt");
close (user_ns); if (mntns_fd < 0)
return mnt_ns; return mntns_fd;
}
pid = fork (); pid = fork ();
if (pid < 0) if (pid < 0)
@ -662,10 +665,6 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
{ {
int f; int f;
/* We passed down these fds, close them. */
close (user_ns);
close (mnt_ns);
for (f = 3; f <= open_files_max_fd; f++) for (f = 3; f <= open_files_max_fd; f++)
if (is_fd_inherited (f)) if (is_fd_inherited (f))
close (f); close (f);
@ -721,10 +720,8 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
_exit (EXIT_FAILURE); _exit (EXIT_FAILURE);
} }
join_namespace_or_die ("user", user_ns); join_namespace_or_die ("user", userns_fd);
join_namespace_or_die ("mnt", mnt_ns); join_namespace_or_die ("mnt", mntns_fd);
close (user_ns);
close (mnt_ns);
if (syscall_setresgid (0, 0, 0) < 0) if (syscall_setresgid (0, 0, 0) < 0)
{ {
@ -743,7 +740,6 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
fprintf (stderr, "cannot chdir to %s: %s\n", cwd, strerror (errno)); fprintf (stderr, "cannot chdir to %s: %s\n", cwd, strerror (errno));
_exit (EXIT_FAILURE); _exit (EXIT_FAILURE);
} }
free (cwd);
if (pause_pid_file_path && pause_pid_file_path[0] != '\0') if (pause_pid_file_path && pause_pid_file_path[0] != '\0')
{ {
@ -784,7 +780,7 @@ static int
copy_file_to_fd (const char *file_to_read, int outfd) copy_file_to_fd (const char *file_to_read, int outfd)
{ {
char buf[512]; char buf[512];
int fd; cleanup_close int fd = -1;
fd = open (file_to_read, O_RDONLY); fd = open (file_to_read, O_RDONLY);
if (fd < 0) if (fd < 0)
@ -796,10 +792,7 @@ copy_file_to_fd (const char *file_to_read, int outfd)
r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof buf)); r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof buf));
if (r < 0) if (r < 0)
{ return r;
close (fd);
return r;
}
if (r == 0) if (r == 0)
break; break;
@ -808,36 +801,33 @@ copy_file_to_fd (const char *file_to_read, int outfd)
{ {
w = TEMP_FAILURE_RETRY (write (outfd, &buf[t], r - t)); w = TEMP_FAILURE_RETRY (write (outfd, &buf[t], r - t));
if (w < 0) if (w < 0)
{ return w;
close (fd);
return w;
}
t += w; t += w;
} }
} }
close (fd);
return 0; return 0;
} }
int int
reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_read, int outputfd) reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_read, int outputfd)
{ {
cleanup_free char **argv = NULL;
cleanup_free char *argv0 = NULL;
cleanup_free char *cwd = NULL;
sigset_t sigset, oldsigset;
int ret; int ret;
pid_t pid; pid_t pid;
char b; char b;
char **argv;
char uid[16]; char uid[16];
char gid[16]; char gid[16];
char *cwd = getcwd (NULL, 0);
sigset_t sigset, oldsigset;
cwd = getcwd (NULL, 0);
if (cwd == NULL) if (cwd == NULL)
{ {
fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); fprintf (stderr, "error getting current working directory: %s\n", strerror (errno));
_exit (EXIT_FAILURE); _exit (EXIT_FAILURE);
} }
sprintf (uid, "%d", geteuid ()); sprintf (uid, "%d", geteuid ());
sprintf (gid, "%d", getegid ()); sprintf (gid, "%d", getegid ());
@ -898,6 +888,8 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
_exit (EXIT_FAILURE); _exit (EXIT_FAILURE);
} }
argv0 = argv[0];
if (do_socket_activation) if (do_socket_activation)
{ {
char s[32]; char s[32];
@ -942,7 +934,6 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
TEMP_FAILURE_RETRY (write (ready, "1", 1)); TEMP_FAILURE_RETRY (write (ready, "1", 1));
_exit (EXIT_FAILURE); _exit (EXIT_FAILURE);
} }
free (cwd);
if (pause_pid_file_path && pause_pid_file_path[0] != '\0') if (pause_pid_file_path && pause_pid_file_path[0] != '\0')
{ {
@ -956,8 +947,8 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
ret = TEMP_FAILURE_RETRY (write (ready, "0", 1)); ret = TEMP_FAILURE_RETRY (write (ready, "0", 1));
if (ret < 0) if (ret < 0)
{ {
fprintf (stderr, "cannot write to ready pipe: %s\n", strerror (errno)); fprintf (stderr, "cannot write to ready pipe: %s\n", strerror (errno));
_exit (EXIT_FAILURE); _exit (EXIT_FAILURE);
} }
close (ready); close (ready);