This patch fixes that do_shmat increases shm_nattch value twice. E.g. if memory segment was created just now and process attaches it, shmctl(..IPC_STAT..) of concurrently running process can at some point of time return data structure with 'shm_nattch' equal to 2.
Signed-off-by: Philippe Mikoyan <philippe.mikoyan@skat.systems> Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhme...@virtuozzo.com> --- ipc/shm.c | 58 +++++++++++++++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/ipc/shm.c b/ipc/shm.c index badac463e2c8..565f17925128 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -190,33 +190,31 @@ static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s) ipc_rmid(&shm_ids(ns), &s->shm_perm); } - -static int __shm_open(struct vm_area_struct *vma) -{ - struct file *file = vma->vm_file; - struct shm_file_data *sfd = shm_file_data(file); - struct shmid_kernel *shp; - - shp = shm_lock(sfd->ns, sfd->id); - - if (IS_ERR(shp)) - return PTR_ERR(shp); - - shp->shm_atim = ktime_get_real_seconds(); - shp->shm_lprid = task_tgid_vnr(current); - shp->shm_nattch++; - shm_unlock(shp); - return 0; -} - /* This is called by fork, once for every shm attach. */ static void shm_open(struct vm_area_struct *vma) { - int err = __shm_open(vma); + struct file *file = vma->vm_file; + struct shm_file_data *sfd = shm_file_data(file); + struct shmid_kernel *shp; + int err = 0; + + shp = shm_lock(sfd->ns, sfd->id); + + if (IS_ERR(shp)) { + err = PTR_ERR(shp); + goto warn; + } + + shp->shm_atim = ktime_get_real_seconds(); + shp->shm_lprid = task_tgid_vnr(current); + shp->shm_nattch++; + shm_unlock(shp); + /* * We raced in the idr lookup or with shm_destroy(). * Either way, the ID is busted. */ +warn: WARN_ON_ONCE(err); } @@ -418,19 +416,10 @@ static int shm_mmap(struct file *file, struct vm_area_struct *vma) struct shm_file_data *sfd = shm_file_data(file); int ret; - /* - * In case of remap_file_pages() emulation, the file can represent - * removed IPC ID: propogate shm_lock() error to caller. - */ - ret = __shm_open(vma); - if (ret) - return ret; - ret = call_mmap(sfd->file, vma); - if (ret) { - shm_close(vma); + if (ret) return ret; - } + sfd->vm_ops = vma->vm_ops; #ifdef CONFIG_MMU WARN_ON(!sfd->vm_ops->fault); @@ -944,6 +933,7 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid, tbuf->shm_cpid = shp->shm_cprid; tbuf->shm_lpid = shp->shm_lprid; tbuf->shm_nattch = shp->shm_nattch; + rcu_read_unlock(); return result; @@ -1351,7 +1341,11 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, path = shp->shm_file->f_path; path_get(&path); + + shp->shm_atim = ktime_get_real_seconds(); + shp->shm_lprid = task_tgid_vnr(current); shp->shm_nattch++; + size = i_size_read(d_inode(path.dentry)); ipc_unlock_object(&shp->shm_perm); rcu_read_unlock(); @@ -1411,6 +1405,8 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, out_fput: fput(file); + if (!err) + goto out; out_nattch: down_write(&shm_ids(ns).rwsem); -- 2.11.0