I am attempting to checkpoint a program that uses unix pipes for communication within its own process. In particular, it attempts to open /proc/%d/fd/%d. CRIU's restore completes successfully but during restored program execution, the open() call on /proc/%d/fd/%d fails with invalid permission.
I believe criu launched as root creates the pipe with rw------- mode, then attaches the file descriptors. Later when application is restored it is no longer running as root, and the open fails.
Here is ls -l and stat -L on the fd when criu is run as root:
lr-x------ 1 lrobison lrobison 64 Mar 23 19:11 /proc/432216/fd/3 -> 'pipe:[20980593]'
File: /proc/432216/fd/3
Size: 0 Blocks: 0 IO Block: 4096 fifo
Device: 0,14 Inode: 20980593 Links: 1
Access: (0600/prw-------) Uid: ( 0/ root) Gid: ( 0/ root)
Here is the same if restoring with --unprivileged and running criu as my user:
lr-x------ 1 lrobison lrobison 64 Mar 23 19:18 /proc/432612/fd/3 -> 'pipe:[21002808]'
File: /proc/432612/fd/3
Size: 0 Blocks: 0 IO Block: 4096 fifo
Device: 0,14 Inode: 21002808 Links: 1
Access: (0600/prw-------) Uid: ( 1050/lrobison) Gid: ( 1051/lrobison)
And in this case the application can continue as expected.
However, for other reasons I need restore to run as root. Given that CRIU should know it will hand off the pipe to the unprivileged user, can CRIU change the pipe's ownership to that user?
Small reproducer
/*
* pipetest.c - Minimal CRIU reproducer: open a pipe, checkpoint, then
* re-open the read end via /proc/self/fd/<n> after restore.
*
* Steps to reproduce:
* 1. Build: gcc -o pipetest pipetest.c
* 2. Run: ./pipetest &
* 3. In another terminal, checkpoint:
* criu dump -t $(pgrep pipetest) -D /tmp/pipetest-img --shell-job
* 4. Restore:
* criu restore -D /tmp/pipetest-img --shell-job
*
* Expected: open(/proc/self/fd/<read_end>) succeeds after restore.
* Observed: open() fails with Permission denied.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
int fds[2];
if (pipe(fds) < 0) {
perror("pipe");
return 1;
}
printf("pipe read_fd=%d write_fd=%d\n", fds[0], fds[1]);
printf("sleeping 20s — checkpoint pid %d now\n", getpid());
fflush(stdout);
sleep(20);
printf("Continuing. 5 seconds of sleep for debug.\n");
sleep(5);
/* After restore, attempt to open the read end via /proc/self/fd */
char path[64];
snprintf(path, sizeof(path), "/proc/%d/fd/%d", getpid(), fds[0]);
printf("re-opening pipe read end via %s\n", path);
fflush(stdout);
int reopen_fd = open(path, O_RDONLY);
if (reopen_fd < 0) {
fprintf(stderr, "open(%s) failed: %s\n", path, strerror(errno));
return 1;
}
printf("open succeeded: new_fd=%d\n", reopen_fd);
/* Quick sanity check: write to write end, read from re-opened fd */
const char msg[] = "hello through pipe\n";
if (write(fds[1], msg, sizeof(msg) - 1) < 0) {
perror("write");
return 1;
}
char buf[64] = {0};
ssize_t n = read(reopen_fd, buf, sizeof(buf) - 1);
if (n < 0) {
perror("read");
return 1;
}
printf("read %zd bytes: %s", n, buf);
close(reopen_fd);
close(fds[0]);
close(fds[1]);
return 0;
}
I am attempting to checkpoint a program that uses unix pipes for communication within its own process. In particular, it attempts to open
/proc/%d/fd/%d. CRIU's restore completes successfully but during restored program execution, the open() call on/proc/%d/fd/%dfails with invalid permission.I believe criu launched as root creates the pipe with
rw-------mode, then attaches the file descriptors. Later when application is restored it is no longer running as root, and the open fails.Here is
ls -landstat -Lon the fd when criu is run as root:Here is the same if restoring with --unprivileged and running criu as my user:
And in this case the application can continue as expected.
However, for other reasons I need restore to run as root. Given that CRIU should know it will hand off the pipe to the unprivileged user, can CRIU change the pipe's ownership to that user?
Small reproducer