Skip to content

Commit

Permalink
nsenter: cloned_binary: detect and handle short copies
Browse files Browse the repository at this point in the history
For a variety of reasons, sendfile(2) can end up doing a short-copy so
we need to just loop until we hit the binary size. Since /proc/self/exe
is tautologically our own binary, there's no chance someone is going to
modify it underneath us (or changing the size).

Signed-off-by: Aleksa Sarai <asarai@suse.de>
  • Loading branch information
cyphar committed Feb 26, 2019
1 parent f79e211 commit 5b775bf
Showing 1 changed file with 14 additions and 4 deletions.
18 changes: 14 additions & 4 deletions libcontainer/nsenter/cloned_binary.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ int memfd_create(const char *name, unsigned int flags)
# define F_SEAL_WRITE 0x0008 /* prevent writes */
#endif

#define RUNC_SENDFILE_MAX 0x7FFFF000 /* sendfile(2) is limited to 2GB. */
#ifdef HAVE_MEMFD_CREATE
# define RUNC_MEMFD_COMMENT "runc_cloned:/proc/self/exe"
# define RUNC_MEMFD_SEALS \
Expand Down Expand Up @@ -195,7 +194,8 @@ static int fetchve(char ***argv)
static int clone_binary(void)
{
int binfd, memfd;
ssize_t sent = 0;
struct stat statbuf = {};
size_t sent = 0;

#ifdef HAVE_MEMFD_CREATE
memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);
Expand All @@ -209,9 +209,17 @@ static int clone_binary(void)
if (binfd < 0)
goto error;

sent = sendfile(memfd, binfd, NULL, RUNC_SENDFILE_MAX);
if (fstat(binfd, &statbuf) < 0)
goto error_binfd;

while (sent < statbuf.st_size) {
int n = sendfile(memfd, binfd, NULL, statbuf.st_size - sent);
if (n < 0)
goto error_binfd;
sent += n;
}
close(binfd);
if (sent < 0)
if (sent != statbuf.st_size)
goto error;

#ifdef HAVE_MEMFD_CREATE
Expand All @@ -235,6 +243,8 @@ static int clone_binary(void)
#endif
return memfd;

error_binfd:
close(binfd);
error:
close(memfd);
return -EIO;
Expand Down

0 comments on commit 5b775bf

Please sign in to comment.