Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Documentation/admin-guide/sysctl/fs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Currently, these files are in /proc/sys/fs:
- protected_hardlinks
- protected_regular
- protected_symlinks
- romount_protect
- suid_dumpable
- super-max
- super-nr
Expand Down Expand Up @@ -272,6 +273,23 @@ follower match, or when the directory owner matches the symlink's owner.
This protection is based on the restrictions in Openwall and grsecurity.


romount_protect
---------------

This toggle enables read-only mount protection.

If romount_protect is set to (0), there are no protections.
If romount_protect is set to (1), filesystems will be
protected in the following ways:
* No new writable mounts will be allowed
* Existing read-only mounts won't be able to be remounted read/write
* Write operations will be denied on all block devices

Once romount_protect is set to (1), it cannot be disabled.

This feature is mainly intended for secure embedded systems.


suid_dumpable:
--------------

Expand Down
2 changes: 1 addition & 1 deletion fs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ obj-y := open.o read_write.o file_table.o super.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 fsopen.o init.o \
kernel_read_file.o remap_range.o
kernel_read_file.o remap_range.o rofs.o

ifeq ($(CONFIG_BLOCK),y)
obj-y += buffer.o block_dev.o direct-io.o mpage.o
Expand Down
3 changes: 3 additions & 0 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -2998,6 +2998,9 @@ static int may_open(struct user_namespace *mnt_userns, const struct path *path,
if (flag & O_NOATIME && !inode_owner_or_capable(mnt_userns, inode))
return -EPERM;

if (handle_rofs_blockwrite(dentry, path->mnt, acc_mode))
return -EPERM;

return 0;
}

Expand Down
6 changes: 6 additions & 0 deletions fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <uapi/linux/mount.h>
#include <linux/fs_context.h>
#include <linux/shmem_fs.h>
#include <linux/mount.h>

#include "pnode.h"
#include "internal.h"
Expand Down Expand Up @@ -3219,6 +3220,11 @@ int path_mount(const char *dev_name, struct path *path,
SB_LAZYTIME |
SB_I_VERSION);

if (handle_rofs_mount(path.dentry, path.mnt, mnt_flags)) {
retval = -EPERM;
goto dput_out;
}

if ((flags & (MS_REMOUNT | MS_BIND)) == (MS_REMOUNT | MS_BIND))
return do_reconfigure_mnt(path, mnt_flags);
if (flags & MS_REMOUNT)
Expand Down
29 changes: 29 additions & 0 deletions fs/rofs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mount.h>
#include <linux/major.h>
#include <linux/fs.h>

int enable_rofs __read_mostly = 0;

int
handle_rofs_mount(struct dentry *dentry, struct vfsmount *mnt, int mnt_flags)
{
if (enable_rofs && !(mnt_flags & MNT_READONLY))
return -EPERM;
else
return 0;
}

int
handle_rofs_blockwrite(struct dentry *dentry, struct vfsmount *mnt, int acc_mode)
{
struct inode *inode = d_backing_inode(dentry);

if (enable_rofs && (acc_mode & MAY_WRITE) &&
inode && (S_ISBLK(inode->i_mode) || (S_ISCHR(inode->i_mode) && imajor(inode) == RAW_MAJOR)))
return -EPERM;
else
return 0;
}
4 changes: 4 additions & 0 deletions include/linux/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,8 @@ extern bool path_is_mountpoint(const struct path *path);

extern void kern_unmount_array(struct vfsmount *mnt[], unsigned int num);

extern int enable_rofs;
extern int handle_rofs_mount(struct dentry *dentry, struct vfsmount *mnt, int mnt_flags);
extern int handle_rofs_blockwrite(struct dentry *dentry, struct vfsmount *mnt, int acc_mode);

#endif /* _LINUX_MOUNT_H */
9 changes: 9 additions & 0 deletions kernel/sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3362,6 +3362,15 @@ static struct ctl_table fs_table[] = {
.extra1 = SYSCTL_ZERO,
.extra2 = &two,
},
{
.procname = "romount_protect",
.data = &enable_rofs,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax_sysadmin,
.extra1 = SYSCTL_ONE,
.extra2 = SYSCTL_ONE,
},
{
.procname = "suid_dumpable",
.data = &suid_dumpable,
Expand Down