@@ -456,3 +456,4 @@
449 i386 futex_waitv sys_futex_waitv
450 i386 set_mempolicy_home_node sys_set_mempolicy_home_node
451 i386 memfd_restricted sys_memfd_restricted
+452 i386 memfd_restricted_bind sys_memfd_restricted_bind
@@ -373,6 +373,7 @@
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 common memfd_restricted sys_memfd_restricted
+452 common memfd_restricted_bind sys_memfd_restricted_bind
#
# Due to a historical design error, certain syscalls are numbered differently
@@ -126,7 +126,7 @@ struct shared_policy {
int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst);
struct mempolicy *mpol_create(
- unsigned long mode, const unsigned long __user *nmask, unsigned long maxnode)
+ unsigned long mode, const unsigned long __user *nmask, unsigned long maxnode);
void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol);
int __mpol_set_shared_policy(struct shared_policy *info, struct mempolicy *mpol,
unsigned long pgoff_start, unsigned long npages);
@@ -1059,6 +1059,11 @@ asmlinkage long sys_set_mempolicy_home_node(unsigned long start, unsigned long l
unsigned long home_node,
unsigned long flags);
asmlinkage long sys_memfd_restricted(unsigned int flags);
+asmlinkage long sys_memfd_restricted_bind(int fd, struct file_range __user *range,
+ unsigned long mode,
+ const unsigned long __user *nmask,
+ unsigned long maxnode,
+ unsigned int flags);
/*
* Architecture-specific system calls
@@ -889,10 +889,13 @@ __SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)
#ifdef __ARCH_WANT_MEMFD_RESTRICTED
#define __NR_memfd_restricted 451
__SYSCALL(__NR_memfd_restricted, sys_memfd_restricted)
+
+#define __NR_memfd_restricted_bind 452
+__SYSCALL(__NR_memfd_restricted_bind, sys_memfd_restricted_bind)
#endif
#undef __NR_syscalls
-#define __NR_syscalls 452
+#define __NR_syscalls 453
/*
* 32 bit systems traditionally used different
@@ -6,9 +6,9 @@
#ifndef _UAPI_LINUX_MEMPOLICY_H
#define _UAPI_LINUX_MEMPOLICY_H
+#include <asm-generic/posix_types.h>
#include <linux/errno.h>
-
/*
* Both the MPOL_* mempolicy mode and the MPOL_F_* optional mode flags are
* passed by the user to either set_mempolicy() or mbind() in an 'int' actual.
@@ -72,4 +72,9 @@ enum {
#define RECLAIM_WRITE (1<<1) /* Writeout pages during reclaim */
#define RECLAIM_UNMAP (1<<2) /* Unmap pages during reclaim */
+struct file_range {
+ __kernel_loff_t offset;
+ __kernel_size_t len;
+};
+
#endif /* _UAPI_LINUX_MEMPOLICY_H */
@@ -362,6 +362,7 @@ COND_SYSCALL(memfd_secret);
/* memfd_restricted */
COND_SYSCALL(memfd_restricted);
+COND_SYSCALL(memfd_restricted_bind);
/*
* Architecture specific weak syscall entries.
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/mempolicy.h>
#include "linux/sbitmap.h"
#include <linux/pagemap.h>
#include <linux/pseudo_fs.h>
@@ -359,3 +360,77 @@ int restrictedmem_get_page(struct file *file, pgoff_t offset,
return 0;
}
EXPORT_SYMBOL_GPL(restrictedmem_get_page);
+
+static int restrictedmem_set_shared_policy(
+ struct file *file, loff_t start, size_t len, struct mempolicy *mpol)
+{
+ struct restrictedmem *rm;
+ unsigned long end;
+
+ if (!PAGE_ALIGNED(start))
+ return -EINVAL;
+
+ len = PAGE_ALIGN(len);
+ end = start + len;
+
+ if (end < start)
+ return -EINVAL;
+ if (end == start)
+ return 0;
+
+ rm = file->f_mapping->private_data;
+ return __mpol_set_shared_policy(shmem_shared_policy(rm->memfd), mpol,
+ start >> PAGE_SHIFT, len >> PAGE_SHIFT);
+}
+
+static long do_memfd_restricted_bind(
+ int fd, loff_t offset, size_t len,
+ unsigned long mode, const unsigned long __user *nmask,
+ unsigned long maxnode, unsigned int flags)
+{
+ long ret;
+ struct fd f;
+ struct mempolicy *mpol;
+
+ /* None of the flags are supported */
+ if (flags)
+ return -EINVAL;
+
+ f = fdget_raw(fd);
+ if (!f.file)
+ return -EBADF;
+
+ if (!file_is_restrictedmem(f.file))
+ return -EINVAL;
+
+ mpol = mpol_create(mode, nmask, maxnode);
+ if (IS_ERR(mpol)) {
+ ret = PTR_ERR(mpol);
+ goto out;
+ }
+
+ ret = restrictedmem_set_shared_policy(f.file, offset, len, mpol);
+
+ mpol_put(mpol);
+
+out:
+ fdput(f);
+
+ return ret;
+}
+
+SYSCALL_DEFINE6(memfd_restricted_bind, int, fd, struct file_range __user *, range,
+ unsigned long, mode, const unsigned long __user *, nmask,
+ unsigned long, maxnode, unsigned int, flags)
+{
+ loff_t offset;
+ size_t len;
+
+ if (unlikely(get_user(offset, &range->offset)))
+ return -EFAULT;
+ if (unlikely(get_user(len, &range->len)))
+ return -EFAULT;
+
+ return do_memfd_restricted_bind(fd, offset, len, mode, nmask,
+ maxnode, flags);
+}
@@ -46,6 +46,7 @@ cat << EOF
#ifndef __ARCH_WANT_MEMFD_RESTRICTED
#define __IGNORE_memfd_restricted
+#define __IGNORE_memfd_restricted_bind
#endif
/* Missing flags argument */