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

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

Open
ryao opened this issue Oct 18, 2022 · 1 comment
Open

Comments

@ryao
Copy link

ryao commented Oct 18, 2022

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'
@ryao
Copy link
Author

ryao commented Oct 18, 2022

I found a workaround. This works:

find_task 1 | member nsproxy | cast struct nsproxy * | member 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

This does not:

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

I am not sure why. The two seem to be the same:

sdb> find_task 1 | member nsproxy
(struct nsproxy *)init_nsproxy+0x0 = 0xffffffff9f65db00
sdb> find_task 1 | member nsproxy | cast struct nsproxy *
(struct nsproxy *)init_nsproxy+0x0 = 0xffffffff9f65db00

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

No branches or pull requests

1 participant