summaryrefslogtreecommitdiffstats
path: root/ipc/shm.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/shm.c')
-rw-r--r--ipc/shm.c53
1 files changed, 43 insertions, 10 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index ed3027d0f277..331fc1b0b3c7 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -156,11 +156,12 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
156 struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id); 156 struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
157 157
158 /* 158 /*
159 * We raced in the idr lookup or with shm_destroy(). Either way, the 159 * Callers of shm_lock() must validate the status of the returned ipc
160 * ID is busted. 160 * object pointer (as returned by ipc_lock()), and error out as
161 * appropriate.
161 */ 162 */
162 WARN_ON(IS_ERR(ipcp)); 163 if (IS_ERR(ipcp))
163 164 return (void *)ipcp;
164 return container_of(ipcp, struct shmid_kernel, shm_perm); 165 return container_of(ipcp, struct shmid_kernel, shm_perm);
165} 166}
166 167
@@ -186,18 +187,33 @@ static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
186} 187}
187 188
188 189
189/* This is called by fork, once for every shm attach. */ 190static int __shm_open(struct vm_area_struct *vma)
190static void shm_open(struct vm_area_struct *vma)
191{ 191{
192 struct file *file = vma->vm_file; 192 struct file *file = vma->vm_file;
193 struct shm_file_data *sfd = shm_file_data(file); 193 struct shm_file_data *sfd = shm_file_data(file);
194 struct shmid_kernel *shp; 194 struct shmid_kernel *shp;
195 195
196 shp = shm_lock(sfd->ns, sfd->id); 196 shp = shm_lock(sfd->ns, sfd->id);
197
198 if (IS_ERR(shp))
199 return PTR_ERR(shp);
200
197 shp->shm_atim = get_seconds(); 201 shp->shm_atim = get_seconds();
198 shp->shm_lprid = task_tgid_vnr(current); 202 shp->shm_lprid = task_tgid_vnr(current);
199 shp->shm_nattch++; 203 shp->shm_nattch++;
200 shm_unlock(shp); 204 shm_unlock(shp);
205 return 0;
206}
207
208/* This is called by fork, once for every shm attach. */
209static void shm_open(struct vm_area_struct *vma)
210{
211 int err = __shm_open(vma);
212 /*
213 * We raced in the idr lookup or with shm_destroy().
214 * Either way, the ID is busted.
215 */
216 WARN_ON_ONCE(err);
201} 217}
202 218
203/* 219/*
@@ -260,6 +276,14 @@ static void shm_close(struct vm_area_struct *vma)
260 down_write(&shm_ids(ns).rwsem); 276 down_write(&shm_ids(ns).rwsem);
261 /* remove from the list of attaches of the shm segment */ 277 /* remove from the list of attaches of the shm segment */
262 shp = shm_lock(ns, sfd->id); 278 shp = shm_lock(ns, sfd->id);
279
280 /*
281 * We raced in the idr lookup or with shm_destroy().
282 * Either way, the ID is busted.
283 */
284 if (WARN_ON_ONCE(IS_ERR(shp)))
285 goto done; /* no-op */
286
263 shp->shm_lprid = task_tgid_vnr(current); 287 shp->shm_lprid = task_tgid_vnr(current);
264 shp->shm_dtim = get_seconds(); 288 shp->shm_dtim = get_seconds();
265 shp->shm_nattch--; 289 shp->shm_nattch--;
@@ -267,6 +291,7 @@ static void shm_close(struct vm_area_struct *vma)
267 shm_destroy(ns, shp); 291 shm_destroy(ns, shp);
268 else 292 else
269 shm_unlock(shp); 293 shm_unlock(shp);
294done:
270 up_write(&shm_ids(ns).rwsem); 295 up_write(&shm_ids(ns).rwsem);
271} 296}
272 297
@@ -388,17 +413,25 @@ static int shm_mmap(struct file *file, struct vm_area_struct *vma)
388 struct shm_file_data *sfd = shm_file_data(file); 413 struct shm_file_data *sfd = shm_file_data(file);
389 int ret; 414 int ret;
390 415
416 /*
417 * In case of remap_file_pages() emulation, the file can represent
418 * removed IPC ID: propogate shm_lock() error to caller.
419 */
420 ret =__shm_open(vma);
421 if (ret)
422 return ret;
423
391 ret = sfd->file->f_op->mmap(sfd->file, vma); 424 ret = sfd->file->f_op->mmap(sfd->file, vma);
392 if (ret != 0) 425 if (ret) {
426 shm_close(vma);
393 return ret; 427 return ret;
428 }
394 sfd->vm_ops = vma->vm_ops; 429 sfd->vm_ops = vma->vm_ops;
395#ifdef CONFIG_MMU 430#ifdef CONFIG_MMU
396 WARN_ON(!sfd->vm_ops->fault); 431 WARN_ON(!sfd->vm_ops->fault);
397#endif 432#endif
398 vma->vm_ops = &shm_vm_ops; 433 vma->vm_ops = &shm_vm_ops;
399 shm_open(vma); 434 return 0;
400
401 return ret;
402} 435}
403 436
404static int shm_release(struct inode *ino, struct file *file) 437static int shm_release(struct inode *ino, struct file *file)