[RFC PATCH 2/3] add statmnt(2) syscall

Miklos Szeredi miklos at szeredi.hu
Tue Sep 19 08:02:17 UTC 2023


On Tue, 19 Sept 2023 at 02:38, Matthew House <mattlloydhouse at gmail.com> wrote:

> One natural solution is to set either of the two lengths to the expected
> size if the provided buffer are too small. That way, the caller learns both
> which of the buffers is too small, and how large they need to be. Replacing
> a provided size with an expected size in this way already has precedent in
> existing syscalls:

This is where the thread started.  Knowing the size of the buffer is
no good, since the needed buffer could change between calls.

We are trying to create a simple interface, no?  My proposal would
need a helper like this:

struct statmnt *statmount(uint64_t mnt_id, uint64_t mask, unsigned int flags)
{
        size_t bufsize = 1 << 15;
        void *buf;
        int ret;

        for (;;) {
                buf = malloc(bufsize <<= 1);
                if (!buf)
                        return NULL;
                ret = syscall(__NR_statmnt, mnt_id, mask, buf, bufsize, flags);
                if (!ret)
                        return buf;
                free(buf);
                if (errno != EOVERFLOW)
                        return NULL;
        }
}

Christian's would be (ignoring .fs_type for now):

int statmount(uint64_t mnt_id, uint64_t mask, struct statmnt *st,
unsigned int flags)
{
        int ret;

        st->mnt_root_size = 1 << 15;
        st->mountpoint_size = 1 << 15;
        for (;;) {
                st->mnt_root = malloc(st->mnt_root_size <<= 1);
                st->mountpoint = malloc(st->mountpoint <<= 1);
                if (!st->mnt_root || !st->mountpoint) {
                        free(st->mnt_root);
                        free(st->mountpoint);
                        return -1;
                }
                ret = syscall(__NR_statmnt, mnt_id, mask, st,
sizeof(*st), flags);
                if (!ret || errno != EOVERFLOW)
                        return ret;
                free(st->mnt_root);
                free(st->mountpoint);
        }
}

It's not hugely more complex, but more complex nonetheless.

Also having the helper allocate buffers inside the struct could easily
result in leaks since it's not obvious what the caller needs to free,
while in the first example it is.

Note that I'm not against having the prototype on the kernel interface
take a typed pointer.  If strings are not needed, both interfaces
would work in exactly the same way.

Thanks,
Miklos



More information about the Linux-security-module-archive mailing list