Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

executor/linux: unshare mount namespace #2047

Closed
wants to merge 2 commits into from

Conversation

KumanekoSakura
Copy link

With commit 598f493 ("executor/linux: dump more information when failed to open kcov file"), we got an unexpected result.

(1) sysfs was already detached from /sys/ .
(2) procfs was still mounted on /proc/ even when /proc/mounts could not be opened.
(3) Mounting another procfs on /proc/ failed on some reports and did not fail on other reports.
(4) Only / and several /proc/ are shown by /proc/mounts .

Since "umount -l /" cannot explain (2) and (3), I don't know what is happening.
But we might be able to mitigate this problem by always unsharing mount namespace and changing mount propagation type to 'private'.

Tetsuo Handa added 2 commits August 14, 2020 10:18
With commit 598f493 ("executor/linux: dump more information when
failed to open kcov file"), we got an unexpected result.

  (1) sysfs was already detached from /sys/ .
  (2) procfs was still mounted on /proc/ even when /proc/mounts could not
      be opened.
  (3) Mounting another procfs on /proc/ failed on some reports and did not
      fail on other reports.
  (4) Only / and several /proc/ are shown by /proc/mounts .

Since "umount -l /" cannot explain (2) and (3), I don't know what is happening.
But we might be able to mitigate this problem by always unsharing mount namespace
and changing mount propagation type to 'private'.
It seems that unshare() fails with EPERM in some callers.
@codecov
Copy link

codecov bot commented Aug 14, 2020

Codecov Report

Merging #2047 into master will not change coverage.
The diff coverage is n/a.

@dvyukov
Copy link
Collaborator

dvyukov commented Aug 14, 2020

We already do unshare(CLONE_NEWNS) in sandbox_common() so all test processes are in separate mount namespace.

I am also nervous merging this. I am not sure it will work on e.g. Android, I am not sure we mount back all filesystems we possibly need for fuzzing, e.g. #2017 uses files from /. This may also lead to difference with C reproduces as C reproducers don't include os_init logic.

And we already do this during sandboxing, if anything the sandboxing code need to be changed. Sandboxing code is also part of C reproducers.

@KumanekoSakura
Copy link
Author

We already do unshare(CLONE_NEWNS) in sandbox_common() so all test processes are in separate mount namespace.

Well, unshare(CLONE_NEWNS) might not be sufficient. If a system is controlled by systemd, systemd issues "mount --make-rshared /" request.
Please run the following example (on a system which is controlled by systemd) with/without an argument.
You will see that number of tmpfs entry increases unless argument is given.

#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sched.h>

int main(int argc, char *argv[])
{
        char c;
        const int fd = open("/proc/mounts", O_RDONLY);
        if (fd < 0)
                return 1;
        if (unshare(CLONE_NEWNS))
                return 1;
        if (argc > 1)
                if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL))
                        return 1;
        if (mount("/mnt", "/mnt", "tmpfs", 0, NULL))
                return 1;
        while (read(fd, &c, 1) == 1 && write(1, &c, 1) == 1);
        return 0;
}

And we can find reports like https://syzkaller.appspot.com/text?tag=CrashLog&x=172b47be900000 that contains
such entries.

Content of /proc/mounts
/dev/root / ext4 rw,seclabel,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
/proc/ /proc proc rw,relatime 0 0
open of /sys/kernel/debug/kcov failed (errno 2)

@KumanekoSakura
Copy link
Author

I am also nervous merging this.

Then, can we try "retry open("/sys/kernel/debug/kcov") after mounting /sys/ and /sys/kernel/debug/ when open("/sys/kernel/debug/kcov") failed" (though there is no guarantee that mounting only these is sufficient) ?

An alternative approach (though Linux 5.2+ kernels only) might be to use fsopen()/fsconfig()/fsmount()/openat() instead of relying on readiness of mount point. Below example reads /sys/kernel/debug/memcg_slabinfo without accessing mount point.

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/mount.h>
#include <sys/syscall.h>

static inline int fsopen(const char *fsname, unsigned int flags)
{
        return syscall(__NR_fsopen, fsname, flags);
}

static inline int fsconfig(int fs_fd, enum fsconfig_command cmd, const char *key,
                           const void *value, int aux)
{
        return syscall(__NR_fsconfig, fs_fd, cmd, key, value, aux);
}

static inline int fsmount(int fd, unsigned int flags, unsigned int mount_attrs)
{
        return syscall(__NR_fsmount, fd, flags, mount_attrs);
}

int main(int argc, char *argv[])
{
        int sfd = fsopen("debugfs", FSOPEN_CLOEXEC);
        int mfd;
        int fd;
        char c;
        if (fsconfig(sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0))
                return 1;
        mfd = fsmount(sfd, FSMOUNT_CLOEXEC, MOUNT_ATTR_NODEV);
        close(sfd);
        fd = openat(mfd, "memcg_slabinfo", O_RDONLY);
        close(mfd);
        while (read(fd, &c, 1) == 1 && write(1, &c, 1) == 1);
        close(fd);
        return 0;
}

@KumanekoSakura
Copy link
Author

Superseded by #2051.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants