|
@@ -1229,6 +1229,7 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
|
|
|
int retval = -EINVAL;
|
|
|
#ifdef CONFIG_MMU
|
|
|
loff_t size = 0;
|
|
|
+ struct file *file;
|
|
|
struct vm_area_struct *next;
|
|
|
#endif
|
|
|
|
|
@@ -1245,7 +1246,8 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
|
|
|
* started at address shmaddr. It records it's size and then unmaps
|
|
|
* it.
|
|
|
* - Then it unmaps all shm vmas that started at shmaddr and that
|
|
|
- * are within the initially determined size.
|
|
|
+ * are within the initially determined size and that are from the
|
|
|
+ * same shm segment from which we determined the size.
|
|
|
* Errors from do_munmap are ignored: the function only fails if
|
|
|
* it's called with invalid parameters or if it's called to unmap
|
|
|
* a part of a vma. Both calls in this function are for full vmas,
|
|
@@ -1271,8 +1273,14 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
|
|
|
if ((vma->vm_ops == &shm_vm_ops) &&
|
|
|
(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
|
|
|
|
|
|
-
|
|
|
- size = file_inode(vma->vm_file)->i_size;
|
|
|
+ /*
|
|
|
+ * Record the file of the shm segment being
|
|
|
+ * unmapped. With mremap(), someone could place
|
|
|
+ * page from another segment but with equal offsets
|
|
|
+ * in the range we are unmapping.
|
|
|
+ */
|
|
|
+ file = vma->vm_file;
|
|
|
+ size = file_inode(file)->i_size;
|
|
|
do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
|
|
|
/*
|
|
|
* We discovered the size of the shm segment, so
|
|
@@ -1298,8 +1306,8 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
|
|
|
|
|
|
/* finding a matching vma now does not alter retval */
|
|
|
if ((vma->vm_ops == &shm_vm_ops) &&
|
|
|
- (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
|
|
|
-
|
|
|
+ ((vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) &&
|
|
|
+ (vma->vm_file == file))
|
|
|
do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
|
|
|
vma = next;
|
|
|
}
|