Commit c89fecfd authored by Tycho Andersen's avatar Tycho Andersen Committed by Pavel Emelyanov

remap: fix dead pid remap of /proc/<pid>

It turns out we can't just test for /proc/<pid>, because the kernel appends
(deleted), since the directory is actually deleted (vs. something like
/proc/1/mountinfo, where the file still exists in the unlinked directory,
so there is no (deleted)). See comment for details.

v2: s/ret/is_dead in /proc/<pid>/xxx test, split tests to correctly test
    both cases
Signed-off-by: 's avatarTycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent ec8db4cb
......@@ -887,16 +887,32 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms,
return -1;
pid = strtol(start + 1, &end, 10);
/* if we didn't find another /, this path something
* like ./proc/kmsg, which we shouldn't mess with. */
if (*end == '/') {
/* If strtol didn't convert anything, then we are looking at
* something like /proc/kmsg, which we shouldn't mess with.
* Anything under /proc/<pid> (including that directory itself)
* can be c/r'd with a dead pid remap, so let's allow all such
* cases.
*/
if (pid != 0) {
bool is_dead = strip_deleted(link);
/* /proc/<pid> will be "/proc/1 (deleted)" when it is
* dead, but a path like /proc/1/mountinfo won't have
* the suffix, since it isn't actually deleted (still
* exists, but the parent dir is deleted). So, if we
* have a path like /proc/1/mountinfo, test if /proc/1
* exists instead, since this is what CRIU will need to
* open on restore.
*/
if (!is_dead) {
*end = 0;
ret = access(rpath, F_OK);
is_dead = access(rpath, F_OK);
*end = '/';
}
if (ret) {
if (is_dead) {
pr_info("Dumping dead process remap of %d\n", pid);
return dump_dead_process_remap(pid, rpath + 1, plen - 1, ost, lfd, id, nsid);
return dump_dead_process_remap(pid, rpath + 1, link->len - 1, ost, lfd, id, nsid);
}
}
......
......@@ -106,6 +106,7 @@
/live/static/pty03
/live/static/pty04
/live/static/remap_dead_pid
/live/static/remap_dead_pid_root
/live/static/rlimits00
/live/static/rmdir_open
/live/static/rtc
......
......@@ -132,6 +132,7 @@ TST_NOFILE = \
dumpable01 \
dumpable02 \
remap_dead_pid \
remap_dead_pid_root \
aio00 \
fd \
apparmor \
......
......@@ -41,8 +41,11 @@ int main(int argc, char **argv)
pid_t result;
sprintf(path, "/proc/%d/mountinfo", pid);
fd = open(path, O_RDONLY);
if (fd < 0) {
fail("failed to open fd");
return -1;
}
/* no matter what, we should kill the child */
kill(pid, SIGKILL);
......
#define _GNU_SOURCE
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "zdtmtst.h"
#ifndef CLONE_NEWNS
#define CLONE_NEWNS 0x00020000
#endif
const char *test_doc = "Check that dead pid's /proc entries are remapped correctly";
const char *test_author = "Tycho Andersen <tycho.andersen@canonical.com>";
int main(int argc, char **argv)
{
pid_t pid;
test_init(argc, argv);
pid = fork();
if (pid < 0) {
fail("fork() failed");
return -1;
}
if (pid == 0) {
test_msg("child is %d\n", pid);
/* Child process just sleeps until it is killed. All we need
* here is a process to open the mountinfo of. */
while(1)
sleep(10);
} else {
int fd, ret;
char path[PATH_MAX];
pid_t result;
sprintf(path, "/proc/%d", pid);
fd = open(path, O_RDONLY);
if (fd < 0) {
fail("failed to open fd");
return -1;
}
/* no matter what, we should kill the child */
kill(pid, SIGKILL);
result = waitpid(pid, NULL, 0);
if (result < 0) {
fail("failed waitpid()");
return -1;
}
test_daemon();
test_waitsig();
ret = fcntl(fd, F_GETFD);
close(fd);
if (ret) {
fail("bad fd after restore");
return -1;
}
}
pass();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment