nsenter: cloned_binary: userspace copy fallback if sendfile fails

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>
This commit is contained in:
Aleksa Sarai 2019-03-01 18:23:54 +11:00
parent 16612d74de
commit 2d4a37b427
No known key found for this signature in database
GPG Key ID: 9E18AA267DDB8DB4
1 changed files with 34 additions and 3 deletions

View File

@ -160,7 +160,7 @@ static char *read_file(char *path, size_t *length)
*length = 0; *length = 0;
for (;;) { for (;;) {
int n; ssize_t n;
n = read(fd, buf, sizeof(buf)); n = read(fd, buf, sizeof(buf));
if (n < 0) if (n < 0)
@ -403,6 +403,33 @@ out:
return ret; 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) static int clone_binary(void)
{ {
int binfd, execfd; int binfd, execfd;
@ -435,8 +462,12 @@ static int clone_binary(void)
while (sent < statbuf.st_size) { while (sent < statbuf.st_size) {
int n = sendfile(execfd, binfd, NULL, statbuf.st_size - sent); int n = sendfile(execfd, binfd, NULL, statbuf.st_size - sent);
if (n < 0) {
/* sendfile can fail so we fallback to a dumb user-space copy. */
n = fd_to_fd(execfd, binfd);
if (n < 0) if (n < 0)
goto error_binfd; goto error_binfd;
}
sent += n; sent += n;
} }
close(binfd); close(binfd);