Skip to content

Trying to view mount namespace results in incomplete structure type error #294

@ryao

Description

@ryao

This is on Ubuntu 18.04 with the HWE stack installed to get kernel 5.3.0-26-generic, and the dbgym package installed:

https://launchpad.net/ubuntu/bionic/amd64/linux-image-unsigned-5.3.0-26-generic-dbgsym/5.3.0-26.28~18.04.1

I am trying to view the mounts for the system, so I do find_task 1 | member nsproxy | deref and boom:

sdb encountered an internal error due to a bug. Here's the
information you need to file the bug:
----------------------------------------------------------
Target Info:
        ProgramFlags.IS_LIVE|IS_LINUX_KERNEL
        Platform(<Architecture.X86_64: 1>, <PlatformFlags.IS_LITTLE_ENDIAN|IS_64_BIT: 3>)

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/sdb-0.1.0-py3.6.egg/sdb/internal/repl.py", line 107, in eval_cmd
    for obj in invoke(self.target, [], input_):
  File "/usr/local/lib/python3.6/dist-packages/sdb-0.1.0-py3.6.egg/sdb/pipeline.py", line 153, in invoke
    yield from execute_pipeline(first_input, pipeline)
  File "/usr/local/lib/python3.6/dist-packages/sdb-0.1.0-py3.6.egg/sdb/pipeline.py", line 84, in execute_pipeline
    yield from massage_input_and_call(pipeline[-1], this_input)
  File "/usr/local/lib/python3.6/dist-packages/sdb-0.1.0-py3.6.egg/sdb/pipeline.py", line 43, in massage_input_and_call
    yield from cmd.call(objs)
  File "/usr/local/lib/python3.6/dist-packages/sdb-0.1.0-py3.6.egg/sdb/command.py", line 326, in call
    result, not issubclass(self.__class__, SingleInputCommand))
  File "/usr/local/lib/python3.6/dist-packages/sdb-0.1.0-py3.6.egg/sdb/command.py", line 289, in __invalid_memory_objects_check
    obj.read_()
TypeError: cannot read object with incomplete structure type
----------------------------------------------------------
Link: https://github.com/delphix/sdb/issues/new

Instead, I do:

sdb> find_task 1 
(struct task_struct *)0xffff8d35592f1e00

Then I open gdb with sudo gdb -c /proc/kcore /usr/lib/debug/boot/vmlinux-5.3.0-26-generic and do:

(gdb) print ((struct task_struct *)0xffff8d35592f1e00)->nsproxy->mnt_ns
$3 = (struct mnt_namespace *) 0xffff8d355f407300

Now I can go back and run:

sdb> echo 0xffff8d355f407300 | cast struct mnt_namespace * | member root.mnt_list |addr | lxlist mount mnt_list | member mnt_devname
(const char *)0xffff8d1d57038068 = "sysfs"
(const char *)0xffff8d35581d7db0 = "proc"
(const char *)0xffff8d1d58ba5958 = "udev"
(const char *)0xffff8d1d58ba5b88 = "devpts"
(const char *)0xffff8d1d58ba5b10 = "tmpfs"
(const char *)0xffff8d1d58f633f0 = "/dev/sda4"
(const char *)0xffff8d1d44950400 = "securityfs"
(const char *)0xffff8d1d467cfe78 = "tmpfs"
(const char *)0xffff8d1d467cf638 = "tmpfs"
(const char *)0xffff8d1d467cf510 = "tmpfs"
(const char *)0xffff8d1d467cf568 = "cgroup"
(const char *)0xffff8d1d467cf2e8 = "cgroup"
(const char *)0xffff8d1d467cf090 = "pstore"
(const char *)0xffff8d1d467cfcf8 = "cgroup"
(const char *)0xffff8d1d467cf758 = "cgroup"
(const char *)0xffff8d1d467cf060 = "cgroup"
(const char *)0xffff8d1d467cfde8 = "cgroup"
(const char *)0xffff8d1d467cfdb8 = "cgroup"
(const char *)0xffff8d1d467cf050 = "cgroup"
(const char *)0xffff8d1d467cf108 = "cgroup"
(const char *)0xffff8d1d467cfea0 = "cgroup"
(const char *)0xffff8d1d467cff40 = "cgroup"
(const char *)0xffff8d1d467cf928 = "cgroup"
(const char *)0xffff8d1d467cf920 = "cgroup"
(const char *)0xffff8d1d51dd5ea0 = "systemd-1"
(const char *)0xffff8d1d588aeab0 = "hugetlbfs"
(const char *)0xffff8d35581d7260 = "debugfs"
(const char *)0xffff8d1d58f5cc30 = "mqueue"
(const char *)0xffff8d1d58feb010 = "sunrpc"
(const char *)0xffff8d1d589149f8 = "nfsd"
(const char *)0xffff8d35470c9070 = "fusectl"
(const char *)0xffff8d355849de20 = "/dev/sda3"
(const char *)0xffff8d35585d8ea0 = "configfs"
(const char *)0xffff8d1d57ec0760 = "/dev/sda2"
(const char *)0xffff8d1d588d5c00 = "tmpfs"
(const char *)0xffff8d353c059178 = "tracefs"
(const char *)0xffff8d353c98a9a0 = "/dev/sda4"
(const char *)0xffff8d1d5465c5d0 = "nsfs"
(const char *)0xffff8d1d589140a0 = "nsfs"
(const char *)0xffff8d1d23d9cce0 = "tmpfs"
(const char *)0xffff8d1c98d84320 = "pool"
(const char *)0xffff8d1d356529c0 = "pool/dataset"
(const char *)0xffff8d35592d8dc0 = ""

I can also do echo 0xffff8d355f407300 | cast struct mnt_namespace * | member root.mnt_list |addr | lxlist mount mnt_list | filter 'obj.mnt_devname == "pool"' | member mnt.mnt_sb.s_fs_info| cast struct zfsvfs * | deref to see the zfsvfs struct for the dataset and keep following pointers to find what I want.

It would be really nice if I did not need to fall back to gdb to get the mnt_ns pointer. I assume this is a bug since gdb had no problem finding it. It is rather strange that sdb has a problem doing this given that it is able to see the type information for nsproxy:

sdb> ptype nsproxy
struct nsproxy {
        atomic_t count;
        struct uts_namespace *uts_ns;
        struct ipc_namespace *ipc_ns;
        struct mnt_namespace *mnt_ns;
        struct pid_namespace *pid_ns_for_children;
        struct net *net_ns;
        struct cgroup_namespace *cgroup_ns;
}

Basically, I want to be able to find_task 1 | member nsproxy.mnt_ns | cast struct mnt_namespace * | member root.mnt_list |addr | lxlist mount mnt_list | filter 'obj.mnt_devname == "pool"' | member mnt.mnt_sb.s_fs_info| cast struct zfsvfs * | deref. Unfortunately, this gives me:

sdb> find_task 1 | member nsproxy.mnt_ns.root.mnt_list |addr | lxlist mount mnt_list | filter 'obj.mnt_devname == "pool"' | member mnt.mnt_sb.s_fs_info| cast struct zfsvfs * | deref
sdb: member: 'struct nsproxy' has no member 'mnt_ns'

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions