nsenter: cloned_binary: detect and handle short copies

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>
This commit is contained in:
Aleksa Sarai 2019-02-16 01:18:14 +11:00
parent f79e211b1d
commit 5b775bf297
No known key found for this signature in database
GPG Key ID: 9E18AA267DDB8DB4
1 changed files with 14 additions and 4 deletions

View File

@ -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 \
@ -195,7 +194,8 @@ error:
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);
@ -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
@ -235,6 +243,8 @@ static int clone_binary(void)
#endif
return memfd;
error_binfd:
close(binfd);
error:
close(memfd);
return -EIO;