[CRIU] [PATCH v2 08/57] zdtm: Add pidns00 test
Kirill Tkhai
ktkhai at virtuozzo.com
Fri Apr 7 01:58:24 PDT 2017
On 06.04.2017 20:23, Andrei Vagin wrote:
> On Thu, Apr 06, 2017 at 01:01:56PM +0300, Kirill Tkhai wrote:
>> On 06.04.2017 01:16, Andrei Vagin wrote:
>>> diff --git a/test/zdtm/static/pidns00.c b/test/zdtm/static/pidns00.c
>>> index cdfdbd3..72e9019 100644
>>> --- a/test/zdtm/static/pidns00.c
>>> +++ b/test/zdtm/static/pidns00.c
>>> @@ -127,6 +127,22 @@ int main(int argc, char **argv)
>>> } else if (pid[1] == 0)
>>> exit(child());
>>> nr++;
>>> + /* Restore pid namespace for children */
>>> + if (setns(fd, CLONE_NEWPID) < 0) {
>>> + pr_perror("Can't setns");
>>> + goto err;
>>> + }
>>> + if (unshare(CLONE_NEWPID) < 0) {
>>> + pr_perror("Can't unshare");
>>> + goto err;
>>> + }
>>> +
>>> + pid[1] = fork();
>>> + if (pid[1] == -1) {
>>> + fail("fork");
>>> + return 1;
>>> + } else if (pid[1] == 0)
>>> + exit(child());
>>>
>>> /* Restore pid namespace for children */
>>> if (setns(fd, CLONE_NEWPID) < 0) {
>>>
>>>
>>> ======================== Run zdtm/static/pidns00 in ns =========================
>>> Start test
>>> Test is SUID
>>> ./pidns00 --pidfile=pidns00.pid --outfile=pidns00.out
>>> Run criu dump
>>> Run criu restore
>>> =[log]=> dump/zdtm/static/pidns00/38/1/restore.log
>>> ------------------------ grep Error ------------------------
>>> (00.371112) Error (criu/namespaces.c:1547): 83 exited normally
>>> (00.372426) Error (criu/namespaces.c:2749): Error during waiting pid_ns helper: No child processes
>>> ------------------------ ERROR OVER ------------------------
>>> Send the 15 signal to 68
>>> Wait for zdtm/static/pidns00(68) to die for 0.100000
>>> Removing dump/zdtm/static/pidns00/38
>>> ======================== Test zdtm/static/pidns00 PASS =========================
>>>
>>> This error is probably because we don't block sigchld.
>>
>> Yeah, I think the same.
>>
>>> [root at fc24 criu]# python test/zdtm.py run -t zdtm/static/pidns00 -f ns --iter 2
>>> === Run 1/1 ================ zdtm/static/pidns00
>>>
>>> ======================== Run zdtm/static/pidns00 in ns =========================
>>> Start test
>>> Test is SUID
>>> ./pidns00 --pidfile=pidns00.pid --outfile=pidns00.out
>>> Run criu dump
>>> Run criu restore
>>> Run criu dump
>>> =[log]=> dump/zdtm/static/pidns00/38/2/dump.log
>>> ------------------------ grep Error ------------------------
>>> (00.028723) Error (criu/cr-dump.c:1388): A session leader of 68(1) is outside of its pid namespace
>>> (00.030975) Error (criu/cr-dump.c:1764): Dumping FAILED.
>>> ------------------------ ERROR OVER ------------------------
>>> ################## Test zdtm/static/pidns00 FAIL at CRIU dump ##################
>>> Send the 9 signal to 68
>>> Wait for zdtm/static/pidns00(68) to die for 0.100000
>>> ##################################### FAIL #####################################
>>>
>>> This error we have to fix before committing into the upstream repo,
>>> because these changes will break CRIU-iter in Jenkins.
>>
>> It's because of sid and pgid are not restored in any way if there is nested pid_ns.
>> To fix that means to fully support them.
>
> We have to do a minimal support, otherwise it can't be commited.
What is minimal support?
>
>>
>>> On Tue, Mar 28, 2017 at 06:35:24PM +0300, Kirill Tkhai wrote:
>>>> Create parent (P) and its three children (C1, C2 and C3)
>>>> with different pid namespaces:
>>>>
>>>> P (pid_ns1)
>>>> /|\
>>>> / | \
>>>> / | \
>>>> / | \
>>>> / | \
>>>> (pid_ns1) C1 C2 C3 (pid_ns1)
>>>> (pid_ns2)
>>>>
>>>> where pid_ns1 is a parent of pid_ns2:
>>>>
>>>> pid_ns1
>>>> |
>>>> pid_ns2
>>>>
>>>> Children C1, C2 and C3 created in the written order,
>>>> i.e. C1 has the smallest pid and C2 has the biggest.
>>>>
>>>> After receiving signal check, that pid namespaces
>>>> restored right.
>>>>
>>>> Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
>>>> ---
>>>> test/zdtm/static/Makefile | 1
>>>> test/zdtm/static/pidns00.c | 206 +++++++++++++++++++++++++++++++++++++++++
>>>> test/zdtm/static/pidns00.desc | 1
>>>> 3 files changed, 208 insertions(+)
>>>> create mode 100644 test/zdtm/static/pidns00.c
>>>> create mode 100644 test/zdtm/static/pidns00.desc
>>>>
>>>> diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
>>>> index 8d5641bb..1c921d35 100644
>>>> --- a/test/zdtm/static/Makefile
>>>> +++ b/test/zdtm/static/Makefile
>>>> @@ -182,6 +182,7 @@ TST_NOFILE := \
>>>> userns01 \
>>>> userns02 \
>>>> netns_sub_veth \
>>>> + pidns00 \
>>>> # jobctl00 \
>>>>
>>>> ifneq ($(SRCARCH),arm)
>>>> diff --git a/test/zdtm/static/pidns00.c b/test/zdtm/static/pidns00.c
>>>> new file mode 100644
>>>> index 00000000..cdfdbd3d
>>>> --- /dev/null
>>>> +++ b/test/zdtm/static/pidns00.c
>>>> @@ -0,0 +1,206 @@
>>>> +#define _GNU_SOURCE
>>>> +#include <stdbool.h>
>>>> +#include <string.h>
>>>> +#include <fcntl.h>
>>>> +#include <unistd.h>
>>>> +#include <signal.h>
>>>> +#include <stdio.h>
>>>> +#include <sys/mount.h>
>>>> +#include <sys/stat.h>
>>>> +#include <sys/mman.h>
>>>> +#include <sys/types.h>
>>>> +#include <sched.h>
>>>> +#include <sys/wait.h>
>>>> +#include <stdlib.h>
>>>> +#include <limits.h>
>>>> +#include <dirent.h>
>>>> +
>>>> +#include "zdtmtst.h"
>>>> +#include "lock.h"
>>>> +
>>>> +/*
>>>> + * Create parent (P) and its three children (C1, C2 and C3)
>>>> + * with different pid namespaces:
>>>> + *
>>>> + * P (pid_ns1)
>>>> + * /|\
>>>> + * / | \
>>>> + * / | \
>>>> + * / | \
>>>> + * / | \
>>>> + * (pid_ns1) C1 C2 C3 (pid_ns1)
>>>> + * (pid_ns2)
>>>> + *
>>>> + * where pid_ns1 is a parent of pid_ns2:
>>>> + *
>>>> + * pid_ns1
>>>> + * |
>>>> + * pid_ns2
>>>> + * Children C1, C2 and C3 created in the written order,
>>>> + * i.e. C1 has the smallest pid and C2 has the biggest
>>>> + * (so, current restorer should restore them in the same order).
>>>> + * After receiving signal check, that pid namespaces
>>>> + * restored right.
>>>> + */
>>>> +
>>>> +#ifndef NSIO
>>>> +#define NSIO 0xb7
>>>> +#define NS_GET_PARENT _IO(NSIO, 0x2)
>>>> +#endif
>>>> +
>>>> +const char *test_doc = "Check pid namespace hierarhy restores right";
>>>> +const char *test_author = "Kirill Tkhai <ktkhai at virtuozzo.com>";
>>>> +
>>>> +futex_t *futex;
>>>> +
>>>> +int child(void)
>>>> +{
>>>> + futex_wait_while_lt(futex, 1);
>>>> + return 0;
>>>> +}
>>>> +
>>>> +int __get_ns_id(int fd, unsigned int *id)
>>>> +{
>>>> + struct stat st;
>>>> + if (fstat(fd, &st) < 0) {
>>>> + pr_perror("fstat() kaput");
>>>> + return 1;
>>>> + }
>>>> + *id = st.st_ino;
>>>> + return 0;
>>>> +}
>>>> +
>>>> +int get_ns_id(pid_t pid, unsigned int *id)
>>>> +{
>>>> + char buf[PATH_MAX];
>>>> + int fd, ret;
>>>> + sprintf(buf, "/proc/%d/ns/pid", pid);
>>>> + fd = open(buf, O_RDONLY);
>>>> + if (fd < 0) {
>>>> + pr_perror("Can't open %s", buf);
>>>> + return -1;
>>>> + }
>>>> + ret = __get_ns_id(fd, id);
>>>> + close(fd);
>>>> + return ret;
>>>> +}
>>>> +int main(int argc, char **argv)
>>>> +{
>>>> + int status, fd, p_fd, i, nr = 0;
>>>> + unsigned int id, c_id;
>>>> + char path[PATH_MAX];
>>>> + pid_t pid[3];
>>>> +
>>>> + test_init(argc, argv);
>>>> + futex = mmap(NULL, sizeof(*futex), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
>>>> + if (futex == MAP_FAILED) {
>>>> + fail("mmap futex\n");
>>>> + return 1;
>>>> + }
>>>> + futex_init(futex);
>>>> +
>>>> + /* Child 1 */
>>>> + pid[0] = fork();
>>>> + if (pid[0] == -1) {
>>>> + fail("fork");
>>>> + return 1;
>>>> + } else if (pid[0] == 0)
>>>> + exit(child());
>>>> + nr++;
>>>> +
>>>> + /* Child 2 */
>>>> + fd = open("/proc/self/ns/pid", O_RDONLY);
>>>> + if (fd < 0) {
>>>> + pr_perror("Can't get my own pid ns");
>>>> + goto err;
>>>> + }
>>>> +
>>>> + if (unshare(CLONE_NEWPID) < 0) {
>>>> + pr_perror("Can't unshare");
>>>> + goto err;
>>>> + }
>>>> +
>>>> + pid[1] = fork();
>>>> + if (pid[1] == -1) {
>>>> + fail("fork");
>>>> + return 1;
>>>> + } else if (pid[1] == 0)
>>>> + exit(child());
>>>> + nr++;
>>>> +
>>>> + /* Restore pid namespace for children */
>>>> + if (setns(fd, CLONE_NEWPID) < 0) {
>>>> + pr_perror("Can't setns");
>>>> + goto err;
>>>> + }
>>>> + close(fd);
>>>> +
>>>> + /* Child 3 */
>>>> + pid[2] = fork();
>>>> + if (pid[2] == -1) {
>>>> + fail("fork");
>>>> + goto err;
>>>> + } else if (pid[2] == 0)
>>>> + exit(child());
>>>> + nr++;
>>>> +
>>>> + test_daemon();
>>>> + test_waitsig();
>>>> +
>>>> + if (get_ns_id(getpid(), &id))
>>>> + goto err;
>>>> +
>>>> + for (i = 0; i < nr; i++) {
>>>> + if (get_ns_id(pid[i], &c_id))
>>>> + goto err;
>>>> + if (i % 2 == 0) {
>>>> + if (c_id != id) {
>>>> + pr_err("Child %d has wrong pid ns\n", i);
>>>> + goto err;
>>>> + }
>>>> + continue;
>>>> + }
>>>> +
>>>> + if (id == c_id) {
>>>> + pr_err("Child %d has wrong pid ns\n", i);
>>>> + goto err;
>>>> + }
>>>> + /* This parent namespace of this Child's should be same to ours */
>>>> + sprintf(path, "/proc/%d/ns/pid", pid[i]);
>>>> + fd = open(path, O_RDONLY);
>>>> + if (fd < 0) {
>>>> + pr_perror("Can't open");
>>>> + goto err;
>>>> + }
>>>> + p_fd = ioctl(fd, NS_GET_PARENT);
>>>> + if (p_fd < 0)
>>>> + pr_perror("Can't get parent");
>>>> + close(fd);
>>>> + if (p_fd < 0)
>>>> + goto err;
>>>> + if (__get_ns_id(p_fd, &c_id))
>>>> + goto err;
>>>> + close(p_fd);
>>>> + if (id != c_id) {
>>>> + pr_err("Child %d has wrong pid ns hierarhy\n", i);
>>>> + goto err;
>>>> + }
>>>> + }
>>>> +
>>>> + futex_set_and_wake(futex, 1);
>>>> +
>>>> + while (nr-- > 0) {
>>>> + if (wait(&status) < 0 || WEXITSTATUS(status)) {
>>>> + fail("pid: status=%d\n", WEXITSTATUS(status));
>>>> + goto err;
>>>> + }
>>>> + }
>>>> +
>>>> + pass();
>>>> + return 0;
>>>> +err:
>>>> + futex_set_and_wake(futex, 1);
>>>> + while (nr-- > 0)
>>>> + wait(&status);
>>>> + return 1;
>>>> +}
>>>> diff --git a/test/zdtm/static/pidns00.desc b/test/zdtm/static/pidns00.desc
>>>> new file mode 100644
>>>> index 00000000..41c1adcc
>>>> --- /dev/null
>>>> +++ b/test/zdtm/static/pidns00.desc
>>>> @@ -0,0 +1 @@
>>>> +{'flavor': 'ns uns', 'flags': 'suid noauto'}
>>>>
More information about the CRIU
mailing list