attach: harden open calls

parent cce677d1
...@@ -231,7 +231,7 @@ static int userns_setup_ids(struct attach_context *ctx, ...@@ -231,7 +231,7 @@ static int userns_setup_ids(struct attach_context *ctx,
if (!(options->namespaces & CLONE_NEWUSER)) if (!(options->namespaces & CLONE_NEWUSER))
return 0; return 0;
f_uidmap = fdopenat(ctx->dfd_init_pid, "uid_map", "re"); f_uidmap = fdopen_at(ctx->dfd_init_pid, "uid_map", "re", PROTECT_OPEN, PROTECT_LOOKUP_ABSOLUTE);
if (!f_uidmap) if (!f_uidmap)
return log_error_errno(-errno, errno, "Failed to open uid_map"); return log_error_errno(-errno, errno, "Failed to open uid_map");
...@@ -251,7 +251,7 @@ static int userns_setup_ids(struct attach_context *ctx, ...@@ -251,7 +251,7 @@ static int userns_setup_ids(struct attach_context *ctx,
} }
} }
f_gidmap = fdopenat(ctx->dfd_init_pid, "gid_map", "re"); f_gidmap = fdopen_at(ctx->dfd_init_pid, "gid_map", "re", PROTECT_OPEN, PROTECT_LOOKUP_ABSOLUTE);
if (!f_gidmap) if (!f_gidmap)
return log_error_errno(-errno, errno, "Failed to open gid_map"); return log_error_errno(-errno, errno, "Failed to open gid_map");
...@@ -316,7 +316,7 @@ static int parse_init_status(struct attach_context *ctx, lxc_attach_options_t *o ...@@ -316,7 +316,7 @@ static int parse_init_status(struct attach_context *ctx, lxc_attach_options_t *o
bool caps_found = false; bool caps_found = false;
int ret; int ret;
f = fdopenat(ctx->dfd_init_pid, "status", "re"); f = fdopen_at(ctx->dfd_init_pid, "status", "re", PROTECT_OPEN, PROTECT_LOOKUP_ABSOLUTE);
if (!f) if (!f)
return log_error_errno(-errno, errno, "Failed to open status file"); return log_error_errno(-errno, errno, "Failed to open status file");
...@@ -389,7 +389,9 @@ static int get_attach_context(struct attach_context *ctx, ...@@ -389,7 +389,9 @@ static int get_attach_context(struct attach_context *ctx,
if (ctx->init_pid < 0) if (ctx->init_pid < 0)
return log_error(-1, "Failed to get init pid"); return log_error(-1, "Failed to get init pid");
ctx->dfd_self_pid = openat(-EBADF, "/proc/self", O_CLOEXEC | O_NOCTTY | O_PATH | O_DIRECTORY); ctx->dfd_self_pid = open_at(-EBADF, "/proc/self",
PROTECT_OPATH_FILE & ~O_NOFOLLOW,
(PROTECT_LOOKUP_ABSOLUTE_WITH_SYMLINKS & ~RESOLVE_NO_XDEV), 0);
if (ctx->dfd_self_pid < 0) if (ctx->dfd_self_pid < 0)
return log_error_errno(-errno, errno, "Failed to open /proc/self"); return log_error_errno(-errno, errno, "Failed to open /proc/self");
...@@ -397,7 +399,9 @@ static int get_attach_context(struct attach_context *ctx, ...@@ -397,7 +399,9 @@ static int get_attach_context(struct attach_context *ctx,
if (ret < 0 || ret >= sizeof(path)) if (ret < 0 || ret >= sizeof(path))
return ret_errno(EIO); return ret_errno(EIO);
ctx->dfd_init_pid = openat(-EBADF, path, O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_PATH | O_DIRECTORY); ctx->dfd_init_pid = open_at(-EBADF, path,
PROTECT_OPATH_DIRECTORY,
(PROTECT_LOOKUP_ABSOLUTE & ~RESOLVE_NO_XDEV), 0);
if (ctx->dfd_init_pid < 0) if (ctx->dfd_init_pid < 0)
return log_error_errno(-errno, errno, "Failed to open /proc/%d", ctx->init_pid); return log_error_errno(-errno, errno, "Failed to open /proc/%d", ctx->init_pid);
...@@ -460,24 +464,30 @@ static int get_attach_context(struct attach_context *ctx, ...@@ -460,24 +464,30 @@ static int get_attach_context(struct attach_context *ctx,
return 0; return 0;
} }
static int in_same_namespace(int ns_fd_pid1, int ns_fd_pid2, const char *ns_path) static int same_ns(int ns_fd_pid1, int ns_fd_pid2, const char *ns_path)
{ {
__do_close int ns_fd1 = -EBADF, ns_fd2 = -EBADF; __do_close int ns_fd1 = -EBADF, ns_fd2 = -EBADF;
int ret = -1; int ret = -1;
struct stat ns_st1, ns_st2; struct stat ns_st1, ns_st2;
ns_fd1 = openat(ns_fd_pid1, ns_path, O_CLOEXEC | O_NOCTTY | O_RDONLY); ns_fd1 = open_at(ns_fd_pid1, ns_path,
PROTECT_OPEN_WITH_TRAILING_SYMLINKS,
(PROTECT_LOOKUP_BENEATH_WITH_MAGICLINKS & ~(RESOLVE_NO_XDEV | RESOLVE_BENEATH)),
0);
if (ns_fd1 < 0) { if (ns_fd1 < 0) {
/* The kernel does not support this namespace. This is not an error. */ /* The kernel does not support this namespace. This is not an error. */
if (errno == ENOENT) if (errno == ENOENT)
return -EINVAL; return -EINVAL;
return -1; return log_error_errno(-errno, errno, "Failed to open %d(%s)", ns_fd_pid1, ns_path);
} }
ns_fd2 = openat(ns_fd_pid2, ns_path, O_CLOEXEC | O_NOCTTY | O_RDONLY); ns_fd2 = open_at(ns_fd_pid2, ns_path,
PROTECT_OPEN_WITH_TRAILING_SYMLINKS,
(PROTECT_LOOKUP_BENEATH_WITH_MAGICLINKS & ~(RESOLVE_NO_XDEV | RESOLVE_BENEATH)),
0);
if (ns_fd2 < 0) if (ns_fd2 < 0)
return -1; return log_error_errno(-errno, errno, "Failed to open %d(%s)", ns_fd_pid2, ns_path);
ret = fstat(ns_fd1, &ns_st1); ret = fstat(ns_fd1, &ns_st1);
if (ret < 0) if (ret < 0)
...@@ -503,9 +513,15 @@ static int get_attach_context_nsfds(struct attach_context *ctx, ...@@ -503,9 +513,15 @@ static int get_attach_context_nsfds(struct attach_context *ctx,
int j; int j;
if (options->namespaces & ns_info[i].clone_flag) if (options->namespaces & ns_info[i].clone_flag)
ctx->ns_fd[i] = openat(ctx->dfd_init_pid, ns_info[i].proc_path, O_CLOEXEC | O_NOCTTY | O_RDONLY); ctx->ns_fd[i] = open_at(ctx->dfd_init_pid,
ns_info[i].proc_path,
PROTECT_OPEN_WITH_TRAILING_SYMLINKS,
(PROTECT_LOOKUP_BENEATH_WITH_MAGICLINKS & ~(RESOLVE_NO_XDEV | RESOLVE_BENEATH)),
0);
else if (ctx->ns_inherited & ns_info[i].clone_flag) else if (ctx->ns_inherited & ns_info[i].clone_flag)
ctx->ns_fd[i] = in_same_namespace(ctx->dfd_self_pid, ctx->dfd_init_pid, ns_info[i].proc_path); ctx->ns_fd[i] = same_ns(ctx->dfd_self_pid,
ctx->dfd_init_pid,
ns_info[i].proc_path);
else else
continue; continue;
......
...@@ -553,7 +553,8 @@ static inline int dup_cloexec(int fd) ...@@ -553,7 +553,8 @@ static inline int dup_cloexec(int fd)
return move_fd(fd_dup); return move_fd(fd_dup);
} }
FILE *fdopenat(int dfd, const char *path, const char *mode) FILE *fdopen_at(int dfd, const char *path, const char *mode,
unsigned int o_flags, unsigned int resolve_flags)
{ {
__do_close int fd = -EBADF; __do_close int fd = -EBADF;
__do_fclose FILE *f = NULL; __do_fclose FILE *f = NULL;
...@@ -561,7 +562,7 @@ FILE *fdopenat(int dfd, const char *path, const char *mode) ...@@ -561,7 +562,7 @@ FILE *fdopenat(int dfd, const char *path, const char *mode)
if (is_empty_string(path)) if (is_empty_string(path))
fd = dup_cloexec(dfd); fd = dup_cloexec(dfd);
else else
fd = openat(dfd, path, O_CLOEXEC | O_NOCTTY | O_NOFOLLOW); fd = open_at(dfd, path, o_flags, resolve_flags, 0);
if (fd < 0) if (fd < 0)
return NULL; return NULL;
......
...@@ -77,7 +77,9 @@ static inline int fd_to_fd(int from, int to) ...@@ -77,7 +77,9 @@ static inline int fd_to_fd(int from, int to)
__hidden extern int fd_cloexec(int fd, bool cloexec); __hidden extern int fd_cloexec(int fd, bool cloexec);
__hidden extern int lxc_open_dirfd(const char *dir); __hidden extern int lxc_open_dirfd(const char *dir);
__hidden extern FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer); __hidden extern FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer);
__hidden extern FILE *fdopenat(int dfd, const char *path, const char *mode); __hidden extern FILE *fdopen_at(int dfd, const char *path, const char *mode,
unsigned int o_flags,
unsigned int resolve_flags);
__hidden extern FILE *fopen_cached(const char *path, const char *mode, void **caller_freed_buffer); __hidden extern FILE *fopen_cached(const char *path, const char *mode, void **caller_freed_buffer);
__hidden extern int timens_offset_write(clockid_t clk_id, int64_t s_offset, int64_t ns_offset); __hidden extern int timens_offset_write(clockid_t clk_id, int64_t s_offset, int64_t ns_offset);
__hidden extern bool exists_dir_at(int dir_fd, const char *path); __hidden extern bool exists_dir_at(int dir_fd, const char *path);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment