Commit 40091325 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'work.mount-syscalls' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull mount ABI updates from Al Viro:
 "The syscalls themselves, finally.

  That's not all there is to that stuff, but switching individual
  filesystems to new methods is fortunately independent from everything
  else, so e.g. NFS series can go through NFS tree, etc.

  As those conversions get done, we'll be finally able to get rid of a
  bunch of duplication in fs/super.c introduced in the beginning of the
  entire thing. I expect that to be finished in the next window..."

* 'work.mount-syscalls' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  vfs: Add a sample program for the new mount API
  vfs: syscall: Add fspick() to select a superblock for reconfiguration
  vfs: syscall: Add fsmount() to create a mount for a superblock
  vfs: syscall: Add fsconfig() for configuring and managing a context
  vfs: Implement logging through fs_context
  vfs: syscall: Add fsopen() to prepare for superblock creation
  Make anon_inodes unconditional
  teach move_mount(2) to work with OPEN_TREE_CLONE
  vfs: syscall: Add move_mount(2) to move mounts around
  vfs: syscall: Add open_tree(2) to reference or clone a mount
parents d27fb65b f1b5618e
......@@ -398,7 +398,12 @@
384 i386 arch_prctl sys_arch_prctl __ia32_compat_sys_arch_prctl
385 i386 io_pgetevents sys_io_pgetevents_time32 __ia32_compat_sys_io_pgetevents
386 i386 rseq sys_rseq __ia32_sys_rseq
# don't use numbers 387 through 392, add new calls at the end
387 i386 open_tree sys_open_tree __ia32_sys_open_tree
388 i386 move_mount sys_move_mount __ia32_sys_move_mount
389 i386 fsopen sys_fsopen __ia32_sys_fsopen
390 i386 fsconfig sys_fsconfig __ia32_sys_fsconfig
391 i386 fsmount sys_fsmount __ia32_sys_fsmount
392 i386 fspick sys_fspick __ia32_sys_fspick
393 i386 semget sys_semget __ia32_sys_semget
394 i386 semctl sys_semctl __ia32_compat_sys_semctl
395 i386 shmget sys_shmget __ia32_sys_shmget
......
......@@ -343,6 +343,12 @@
332 common statx __x64_sys_statx
333 common io_pgetevents __x64_sys_io_pgetevents
334 common rseq __x64_sys_rseq
335 common open_tree __x64_sys_open_tree
336 common move_mount __x64_sys_move_mount
337 common fsopen __x64_sys_fsopen
338 common fsconfig __x64_sys_fsconfig
339 common fsmount __x64_sys_fsmount
340 common fspick __x64_sys_fspick
# don't use numbers 387 through 423, add new calls after the last
# 'common' entry
424 common pidfd_send_signal __x64_sys_pidfd_send_signal
......
......@@ -13,7 +13,7 @@ obj-y := open.o read_write.o file_table.o super.o \
seq_file.o xattr.o libfs.o fs-writeback.o \
pnode.o splice.o sync.o utimes.o d_path.o \
stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
fs_types.o fs_context.o fs_parser.o
fs_types.o fs_context.o fs_parser.o fsopen.o
ifeq ($(CONFIG_BLOCK),y)
obj-y += buffer.o block_dev.o direct-io.o mpage.o
......
......@@ -255,6 +255,7 @@ static void __fput(struct file *file)
struct dentry *dentry = file->f_path.dentry;
struct vfsmount *mnt = file->f_path.mnt;
struct inode *inode = file->f_inode;
fmode_t mode = file->f_mode;
if (unlikely(!(file->f_mode & FMODE_OPENED)))
goto out;
......@@ -277,18 +278,20 @@ static void __fput(struct file *file)
if (file->f_op->release)
file->f_op->release(inode, file);
if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL &&
!(file->f_mode & FMODE_PATH))) {
!(mode & FMODE_PATH))) {
cdev_put(inode->i_cdev);
}
fops_put(file->f_op);
put_pid(file->f_owner.pid);
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
i_readcount_dec(inode);
if (file->f_mode & FMODE_WRITER) {
if (mode & FMODE_WRITER) {
put_write_access(inode);
__mnt_drop_write(mnt);
}
dput(dentry);
if (unlikely(mode & FMODE_NEED_UNMOUNT))
dissolve_on_fput(mnt);
mntput(mnt);
out:
file_free(file);
......
......@@ -11,6 +11,7 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/fs_context.h>
#include <linux/fs_parser.h>
#include <linux/fs.h>
......@@ -23,6 +24,7 @@
#include <linux/pid_namespace.h>
#include <linux/user_namespace.h>
#include <net/net_namespace.h>
#include <asm/sections.h>
#include "mount.h"
#include "internal.h"
......@@ -271,6 +273,8 @@ static struct fs_context *alloc_fs_context(struct file_system_type *fs_type,
fc->cred = get_current_cred();
fc->net_ns = get_net(current->nsproxy->net_ns);
mutex_init(&fc->uapi_mutex);
switch (purpose) {
case FS_CONTEXT_FOR_MOUNT:
fc->user_ns = get_user_ns(fc->cred->user_ns);
......@@ -353,6 +357,8 @@ struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)
if (!fc)
return ERR_PTR(-ENOMEM);
mutex_init(&fc->uapi_mutex);
fc->fs_private = NULL;
fc->s_fs_info = NULL;
fc->source = NULL;
......@@ -361,6 +367,8 @@ struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)
get_net(fc->net_ns);
get_user_ns(fc->user_ns);
get_cred(fc->cred);
if (fc->log)
refcount_inc(&fc->log->usage);
/* Can't call put until we've called ->dup */
ret = fc->ops->dup(fc, src_fc);
......@@ -378,7 +386,6 @@ struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)
}
EXPORT_SYMBOL(vfs_dup_fs_context);
#ifdef CONFIG_PRINTK
/**
* logfc - Log a message to a filesystem context
* @fc: The filesystem context to log to.
......@@ -386,27 +393,100 @@ EXPORT_SYMBOL(vfs_dup_fs_context);
*/
void logfc(struct fs_context *fc, const char *fmt, ...)
{
static const char store_failure[] = "OOM: Can't store error string";
struct fc_log *log = fc ? fc->log : NULL;
const char *p;
va_list va;
char *q;
u8 freeable;
va_start(va, fmt);
switch (fmt[0]) {
case 'w':
vprintk_emit(0, LOGLEVEL_WARNING, NULL, 0, fmt, va);
break;
case 'e':
vprintk_emit(0, LOGLEVEL_ERR, NULL, 0, fmt, va);
break;
default:
vprintk_emit(0, LOGLEVEL_NOTICE, NULL, 0, fmt, va);
break;
if (!strchr(fmt, '%')) {
p = fmt;
goto unformatted_string;
}
if (strcmp(fmt, "%s") == 0) {
p = va_arg(va, const char *);
goto unformatted_string;
}
pr_cont("\n");
q = kvasprintf(GFP_KERNEL, fmt, va);
copied_string:
if (!q)
goto store_failure;
freeable = 1;
goto store_string;
unformatted_string:
if ((unsigned long)p >= (unsigned long)__start_rodata &&
(unsigned long)p < (unsigned long)__end_rodata)
goto const_string;
if (log && within_module_core((unsigned long)p, log->owner))
goto const_string;
q = kstrdup(p, GFP_KERNEL);
goto copied_string;
store_failure:
p = store_failure;
const_string:
q = (char *)p;
freeable = 0;
store_string:
if (!log) {
switch (fmt[0]) {
case 'w':
printk(KERN_WARNING "%s\n", q + 2);
break;
case 'e':
printk(KERN_ERR "%s\n", q + 2);
break;
default:
printk(KERN_NOTICE "%s\n", q + 2);
break;
}
if (freeable)
kfree(q);
} else {
unsigned int logsize = ARRAY_SIZE(log->buffer);
u8 index;
index = log->head & (logsize - 1);
BUILD_BUG_ON(sizeof(log->head) != sizeof(u8) ||
sizeof(log->tail) != sizeof(u8));
if ((u8)(log->head - log->tail) == logsize) {
/* The buffer is full, discard the oldest message */
if (log->need_free & (1 << index))
kfree(log->buffer[index]);
log->tail++;
}
log->buffer[index] = q;
log->need_free &= ~(1 << index);
log->need_free |= freeable << index;
log->head++;
}
va_end(va);
}
EXPORT_SYMBOL(logfc);
#endif
/*
* Free a logging structure.
*/
static void put_fc_log(struct fs_context *fc)
{
struct fc_log *log = fc->log;
int i;
if (log) {
if (refcount_dec_and_test(&log->usage)) {
fc->log = NULL;
for (i = 0; i <= 7; i++)
if (log->need_free & (1 << i))
kfree(log->buffer[i]);
kfree(log);
}
}
}
/**
* put_fs_context - Dispose of a superblock configuration context.
......@@ -431,6 +511,7 @@ void put_fs_context(struct fs_context *fc)
put_user_ns(fc->user_ns);
put_cred(fc->cred);
kfree(fc->subtype);
put_fc_log(fc);
put_filesystem(fc->fs_type);
kfree(fc->source);
kfree(fc);
......@@ -640,3 +721,54 @@ int parse_monolithic_mount_data(struct fs_context *fc, void *data)
return monolithic_mount_data(fc, data);
}
/*
* Clean up a context after performing an action on it and put it into a state
* from where it can be used to reconfigure a superblock.
*
* Note that here we do only the parts that can't fail; the rest is in
* finish_clean_context() below and in between those fs_context is marked
* FS_CONTEXT_AWAITING_RECONF. The reason for splitup is that after
* successful mount or remount we need to report success to userland.
* Trying to do full reinit (for the sake of possible subsequent remount)
* and failing to allocate memory would've put us into a nasty situation.
* So here we only discard the old state and reinitialization is left
* until we actually try to reconfigure.
*/
void vfs_clean_context(struct fs_context *fc)
{
if (fc->need_free && fc->ops && fc->ops->free)
fc->ops->free(fc);
fc->need_free = false;
fc->fs_private = NULL;
fc->s_fs_info = NULL;
fc->sb_flags = 0;
security_free_mnt_opts(&fc->security);
kfree(fc->subtype);
fc->subtype = NULL;
kfree(fc->source);
fc->source = NULL;
fc->purpose = FS_CONTEXT_FOR_RECONFIGURE;
fc->phase = FS_CONTEXT_AWAITING_RECONF;
}
int finish_clean_context(struct fs_context *fc)
{
int error;
if (fc->phase != FS_CONTEXT_AWAITING_RECONF)
return 0;
if (fc->fs_type->init_fs_context)
error = fc->fs_type->init_fs_context(fc);
else
error = legacy_init_fs_context(fc);
if (unlikely(error)) {
fc->phase = FS_CONTEXT_FAILED;
return error;
}
fc->need_free = true;
fc->phase = FS_CONTEXT_RECONF_PARAMS;
return 0;
}
This diff is collapsed.
......@@ -55,8 +55,11 @@ extern void __init chrdev_init(void);
/*
* fs_context.c
*/
extern const struct fs_context_operations legacy_fs_context_ops;
extern int parse_monolithic_mount_data(struct fs_context *, void *);
extern void fc_drop_locked(struct fs_context *);
extern void vfs_clean_context(struct fs_context *fc);
extern int finish_clean_context(struct fs_context *fc);
/*
* namei.c
......@@ -92,6 +95,7 @@ extern void __init mnt_init(void);
extern int __mnt_want_write_file(struct file *);
extern void __mnt_drop_write_file(struct file *);
extern void dissolve_on_fput(struct vfsmount *);
/*
* fs_struct.c
*/
......
This diff is collapsed.
......@@ -165,10 +165,13 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
#define FMODE_NONOTIFY ((__force fmode_t)0x4000000)
/* File is capable of returning -EAGAIN if I/O will block */
#define FMODE_NOWAIT ((__force fmode_t)0x8000000)
#define FMODE_NOWAIT ((__force fmode_t)0x8000000)
/* File represents mount that needs unmounting */
#define FMODE_NEED_UNMOUNT ((__force fmode_t)0x10000000)
/* File does not contribute to nr_files count */
#define FMODE_NOACCOUNT ((__force fmode_t)0x20000000)
#define FMODE_NOACCOUNT ((__force fmode_t)0x20000000)
/*
* Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector
......
......@@ -13,8 +13,10 @@
#define _LINUX_FS_CONTEXT_H
#include <linux/kernel.h>
#include <linux/refcount.h>
#include <linux/errno.h>
#include <linux/security.h>
#include <linux/mutex.h>
struct cred;
struct dentry;
......@@ -34,6 +36,19 @@ enum fs_context_purpose {
FS_CONTEXT_FOR_RECONFIGURE, /* Superblock reconfiguration (remount) */
};
/*
* Userspace usage phase for fsopen/fspick.
*/
enum fs_context_phase {
FS_CONTEXT_CREATE_PARAMS, /* Loading params for sb creation */
FS_CONTEXT_CREATING, /* A superblock is being created */
FS_CONTEXT_AWAITING_MOUNT, /* Superblock created, awaiting fsmount() */
FS_CONTEXT_AWAITING_RECONF, /* Awaiting initialisation for reconfiguration */
FS_CONTEXT_RECONF_PARAMS, /* Loading params for reconfiguration */
FS_CONTEXT_RECONFIGURING, /* Reconfiguring the superblock */
FS_CONTEXT_FAILED, /* Failed to correctly transition a context */
};
/*
* Type of parameter value.
*/
......@@ -74,12 +89,14 @@ struct fs_parameter {
*/
struct fs_context {
const struct fs_context_operations *ops;
struct mutex uapi_mutex; /* Userspace access mutex */
struct file_system_type *fs_type;
void *fs_private; /* The filesystem's context */
struct dentry *root; /* The root and superblock */
struct user_namespace *user_ns; /* The user namespace for this mount */
struct net *net_ns; /* The network namespace for this mount */
const struct cred *cred; /* The mounter's credentials */
struct fc_log *log; /* Logging buffer */
const char *source; /* The source name (eg. dev path) */
const char *subtype; /* The subtype to set on the superblock */
void *security; /* Linux S&M options */
......@@ -88,6 +105,7 @@ struct fs_context {
unsigned int sb_flags_mask; /* Superblock flags that were changed */
unsigned int lsm_flags; /* Information flags from the fs to the LSM */
enum fs_context_purpose purpose:8;
enum fs_context_phase phase:8; /* The phase the context is in */
bool need_free:1; /* Need to call ops->free() */
bool global:1; /* Goes into &init_user_ns */
};
......@@ -135,15 +153,21 @@ extern int vfs_get_super(struct fs_context *fc,
extern const struct file_operations fscontext_fops;
#ifdef CONFIG_PRINTK
/*
* Mount error, warning and informational message logging. This structure is
* shareable between a mount and a subordinate mount.
*/
struct fc_log {
refcount_t usage;
u8 head; /* Insertion index in buffer[] */
u8 tail; /* Removal index in buffer[] */
u8 need_free; /* Mask of kfree'able items in buffer[] */
struct module *owner; /* Owner module for strings that don't then need freeing */
char *buffer[8];
};
extern __attribute__((format(printf, 2, 3)))
void logfc(struct fs_context *fc, const char *fmt, ...);
#else
static inline __attribute__((format(printf, 2, 3)))
void logfc(struct fs_context *fc, const char *fmt, ...)
{
}
#endif
/**
* infof - Store supplementary informational message
......
......@@ -159,6 +159,10 @@
* Parse a string of security data filling in the opts structure
* @options string containing all mount options known by the LSM
* @opts binary data structure usable by the LSM
* @move_mount:
* Check permission before a mount is moved.
* @from_path indicates the mount that is going to be moved.
* @to_path indicates the mountpoint that will be mounted upon.
* @dentry_init_security:
* Compute a context for a dentry as the inode is not yet available
* since NFSv4 has no label backed by an EA anyway.
......@@ -1502,6 +1506,7 @@ union security_list_options {
unsigned long *set_kern_flags);
int (*sb_add_mnt_opt)(const char *option, const char *val, int len,
void **mnt_opts);
int (*move_mount)(const struct path *from_path, const struct path *to_path);
int (*dentry_init_security)(struct dentry *dentry, int mode,
const struct qstr *name, void **ctx,
u32 *ctxlen);
......@@ -1839,6 +1844,7 @@ struct security_hook_heads {
struct hlist_head sb_set_mnt_opts;
struct hlist_head sb_clone_mnt_opts;
struct hlist_head sb_add_mnt_opt;
struct hlist_head move_mount;
struct hlist_head dentry_init_security;
struct hlist_head dentry_create_files_as;
#ifdef CONFIG_SECURITY_PATH
......
......@@ -709,6 +709,12 @@ static inline bool is_module_text_address(unsigned long addr)
return false;
}
static inline bool within_module_core(unsigned long addr,
const struct module *mod)
{
return false;
}
/* Get/put a kernel symbol (calls should be symmetric) */
#define symbol_get(x) ({ extern typeof(x) x __attribute__((weak)); &(x); })
#define symbol_put(x) do { } while (0)
......
......@@ -251,6 +251,7 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb,
unsigned long *set_kern_flags);
int security_add_mnt_opt(const char *option, const char *val,
int len, void **mnt_opts);
int security_move_mount(const struct path *from_path, const struct path *to_path);
int security_dentry_init_security(struct dentry *dentry, int mode,
const struct qstr *name, void **ctx,
u32 *ctxlen);
......@@ -614,6 +615,12 @@ static inline int security_add_mnt_opt(const char *option, const char *val,
return 0;
}
static inline int security_move_mount(const struct path *from_path,
const struct path *to_path)
{
return 0;
}
static inline int security_inode_alloc(struct inode *inode)
{
return 0;
......
......@@ -985,6 +985,15 @@ asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags,
unsigned mask, struct statx __user *buffer);
asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len,
int flags, uint32_t sig);
asmlinkage long sys_open_tree(int dfd, const char __user *path, unsigned flags);
asmlinkage long sys_move_mount(int from_dfd, const char __user *from_path,
int to_dfd, const char __user *to_path,
unsigned int ms_flags);
asmlinkage long sys_fsopen(const char __user *fs_name, unsigned int flags);
asmlinkage long sys_fsconfig(int fs_fd, unsigned int cmd, const char __user *key,
const void __user *value, int aux);
asmlinkage long sys_fsmount(int fs_fd, unsigned int flags, unsigned int ms_flags);
asmlinkage long sys_fspick(int dfd, const char __user *path, unsigned int flags);
asmlinkage long sys_pidfd_send_signal(int pidfd, int sig,
siginfo_t __user *info,
unsigned int flags);
......
......@@ -91,5 +91,7 @@
#define AT_STATX_FORCE_SYNC 0x2000 /* - Force the attributes to be sync'd with the server */
#define AT_STATX_DONT_SYNC 0x4000 /* - Don't sync attributes with the server */
#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */
#endif /* _UAPI_LINUX_FCNTL_H */
......@@ -55,4 +55,66 @@
#define MS_MGC_VAL 0xC0ED0000
#define MS_MGC_MSK 0xffff0000
/*
* open_tree() flags.
*/
#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */
/*
* move_mount() flags.
*/
#define MOVE_MOUNT_F_SYMLINKS 0x00000001 /* Follow symlinks on from path */
#define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002 /* Follow automounts on from path */
#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */
#define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */
#define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */
#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */
#define MOVE_MOUNT__MASK 0x00000077
/*
* fsopen() flags.
*/
#define FSOPEN_CLOEXEC 0x00000001
/*
* fspick() flags.
*/
#define FSPICK_CLOEXEC 0x00000001
#define FSPICK_SYMLINK_NOFOLLOW 0x00000002
#define FSPICK_NO_AUTOMOUNT 0x00000004
#define FSPICK_EMPTY_PATH 0x00000008
/*
* The type of fsconfig() call made.
*/
enum fsconfig_command {
FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */
FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */
FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */
FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */
FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */
FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */
FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */
FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */
};
/*
* fsmount() flags.
*/
#define FSMOUNT_CLOEXEC 0x00000001
/*
* Mount attributes.
*/
#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */
#define MOUNT_ATTR_NOSUID 0x00000002 /* Ignore suid and sgid bits */
#define MOUNT_ATTR_NODEV 0x00000004 /* Disallow access to device special files */
#define MOUNT_ATTR_NOEXEC 0x00000008 /* Disallow program execution */
#define MOUNT_ATTR__ATIME 0x00000070 /* Setting on how atime should be updated */
#define MOUNT_ATTR_RELATIME 0x00000000 /* - Update atime relative to mtime/ctime. */
#define MOUNT_ATTR_NOATIME 0x00000010 /* - Do not update access times. */
#define MOUNT_ATTR_STRICTATIME 0x00000020 /* - Always perform atime updates */
#define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */
#endif /* _UAPI_LINUX_MOUNT_H */
......@@ -154,10 +154,11 @@ config SAMPLE_ANDROID_BINDERFS
Builds a sample program to illustrate the use of the Android binderfs
filesystem.
config SAMPLE_STATX
bool "Build example extended-stat using code"
depends on BROKEN
config SAMPLE_VFS
bool "Build example programs that use new VFS system calls"
help
Build example userspace program to use the new extended-stat syscall.
Build example userspace programs that use new VFS system calls such
as mount API and statx(). Note that this is restricted to the x86
arch whilst it accesses system calls that aren't yet in all arches.
endif # SAMPLES
......@@ -3,4 +3,4 @@
obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \
hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
configfs/ connector/ v4l/ trace_printk/ \
vfio-mdev/ statx/ qmi/ binderfs/ pidfd/
vfio-mdev/ vfs/ qmi/ binderfs/ pidfd/
# List of programs to build
hostprogs-$(CONFIG_SAMPLE_STATX) := test-statx
hostprogs-$(CONFIG_SAMPLE_VFS) := \
test-fsmount \
test-statx
# Tell kbuild to always build the programs
always := $(hostprogs-y)
HOSTCFLAGS_test-fsmount.o += -I$(objtree)/usr/include
HOSTCFLAGS_test-statx.o += -I$(objtree)/usr/include
/* fd-based mount test.
*
* Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <linux/mount.h>
#include <linux/unistd.h>
#define E(x) do { if ((x) == -1) { perror(#x); exit(1); } } while(0)
static void check_messages(int fd)
{
char buf[4096];
int err, n;
err = errno;
for (;;) {
n = read(fd, buf, sizeof(buf));
if (n < 0)
break;
n -= 2;
switch (buf[0]) {
case 'e':
fprintf(stderr, "Error: %*.*s\n", n, n, buf + 2);
break;
case 'w':
fprintf(stderr, "Warning: %*.*s\n", n, n, buf + 2);
break;
case 'i':
fprintf(stderr, "Info: %*.*s\n", n, n, buf + 2);
break;
}
}
errno = err;
}
static __attribute__((noreturn))
void mount_error(int fd, const char *s)
{
check_messages(fd);
fprintf(stderr, "%s: %m\n", s);
exit(1);
}
/* Hope -1 isn't a syscall */
#ifndef __NR_fsopen
#define __NR_fsopen -1
#endif
#ifndef __NR_fsmount
#define __NR_fsmount -1
#endif
#ifndef __NR_fsconfig
#define __NR_fsconfig -1
#endif
#ifndef __NR_move_mount
#define __NR_move_mount -1
#endif
static inline int fsopen(const char *fs_name, unsigned int flags)
{
return syscall(__NR_fsopen, fs_name, flags);
}
static inline int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags)
{
return syscall(__NR_fsmount, fsfd, flags, ms_flags);
}
static inline int fsconfig(int fsfd, unsigned int cmd,
const char *key, const void *val, int aux)
{
return syscall(__NR_fsconfig, fsfd, cmd, key, val, aux);
}
static inline int move_mount(int from_dfd, const char *from_pathname,
int to_dfd, const char *to_pathname,
unsigned int flags)
{
return syscall(__NR_move_mount,
from_dfd, from_pathname,
to_dfd, to_pathname, flags);
}
#define E_fsconfig(fd, cmd, key, val, aux) \
do { \
if (fsconfig(fd, cmd, key, val, aux) == -1) \
mount_error(fd, key ?: "create"); \
} while (0)
int main(int argc, char *argv[])
{
int fsfd, mfd;
/* Mount a publically available AFS filesystem */
fsfd = fsopen("afs", 0);
if (fsfd == -1) {
perror("fsopen");
exit(1);
}
E_fsconfig(fsfd, FSCONFIG_SET_STRING, "source", "#grand.central.org:root.cell.", 0);
E_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
mfd = fsmount(fsfd, 0, MOUNT_ATTR_RDONLY);
if (mfd < 0)
mount_error(fsfd, "fsmount");
E(close(fsfd));
if (move_mount(mfd, "", AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH) < 0) {
perror("move_mount");
exit(1);
}
E(close(mfd));
exit(0);
}
......@@ -25,13 +25,21 @@
#include <sys/types.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#define statx foo
#define statx_timestamp foo_timestamp
#include <sys/stat.h>
#undef statx
#undef statx_timestamp
#define AT_STATX_SYNC_TYPE 0x6000
#define AT_STATX_SYNC_AS_STAT 0x0000
#define AT_STATX_FORCE_SYNC 0x2000
#define AT_STATX_DONT_SYNC 0x4000
#ifndef __NR_statx
#define __NR_statx -1
#endif
static __attribute__((unused))
ssize_t statx(int dfd, const char *filename, unsigned flags,
unsigned int mask, struct statx *buffer)
......@@ -157,7 +165,8 @@ static void dump_statx(struct statx *stx)
"?dai?c??" /* 7- 0 0x00000000-000000ff */
;
printf("Attributes: %016llx (", stx->stx_attributes);
printf("Attributes: %016llx (",
(unsigned long long)stx->stx_attributes);
for (byte = 64 - 8; byte >= 0; byte -= 8) {
bits = stx->stx_attributes >> byte;
mbits = stx->stx_attributes_mask >> byte;
......
......@@ -866,6 +866,11 @@ int security_add_mnt_opt(const char *option, const char *val, int len,
}
EXPORT_SYMBOL(security_add_mnt_opt);
int security_move_mount(const struct path *from_path, const struct path *to_path)
{
return call_int_hook(move_mount, 0, from_path, to_path);
}
int security_inode_alloc(struct inode *inode)
{
int rc = lsm_inode_alloc(inode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment