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

Handle symlinks in path_lookup() #216

Open
brenns10 opened this issue Oct 25, 2022 · 1 comment · May be fixed by #218
Open

Handle symlinks in path_lookup() #216

brenns10 opened this issue Oct 25, 2022 · 1 comment · May be fixed by #218
Labels
enhancement New feature or request

Comments

@brenns10
Copy link
Contributor

Suppose that we're looking up /foo/bar/baz, and bar is a symlink to a different directory. Currently, path_lookup() fails because it does not have any logic to follow symlinks. Let's add a follow_symlinks=False kwarg and add that logic in without breaking backward compatibility.

(this is just a reminder to myself to do this, I hope to send a pull request shortly)

@osandov osandov linked a pull request Dec 3, 2022 that will close this issue
@osandov osandov added the enhancement New feature or request label Jul 5, 2023
@osandov
Copy link
Owner

osandov commented Oct 1, 2024

@ryantimwilson is interested in reviving this, so I'm going to summarize and expand on my comments on the last attempt:

Before we modify path_lookup() itself, we're going to need a new helper in drgn/helpers/linux/fs.py along these lines:

class SymlinkNotCachedError(Exception):
    """Error raised when attempting to read an uncached symbolic link."""


def inode_readlink(inode: Object) -> bytes:
    """
    Return the target of a symbolic link.

    >>> inode = path_lookup("/bin").dentry.d_inode
    >>> inode_readlink(inode)
    b'usr/bin'

    :param inode: ``struct inode *``
    :return: Link target
    :raises ValueError: if *inode* is not a symbolic link
    :raises SymlinkNotCachedError: if the link target is not cached
    :raises NotImplementedError: if reading symbolic links is not yet
        implemented for the filesystem containing *inode*
    """
    ...

Basically, when the target of a symlink inode is requested in the kernel, the filesystem reads it from the disk/network/etc. and usually caches it somewhere. drgn can obviously only read it if it is cached. The tricky thing is that filesystems cache it differently. See vfs_readlink() in the kernel, which calls the filesystem's ->get_link() callback.

So, we're going to need to pick an initial set of filesystems to implement this for. inode_readlink() can check the ->get_link() callback to figure out how to proceed . E.g., if inode.i_op.get_link == prog["page_get_link"]: ... emulate page_get_link .... For the initial PR, I'd suggest starting with one or both of these:

Then, we could add these in followup PRs:

  • ext4: three possibilities depending on the filesystem configuration. I'd pretend that the encrypted option doesn't exist for now and only handle the other two.
  • XFS: uses xfs_vn_get_link(). It looks complicated.

Once inode_readlink() is implemented for a couple of filesystems, the next step is to use it in path_lookup(). My comment on the previous attempt has some thoughts on how to go about that.

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

Successfully merging a pull request may close this issue.

2 participants