open_by_handle_at: mount_fd opened with O_PATH

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

I recently noticed that the syscall open_by_handle_at() automatically fails if its first argument is a file descriptor opened with O_PATH. I looked at the code
and saw no reason this could not be allowed. Attached to this mail are a
a reproducer and the patch I came up with.

I am not quite familiar with the kernel's way of processing patches. Any pointer
or advice on this matter is very welcome.

Cheers,
Quentin Bouget

#define _GNU_SOURCE
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

int
main()
{
    struct file_handle *fhandle;
    const char *pathname = "/";
    int mount_fd;
    int mountid;
    int fd;

    fhandle = malloc(sizeof(*fhandle) + 128);
    if (fhandle == NULL)
        error(EXIT_FAILURE, errno, "malloc");
    fhandle->handle_bytes = 128;

    fd = open(pathname, O_RDONLY | O_PATH | O_NOFOLLOW);
    if (fd < 0)
        error(EXIT_FAILURE, errno, "open");

    if (name_to_handle_at(fd, "", fhandle, &mountid, AT_EMPTY_PATH))
        error(EXIT_FAILURE, errno, "name_to_handle_at");

    mount_fd = fd;
    fd = open_by_handle_at(mount_fd, fhandle, O_RDONLY | O_PATH | O_NOFOLLOW);
    if (fd < 0)
        error(EXIT_FAILURE, errno, "open_by_handle_at");

    if (close(fd))
        error(EXIT_FAILURE, errno, "close");

    if (close(mount_fd))
        error(EXIT_FAILURE, errno, "close");

    free(fhandle);

    return EXIT_SUCCESS;
}
>From e3717e276444c5711335d398c29beedaf61bac82 Mon Sep 17 00:00:00 2001
From: Quentin Bouget <quentin.bouget@xxxxxx>
Date: Thu, 24 Oct 2019 16:54:54 +0200
Subject: [PATCH] vfs: let open_by_handle_at() use mount_fd opened with O_PATH

The first argument of open_by_handle_at() is `mount_fd':

> a file descriptor for any object (file, directory, etc.) in the
> mounted filesystem with respect to which `handle' should be
> interpreted.

This patch allows for this file descriptor to be opened with O_PATH.

Signed-off-by: Quentin Bouget <quentin.bouget@xxxxxx>
---
 fs/fhandle.c | 35 +++++++++++++++++++++++------------
 1 file changed, 23 insertions(+), 12 deletions(-)

diff --git a/fs/fhandle.c b/fs/fhandle.c
index 01263ffbc..8b67f1b9e 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -112,22 +112,33 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
 	return err;
 }
 
+static struct vfsmount *get_vfsmount_from_cwd(void)
+{
+	struct fs_struct *fs = current->fs;
+	struct vfsmount *mnt;
+
+	spin_lock(&fs->lock);
+	mnt = mntget(fs->pwd.mnt);
+	spin_unlock(&fs->lock);
+
+	return mnt;
+}
+
 static struct vfsmount *get_vfsmount_from_fd(int fd)
 {
 	struct vfsmount *mnt;
+	struct path path;
+	int err;
 
-	if (fd == AT_FDCWD) {
-		struct fs_struct *fs = current->fs;
-		spin_lock(&fs->lock);
-		mnt = mntget(fs->pwd.mnt);
-		spin_unlock(&fs->lock);
-	} else {
-		struct fd f = fdget(fd);
-		if (!f.file)
-			return ERR_PTR(-EBADF);
-		mnt = mntget(f.file->f_path.mnt);
-		fdput(f);
-	}
+	if (fd == AT_FDCWD)
+		return get_vfsmount_from_cwd();
+
+	err = filename_lookup(fd, getname_kernel(""), LOOKUP_EMPTY, &path, NULL);
+	if (err)
+		return ERR_PTR(err);
+
+	mnt = mntget(path.mnt);
+	path_put(&path);
 	return mnt;
 }
 
-- 
2.18.1


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux