summaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2018-06-17 12:24:00 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2018-07-12 10:04:28 -0400
commit4f089acc5f76ab1dff17b5f0be7608671a8441dc (patch)
treeb1350378a7669fd4cfdb311759d3642f1f179c0b /ipc
parent183266f26f45a47958afb5c9aa1b3d4651e2eb8c (diff)
downloadlinux-4f089acc5f76ab1dff17b5f0be7608671a8441dc.tar.gz
linux-4f089acc5f76ab1dff17b5f0be7608671a8441dc.tar.bz2
linux-4f089acc5f76ab1dff17b5f0be7608671a8441dc.zip
do_shmat(): grab shp->shm_file earlier, switch to alloc_file_clone()
Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/shm.c39
1 files changed, 18 insertions, 21 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index c702abd578a7..7c8de9511950 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1354,14 +1354,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg,
struct shmid_kernel *shp;
unsigned long addr = (unsigned long)shmaddr;
unsigned long size;
- struct file *file;
+ struct file *file, *base;
int err;
unsigned long flags = MAP_SHARED;
unsigned long prot;
int acc_mode;
struct ipc_namespace *ns;
struct shm_file_data *sfd;
- struct path path;
int f_flags;
unsigned long populate = 0;
@@ -1435,46 +1434,44 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg,
goto out_unlock;
}
- path = shp->shm_file->f_path;
- path_get(&path);
+ /*
+ * 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.
+ */
+ base = get_file(shp->shm_file);
shp->shm_nattch++;
- size = i_size_read(d_inode(path.dentry));
+ size = i_size_read(file_inode(base));
ipc_unlock_object(&shp->shm_perm);
rcu_read_unlock();
err = -ENOMEM;
sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
if (!sfd) {
- path_put(&path);
+ fput(base);
goto out_nattch;
}
- file = alloc_file(&path, f_flags,
- is_file_hugepages(shp->shm_file) ?
+ file = alloc_file_clone(base, f_flags,
+ is_file_hugepages(base) ?
&shm_file_operations_huge :
&shm_file_operations);
err = PTR_ERR(file);
if (IS_ERR(file)) {
kfree(sfd);
- path_put(&path);
+ fput(base);
goto out_nattch;
}
- file->private_data = sfd;
- file->f_mapping = shp->shm_file->f_mapping;
sfd->id = shp->shm_perm.id;
sfd->ns = get_ipc_ns(ns);
- /*
- * 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->file = base;
sfd->vm_ops = NULL;
+ file->private_data = sfd;
err = security_mmap_file(file, prot, flags);
if (err)