Re: xattr names for unprivileged stacking?

Matthew Wilcox
2020-08-29T20:12:55Z

On Sat, Aug 29, 2020 at 08:40:42PM +0100, Al Viro wrote:
> On Sat, Aug 29, 2020 at 08:17:51PM +0100, Matthew Wilcox wrote:
>
> > I probably have the wrong nomenclature for what I'm proposing.
> >
> > So here's a concrete API. What questions need to be answered?
> >
> > fd = open("real", O_RDWR);
> >
> > // fetch stream names
> > sfd = open_stream(fd, NULL);
> > read(sfd, names, length);
>
> 1) what does fstat() on sfd return?

My strawman answers:

- st_dev, st_ino, st_uid, st_gid, st_rdev, st_blksize are those of the
containing file
- st_mode: S_IFREG | parent & 0777
- st_nlink: 1
- st_size, st_blocks st_atime, st_mtime, st_ctime: as appropriate

> 2) what does keeping it open do to underlying file?

I don't have a solid answer here. Maybe it keeps a reference count on
the underlying inode? Obviously we need to prevent the superblock from
disappearing from under it. Maybe it needs to keep a refcount on the
struct file it was spawned from. I haven't thought this through yet.

> 3) what happens to it if that underlying file is unlinked?

Unlinking a file necessarily unlinks all the streams. So the file
remains in existance until all fds on it are closed, including all
the streams.

> 4) what does it do to underlying filesystem? Can it be unmounted?

I think I covered that in the earlier answers.

> > // create a new anonymous stream
> > sfd = open_stream(fd, "");
> > write(sfd, buffer, buflen);
> > // name it
> > linkat(sfd, NULL, fd, "newstream", AT_EMPTY_PATH);
>
> Oh, lovely - so linkat() *CAN* get that for dirfd and must somehow tell
> it from the normal case. With the semantics entirely unrelated to the normal
> one.

I'm open to just using a different syscall. link_stream(sfd, "newstream");
And, as you point out below, we need unlink_stream(fd, "stream");

> And on top of everything else, we have
> 5) what are the permissions involved? When are they determined, BTW?

If you can open a file, you can open its streams. So an O_PATH file
descriptor can't be used to open streams.

> > close(sfd);
> >
> > - Stream names are NUL terminated and may contain any other character.
> > If you want to put a '/' in a stream name, that's fine, but there's
> > no hierarchy. Ditto "//../././../../..//./." It's just a really
> > oddly named stream.
>
> Er... Whatever for?

Interoperability. If some other system creates a stream with a '/' in
it, I don't want the filesystem to have to convert. Although, at least
Windows doesn't permit '/' in stream names [1] [2]. Of course, individual
filesystems could reject characters in names that they don't like.

[1] https://docs.microsoft.com/en-us/windows/win32/fileio/file-streams
[2] https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file

> > - linkat() will fail if 'fd' does not match where 'sfd' was created.
>
> 6) "match" in the above being what, exactly?

Referring to a different inode than the one it was created in. Although
if we just go with the link_stream() proposal above, then this point is
moot.