Skip to content

Commit ff62a34

Browse files
elmarcotorvalds
authored andcommitted
hugetlb: implement memfd sealing
Implements memfd sealing, similar to shmem: - WRITE: deny fallocate(PUNCH_HOLE). mmap() write is denied in memfd_add_seals(). write() doesn't exist for hugetlbfs. - SHRINK: added similar check as shmem_setattr() - GROW: added similar check as shmem_setattr() & shmem_fallocate() Except write() operation that doesn't exist with hugetlbfs, that should make sealing as close as it can be to shmem support. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Marc-André Lureau <[email protected]> Reviewed-by: Mike Kravetz <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Michal Hocko <[email protected]> Cc: David Herrmann <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent da14c1e commit ff62a34

File tree

2 files changed

+28
-2
lines changed

2 files changed

+28
-2
lines changed

fs/hugetlbfs/inode.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -510,8 +510,16 @@ static long hugetlbfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
510510

511511
if (hole_end > hole_start) {
512512
struct address_space *mapping = inode->i_mapping;
513+
struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
513514

514515
inode_lock(inode);
516+
517+
/* protected by i_mutex */
518+
if (info->seals & F_SEAL_WRITE) {
519+
inode_unlock(inode);
520+
return -EPERM;
521+
}
522+
515523
i_mmap_lock_write(mapping);
516524
if (!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root))
517525
hugetlb_vmdelete_list(&mapping->i_mmap,
@@ -529,6 +537,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
529537
loff_t len)
530538
{
531539
struct inode *inode = file_inode(file);
540+
struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
532541
struct address_space *mapping = inode->i_mapping;
533542
struct hstate *h = hstate_inode(inode);
534543
struct vm_area_struct pseudo_vma;
@@ -560,6 +569,11 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
560569
if (error)
561570
goto out;
562571

572+
if ((info->seals & F_SEAL_GROW) && offset + len > inode->i_size) {
573+
error = -EPERM;
574+
goto out;
575+
}
576+
563577
/*
564578
* Initialize a pseudo vma as this is required by the huge page
565579
* allocation routines. If NUMA is configured, use page index
@@ -650,6 +664,7 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
650664
struct hstate *h = hstate_inode(inode);
651665
int error;
652666
unsigned int ia_valid = attr->ia_valid;
667+
struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
653668

654669
BUG_ON(!inode);
655670

@@ -658,9 +673,16 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
658673
return error;
659674

660675
if (ia_valid & ATTR_SIZE) {
661-
if (attr->ia_size & ~huge_page_mask(h))
676+
loff_t oldsize = inode->i_size;
677+
loff_t newsize = attr->ia_size;
678+
679+
if (newsize & ~huge_page_mask(h))
662680
return -EINVAL;
663-
error = hugetlb_vmtruncate(inode, attr->ia_size);
681+
/* protected by i_mutex */
682+
if ((newsize < oldsize && (info->seals & F_SEAL_SHRINK)) ||
683+
(newsize > oldsize && (info->seals & F_SEAL_GROW)))
684+
return -EPERM;
685+
error = hugetlb_vmtruncate(inode, newsize);
664686
if (error)
665687
return error;
666688
}
@@ -712,13 +734,16 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
712734

713735
inode = new_inode(sb);
714736
if (inode) {
737+
struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
738+
715739
inode->i_ino = get_next_ino();
716740
inode_init_owner(inode, dir, mode);
717741
lockdep_set_class(&inode->i_mapping->i_mmap_rwsem,
718742
&hugetlbfs_i_mmap_rwsem_key);
719743
inode->i_mapping->a_ops = &hugetlbfs_aops;
720744
inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
721745
inode->i_mapping->private_data = resv_map;
746+
info->seals = F_SEAL_SEAL;
722747
switch (mode & S_IFMT) {
723748
default:
724749
init_special_inode(inode, mode, dev);

include/linux/hugetlb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb)
273273
struct hugetlbfs_inode_info {
274274
struct shared_policy policy;
275275
struct inode vfs_inode;
276+
unsigned int seals;
276277
};
277278

278279
static inline struct hugetlbfs_inode_info *HUGETLBFS_I(struct inode *inode)

0 commit comments

Comments
 (0)