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

cockpit: support access attributes in fsinfo #21603

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

jelly
Copy link
Member

@jelly jelly commented Feb 10, 2025

For cockpit-files it is useful to know if the current watched directory or for example a text file is editable for the current user. Doing this based on the existing file permissions doesn't take ACL's into account.

The access syscall only handles one access check (read/write/execute) per call making it rather inefficient to check for multiple scenario's, so that's why there are separate attrs depending on what the user want so in worst case we only add 1 extra syscall.

As Python does not support AT_EMPTY_PATH there is a workaround to read the file from /proc/self this is only required for reading the access bits of the current watched directory.

Closes: #21596

@jelly jelly added the no-test For doc/workflow changes, or experiments which don't need a full CI run, label Feb 10, 2025
For cockpit-files it is useful to know if the current watched directory
or for example a text file is editable for the current user. Doing this
based on the existing file permissions doesn't take ACL's into account.

The `access` syscall only handles one access check (read/write/execute)
per call making it rather inefficient to check for multiple scenario's,
so that's why there are separate attrs depending on what the user want
so in worst case we only add 1 extra syscall.

As Python does not support AT_EMPTY_PATH there is a workaround to read
the file from /proc/self this is only required for reading the access
bits of the current watched directory.

Closes: cockpit-project#21596
Verify we only send what is specified, this uncovered interesting fsinfo
behaviour depending if you send `fnmatch='*.txt'` or `fnmatch=''` the
latter does not set `entries` while `*.txt` does likely as `''` does not
match anything and thus no `entries` are set.
@jelly jelly force-pushed the fsinfo-read-write-permissions branch from ca10789 to 4ad7e12 Compare February 13, 2025 10:42
@jelly jelly marked this pull request as ready for review February 13, 2025 10:44
# HACK: Python's os.access() does not support passing "AT_EMPTY_PATH"
# so we need to resolve the name of the watched directory.
try:
name = os.readlink(f'/proc/self/fd/{fd}')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you can't just os.access() directly on the /proc/self/fd link with follow_symlinks=True? That underlying file descriptor is exactly what you want to query. Trying to do it via filename is possibly racy and I imagine it could run into corner cases...

@@ -393,6 +407,11 @@ def get_group(gid: int) -> 'str | int':
}
stat_getters = tuple((key, available_stat_getters.get(key, lambda _: None)) for key in attrs)

available_access_getters = {
'r-ok': lambda name, fd, follow: get_access(name, fd, os.R_OK, follow_symlinks=follow),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about having a map from r-ok to os.R_OK (and so on) instead, and removing one layer of indirection?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also: x-ok?

@@ -1298,14 +1298,16 @@ async def test_fsinfo_watch_identity_changes(

@pytest.mark.asyncio
async def test_fsinfo_self_owner(transport: MockTransport, tmp_path: Path) -> None:
client = await FsInfoClient.open(transport, tmp_path, ['user', 'uid', 'group', 'gid'])
client = await FsInfoClient.open(transport, tmp_path, ['user', 'uid', 'group', 'gid'], fnmatch='')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this change. '' should already be the default value if the attrs array doesn't contain entries.

        attrs = set(get_strv(options, 'attrs'))
        self.getattrs = self.make_getattrs(attrs - {'targets', 'entries'})
        self.fnmatch = get_str(options, 'fnmatch', '*' if 'entries' in attrs else '')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no-test For doc/workflow changes, or experiments which don't need a full CI run,
Projects
None yet
Development

Successfully merging this pull request may close these issues.

fsinfo: include access bits for cockpit-files
2 participants