@@ -98,11 +98,17 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
return -EINTR;
if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) {
- /* Map delay slot emulation page */
+ /*
+ * Map delay slot emulation page.
+ *
+ * Note: passing vm_seals = 0
+ * Don't support sealing for vdso for now.
+ * This might change when we add sealing support for vdso.
+ */
base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
VM_READ | VM_EXEC |
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
- 0, NULL);
+ 0, NULL, 0);
if (IS_ERR_VALUE(base)) {
ret = base;
goto out;
@@ -266,6 +266,15 @@ extern unsigned int kobjsize(const void *objp);
MM_SEAL_BASE | \
MM_SEAL_PROT_PKEY)
+/*
+ * PROT_SEAL_ALL is all supported flags in mmap().
+ * See include/uapi/asm-generic/mman-common.h.
+ */
+#define PROT_SEAL_ALL ( \
+ PROT_SEAL_SEAL | \
+ PROT_SEAL_BASE | \
+ PROT_SEAL_PROT_PKEY)
+
/*
* vm_flags in vm_area_struct, see mm_types.h.
* When changing, update also include/trace/events/mmflags.h.
@@ -3290,7 +3299,7 @@ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned lo
extern unsigned long mmap_region(struct file *file, unsigned long addr,
unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
- struct list_head *uf);
+ struct list_head *uf, unsigned long vm_seals);
extern unsigned long do_mmap(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot, unsigned long flags,
vm_flags_t vm_flags, unsigned long pgoff, unsigned long *populate,
@@ -3339,12 +3348,47 @@ static inline unsigned long vma_seals(struct vm_area_struct *vma)
return (vma->vm_seals & MM_SEAL_ALL);
}
+static inline void update_vma_seals(struct vm_area_struct *vma, unsigned long vm_seals)
+{
+ vma->vm_seals |= vm_seals;
+}
+
extern bool can_modify_mm(struct mm_struct *mm, unsigned long start,
unsigned long end, unsigned long checkSeals);
extern bool can_modify_vma(struct vm_area_struct *vma,
unsigned long checkSeals);
+/*
+ * Convert prot field of mmap to vm_seals type.
+ */
+static inline unsigned long convert_mmap_seals(unsigned long prot)
+{
+ unsigned long seals = 0;
+
+ /*
+ * set SEAL_PROT_PKEY implies SEAL_BASE.
+ */
+ if (prot & PROT_SEAL_PROT_PKEY)
+ prot |= PROT_SEAL_BASE;
+
+ /*
+ * The seal bits start from bit 26 of the "prot" field of mmap.
+ * see comments in include/uapi/asm-generic/mman-common.h.
+ */
+ seals = (prot & PROT_SEAL_ALL) >> PROT_SEAL_BIT_BEGIN;
+ return seals;
+}
+
+/*
+ * check input sealing type from the "prot" field of mmap().
+ * for CONFIG_MSEAL case, this always return 0 (successful).
+ */
+static inline int check_mmap_seals(unsigned long prot, unsigned long *vm_seals)
+{
+ *vm_seals = convert_mmap_seals(prot);
+ return 0;
+}
#else
static inline bool check_vma_seals_mergeable(unsigned long vm_seals1)
{
@@ -3367,6 +3411,23 @@ static inline bool can_modify_vma(struct vm_area_struct *vma,
{
return true;
}
+
+static inline void update_vma_seals(struct vm_area_struct *vma, unsigned long vm_seals)
+{
+}
+
+/*
+ * check input sealing type from the "prot" field of mmap().
+ * For not CONFIG_MSEAL, if SEAL flag is set, it will return failure.
+ */
+static inline int check_mmap_seals(unsigned long prot, unsigned long *vm_seals)
+{
+ if (prot & PROT_SEAL_ALL)
+ return -EINVAL;
+
+ return 0;
+}
+
#endif
/* These take the mm semaphore themselves */
@@ -17,6 +17,19 @@
#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */
+/*
+ * The PROT_SEAL_XX defines memory sealings flags in the prot argument
+ * of mmap(). The bits currently take consecutive bits and match
+ * the same sequence as MM_SEAL_XX type, this allows convert_mmap_seals()
+ * to convert prot to MM_SEAL_XX type using bit operations.
+ * The include/uapi/linux/mman.h header file defines the MM_SEAL_XX type,
+ * which is used by the mseal() system call.
+ */
+#define PROT_SEAL_BIT_BEGIN 26
+#define PROT_SEAL_SEAL _BITUL(PROT_SEAL_BIT_BEGIN) /* 0x04000000 seal seal */
+#define PROT_SEAL_BASE _BITUL(PROT_SEAL_BIT_BEGIN + 1) /* 0x08000000 base for all sealing types */
+#define PROT_SEAL_PROT_PKEY _BITUL(PROT_SEAL_BIT_BEGIN + 2) /* 0x10000000 seal prot and pkey */
+
/* 0x01 - 0x03 are defined in linux/mman.h */
#define MAP_TYPE 0x0f /* Mask for type of mapping */
#define MAP_FIXED 0x10 /* Interpret addr exactly */
@@ -1211,6 +1211,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
{
struct mm_struct *mm = current->mm;
int pkey = 0;
+ unsigned long vm_seals = 0;
*populate = 0;
@@ -1231,6 +1232,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
if (flags & MAP_FIXED_NOREPLACE)
flags |= MAP_FIXED;
+ if (check_mmap_seals(prot, &vm_seals) < 0)
+ return -EINVAL;
+
if (!(flags & MAP_FIXED))
addr = round_hint_to_min(addr);
@@ -1381,7 +1385,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
vm_flags |= VM_NORESERVE;
}
- addr = mmap_region(file, addr, len, vm_flags, pgoff, uf);
+ addr = mmap_region(file, addr, len, vm_flags, pgoff, uf, vm_seals);
if (!IS_ERR_VALUE(addr) &&
((vm_flags & VM_LOCKED) ||
(flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))
@@ -2679,7 +2683,7 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len,
unsigned long mmap_region(struct file *file, unsigned long addr,
unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
- struct list_head *uf)
+ struct list_head *uf, unsigned long vm_seals)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma = NULL;
@@ -2723,7 +2727,13 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
next = vma_next(&vmi);
prev = vma_prev(&vmi);
- if (vm_flags & VM_SPECIAL) {
+ /*
+ * For now, sealed VMA doesn't merge with other VMA,
+ * Will change this in later commit when we make sealed VMA
+ * also mergeable.
+ */
+ if ((vm_flags & VM_SPECIAL) ||
+ (vm_seals & MM_SEAL_ALL)) {
if (prev)
vma_iter_next_range(&vmi);
goto cannot_expand;
@@ -2781,6 +2791,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
vma->vm_page_prot = vm_get_page_prot(vm_flags);
vma->vm_pgoff = pgoff;
+ update_vma_seals(vma, vm_seals);
+
if (file) {
if (vm_flags & VM_SHARED) {
error = mapping_map_writable(file->f_mapping);
@@ -2992,6 +3004,13 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
if (pgoff + (size >> PAGE_SHIFT) < pgoff)
return ret;
+ /*
+ * Do not support sealing in remap_file_page.
+ * sealing is set via mmap() and mseal().
+ */
+ if (prot & PROT_SEAL_ALL)
+ return ret;
+
if (mmap_write_lock_killable(mm))
return -EINTR;