|
@@ -225,6 +225,12 @@ static int __shm_open(struct vm_area_struct *vma)
|
|
|
if (IS_ERR(shp))
|
|
|
return PTR_ERR(shp);
|
|
|
|
|
|
+ if (shp->shm_file != sfd->file) {
|
|
|
+ /* ID was reused */
|
|
|
+ shm_unlock(shp);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
shp->shm_atim = ktime_get_real_seconds();
|
|
|
ipc_update_pid(&shp->shm_lprid, task_tgid(current));
|
|
|
shp->shm_nattch++;
|
|
@@ -455,8 +461,9 @@ static int shm_mmap(struct file *file, struct vm_area_struct *vma)
|
|
|
int ret;
|
|
|
|
|
|
/*
|
|
|
- * In case of remap_file_pages() emulation, the file can represent
|
|
|
- * removed IPC ID: propogate shm_lock() error to caller.
|
|
|
+ * In case of remap_file_pages() emulation, the file can represent an
|
|
|
+ * IPC ID that was removed, and possibly even reused by another shm
|
|
|
+ * segment already. Propagate this case as an error to caller.
|
|
|
*/
|
|
|
ret = __shm_open(vma);
|
|
|
if (ret)
|
|
@@ -480,6 +487,7 @@ static int shm_release(struct inode *ino, struct file *file)
|
|
|
struct shm_file_data *sfd = shm_file_data(file);
|
|
|
|
|
|
put_ipc_ns(sfd->ns);
|
|
|
+ fput(sfd->file);
|
|
|
shm_file_data(file) = NULL;
|
|
|
kfree(sfd);
|
|
|
return 0;
|
|
@@ -1445,7 +1453,16 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg,
|
|
|
file->f_mapping = shp->shm_file->f_mapping;
|
|
|
sfd->id = shp->shm_perm.id;
|
|
|
sfd->ns = get_ipc_ns(ns);
|
|
|
- sfd->file = shp->shm_file;
|
|
|
+ /*
|
|
|
+ * We need to take a reference to the real shm file to prevent the
|
|
|
+ * pointer from becoming stale in cases where the lifetime of the outer
|
|
|
+ * file extends beyond that of the shm segment. It's not usually
|
|
|
+ * possible, but it can happen during remap_file_pages() emulation as
|
|
|
+ * that unmaps the memory, then does ->mmap() via file reference only.
|
|
|
+ * We'll deny the ->mmap() if the shm segment was since removed, but to
|
|
|
+ * detect shm ID reuse we need to compare the file pointers.
|
|
|
+ */
|
|
|
+ sfd->file = get_file(shp->shm_file);
|
|
|
sfd->vm_ops = NULL;
|
|
|
|
|
|
err = security_mmap_file(file, prot, flags);
|