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:
parent
16612d74de
commit
2d4a37b427
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue