Skip to content

Commit

Permalink
nsenter: cloned_binary: userspace copy fallback if sendfile fails
Browse files Browse the repository at this point in the history
There are some circumstances where sendfile(2) can fail (one example is
that AppArmor appears to block writing to deleted files with sendfile(2)
under some circumstances) and so we need to have a userspace fallback.
It's fairly trivial (and handles short-writes).

Signed-off-by: Aleksa Sarai <asarai@suse.de>
  • Loading branch information
cyphar committed Mar 1, 2019
1 parent 16612d7 commit 2d4a37b
Showing 1 changed file with 34 additions and 3 deletions.
37 changes: 34 additions & 3 deletions libcontainer/nsenter/cloned_binary.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ static char *read_file(char *path, size_t *length)

*length = 0;
for (;;) {
int n;
ssize_t n;

n = read(fd, buf, sizeof(buf));
if (n < 0)
Expand Down Expand Up @@ -403,6 +403,33 @@ static int try_bindfd(void)
return ret;
}

static ssize_t fd_to_fd(int outfd, int infd)
{
ssize_t total = 0;
char buffer[4096];

for (;;) {
ssize_t nread, nwritten = 0;

nread = read(infd, buffer, sizeof(buffer));
if (nread < 0)
return -1;
if (!nread)
break;

do {
ssize_t n = write(outfd, buffer + nwritten, nread - nwritten);
if (n < 0)
return -1;
nwritten += n;
} while(nwritten < nread);

total += nwritten;
}

return total;
}

static int clone_binary(void)
{
int binfd, execfd;
Expand Down Expand Up @@ -435,8 +462,12 @@ static int clone_binary(void)

while (sent < statbuf.st_size) {
int n = sendfile(execfd, binfd, NULL, statbuf.st_size - sent);
if (n < 0)
goto error_binfd;
if (n < 0) {
/* sendfile can fail so we fallback to a dumb user-space copy. */
n = fd_to_fd(execfd, binfd);
if (n < 0)
goto error_binfd;
}
sent += n;
}
close(binfd);
Expand Down

0 comments on commit 2d4a37b

Please sign in to comment.