diff options
-rw-r--r-- | arch/x86/syscalls/syscall_32.tbl | 1 | ||||
-rw-r--r-- | arch/x86/syscalls/syscall_64.tbl | 1 | ||||
-rw-r--r-- | include/linux/syscalls.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/memfd.h | 8 | ||||
-rw-r--r-- | kernel/sys_ni.c | 1 | ||||
-rw-r--r-- | mm/shmem.c | 73 |
6 files changed, 85 insertions, 0 deletions
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl index d1b4a119d4a5..028b78168d85 100644 --- a/arch/x86/syscalls/syscall_32.tbl +++ b/arch/x86/syscalls/syscall_32.tbl | |||
@@ -362,3 +362,4 @@ | |||
362 | 353 i386 renameat2 sys_renameat2 | 362 | 353 i386 renameat2 sys_renameat2 |
363 | 354 i386 seccomp sys_seccomp | 363 | 354 i386 seccomp sys_seccomp |
364 | 355 i386 getrandom sys_getrandom | 364 | 355 i386 getrandom sys_getrandom |
365 | 356 i386 memfd_create sys_memfd_create | ||
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl index 252c804bb1aa..ca2b9aa78c81 100644 --- a/arch/x86/syscalls/syscall_64.tbl +++ b/arch/x86/syscalls/syscall_64.tbl | |||
@@ -325,6 +325,7 @@ | |||
325 | 316 common renameat2 sys_renameat2 | 325 | 316 common renameat2 sys_renameat2 |
326 | 317 common seccomp sys_seccomp | 326 | 317 common seccomp sys_seccomp |
327 | 318 common getrandom sys_getrandom | 327 | 318 common getrandom sys_getrandom |
328 | 319 common memfd_create sys_memfd_create | ||
328 | 329 | ||
329 | # | 330 | # |
330 | # x32-specific system call numbers start at 512 to avoid cache impact | 331 | # x32-specific system call numbers start at 512 to avoid cache impact |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 701daff5d899..15a069425cbf 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -802,6 +802,7 @@ asmlinkage long sys_timerfd_settime(int ufd, int flags, | |||
802 | asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr); | 802 | asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr); |
803 | asmlinkage long sys_eventfd(unsigned int count); | 803 | asmlinkage long sys_eventfd(unsigned int count); |
804 | asmlinkage long sys_eventfd2(unsigned int count, int flags); | 804 | asmlinkage long sys_eventfd2(unsigned int count, int flags); |
805 | asmlinkage long sys_memfd_create(const char __user *uname_ptr, unsigned int flags); | ||
805 | asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); | 806 | asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); |
806 | asmlinkage long sys_old_readdir(unsigned int, struct old_linux_dirent __user *, unsigned int); | 807 | asmlinkage long sys_old_readdir(unsigned int, struct old_linux_dirent __user *, unsigned int); |
807 | asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *, | 808 | asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *, |
diff --git a/include/uapi/linux/memfd.h b/include/uapi/linux/memfd.h new file mode 100644 index 000000000000..534e364bda92 --- /dev/null +++ b/include/uapi/linux/memfd.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef _UAPI_LINUX_MEMFD_H | ||
2 | #define _UAPI_LINUX_MEMFD_H | ||
3 | |||
4 | /* flags for memfd_create(2) (unsigned int) */ | ||
5 | #define MFD_CLOEXEC 0x0001U | ||
6 | #define MFD_ALLOW_SEALING 0x0002U | ||
7 | |||
8 | #endif /* _UAPI_LINUX_MEMFD_H */ | ||
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 2904a2105914..1f79e3714533 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c | |||
@@ -197,6 +197,7 @@ cond_syscall(compat_sys_timerfd_settime); | |||
197 | cond_syscall(compat_sys_timerfd_gettime); | 197 | cond_syscall(compat_sys_timerfd_gettime); |
198 | cond_syscall(sys_eventfd); | 198 | cond_syscall(sys_eventfd); |
199 | cond_syscall(sys_eventfd2); | 199 | cond_syscall(sys_eventfd2); |
200 | cond_syscall(sys_memfd_create); | ||
200 | 201 | ||
201 | /* performance counters: */ | 202 | /* performance counters: */ |
202 | cond_syscall(sys_perf_event_open); | 203 | cond_syscall(sys_perf_event_open); |
diff --git a/mm/shmem.c b/mm/shmem.c index 8b43bb7a4efe..4a5498795a2b 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -66,7 +66,9 @@ static struct vfsmount *shm_mnt; | |||
66 | #include <linux/highmem.h> | 66 | #include <linux/highmem.h> |
67 | #include <linux/seq_file.h> | 67 | #include <linux/seq_file.h> |
68 | #include <linux/magic.h> | 68 | #include <linux/magic.h> |
69 | #include <linux/syscalls.h> | ||
69 | #include <linux/fcntl.h> | 70 | #include <linux/fcntl.h> |
71 | #include <uapi/linux/memfd.h> | ||
70 | 72 | ||
71 | #include <asm/uaccess.h> | 73 | #include <asm/uaccess.h> |
72 | #include <asm/pgtable.h> | 74 | #include <asm/pgtable.h> |
@@ -2732,6 +2734,77 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root) | |||
2732 | shmem_show_mpol(seq, sbinfo->mpol); | 2734 | shmem_show_mpol(seq, sbinfo->mpol); |
2733 | return 0; | 2735 | return 0; |
2734 | } | 2736 | } |
2737 | |||
2738 | #define MFD_NAME_PREFIX "memfd:" | ||
2739 | #define MFD_NAME_PREFIX_LEN (sizeof(MFD_NAME_PREFIX) - 1) | ||
2740 | #define MFD_NAME_MAX_LEN (NAME_MAX - MFD_NAME_PREFIX_LEN) | ||
2741 | |||
2742 | #define MFD_ALL_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING) | ||
2743 | |||
2744 | SYSCALL_DEFINE2(memfd_create, | ||
2745 | const char __user *, uname, | ||
2746 | unsigned int, flags) | ||
2747 | { | ||
2748 | struct shmem_inode_info *info; | ||
2749 | struct file *file; | ||
2750 | int fd, error; | ||
2751 | char *name; | ||
2752 | long len; | ||
2753 | |||
2754 | if (flags & ~(unsigned int)MFD_ALL_FLAGS) | ||
2755 | return -EINVAL; | ||
2756 | |||
2757 | /* length includes terminating zero */ | ||
2758 | len = strnlen_user(uname, MFD_NAME_MAX_LEN + 1); | ||
2759 | if (len <= 0) | ||
2760 | return -EFAULT; | ||
2761 | if (len > MFD_NAME_MAX_LEN + 1) | ||
2762 | return -EINVAL; | ||
2763 | |||
2764 | name = kmalloc(len + MFD_NAME_PREFIX_LEN, GFP_TEMPORARY); | ||
2765 | if (!name) | ||
2766 | return -ENOMEM; | ||
2767 | |||
2768 | strcpy(name, MFD_NAME_PREFIX); | ||
2769 | if (copy_from_user(&name[MFD_NAME_PREFIX_LEN], uname, len)) { | ||
2770 | error = -EFAULT; | ||
2771 | goto err_name; | ||
2772 | } | ||
2773 | |||
2774 | /* terminating-zero may have changed after strnlen_user() returned */ | ||
2775 | if (name[len + MFD_NAME_PREFIX_LEN - 1]) { | ||
2776 | error = -EFAULT; | ||
2777 | goto err_name; | ||
2778 | } | ||
2779 | |||
2780 | fd = get_unused_fd_flags((flags & MFD_CLOEXEC) ? O_CLOEXEC : 0); | ||
2781 | if (fd < 0) { | ||
2782 | error = fd; | ||
2783 | goto err_name; | ||
2784 | } | ||
2785 | |||
2786 | file = shmem_file_setup(name, 0, VM_NORESERVE); | ||
2787 | if (IS_ERR(file)) { | ||
2788 | error = PTR_ERR(file); | ||
2789 | goto err_fd; | ||
2790 | } | ||
2791 | info = SHMEM_I(file_inode(file)); | ||
2792 | file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; | ||
2793 | file->f_flags |= O_RDWR | O_LARGEFILE; | ||
2794 | if (flags & MFD_ALLOW_SEALING) | ||
2795 | info->seals &= ~F_SEAL_SEAL; | ||
2796 | |||
2797 | fd_install(fd, file); | ||
2798 | kfree(name); | ||
2799 | return fd; | ||
2800 | |||
2801 | err_fd: | ||
2802 | put_unused_fd(fd); | ||
2803 | err_name: | ||
2804 | kfree(name); | ||
2805 | return error; | ||
2806 | } | ||
2807 | |||
2735 | #endif /* CONFIG_TMPFS */ | 2808 | #endif /* CONFIG_TMPFS */ |
2736 | 2809 | ||
2737 | static void shmem_put_super(struct super_block *sb) | 2810 | static void shmem_put_super(struct super_block *sb) |