|
|
@@ -417,6 +417,7 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
|
|
|
prev = vma;
|
|
|
|
|
|
for (nstart = start ; ; ) {
|
|
|
+ unsigned long mask_off_old_flags;
|
|
|
unsigned long newflags;
|
|
|
int new_vma_pkey;
|
|
|
|
|
|
@@ -426,9 +427,17 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
|
|
|
if (rier && (vma->vm_flags & VM_MAYEXEC))
|
|
|
prot |= PROT_EXEC;
|
|
|
|
|
|
+ /*
|
|
|
+ * Each mprotect() call explicitly passes r/w/x permissions.
|
|
|
+ * If a permission is not passed to mprotect(), it must be
|
|
|
+ * cleared from the VMA.
|
|
|
+ */
|
|
|
+ mask_off_old_flags = VM_READ | VM_WRITE | VM_EXEC |
|
|
|
+ ARCH_VM_PKEY_FLAGS;
|
|
|
+
|
|
|
new_vma_pkey = arch_override_mprotect_pkey(vma, prot, pkey);
|
|
|
newflags = calc_vm_prot_bits(prot, new_vma_pkey);
|
|
|
- newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
|
|
|
+ newflags |= (vma->vm_flags & ~mask_off_old_flags);
|
|
|
|
|
|
/* newflags >> 4 shift VM_MAY% in place of VM_% */
|
|
|
if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) {
|