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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions