aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/shm.c
diff options
context:
space:
mode:
authorVasiliy Kulikov <segoon@openwall.com>2011-07-28 19:55:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-30 14:44:19 -0400
commit5774ed014f02120db9a6945a1ecebeb97c2acccb (patch)
tree74174553e2729fd582dc73f9d61b2a54286b3ede /ipc/shm.c
parent6c6e3b828b2a13b923b9465fc4316c5bdc92291f (diff)
shm: handle separate PID namespaces case
shm_try_destroy_orphaned() and shm_try_destroy_current() didn't handle the case of separate PID namespaces, but a single IPC namespace. If there are tasks with the same PID values using the same shmem object, the wrong destroy decision could be reached. On shm segment creation store the pointer to the creator task in shmid_kernel->shm_creator field and zero it on task exit. Then use the ->shm_creator insread of shm_cprid in both functions. As shmid_kernel object is already locked at this stage, no additional locking is needed. Signed-off-by: Vasiliy Kulikov <segoon@openwall.com> Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc/shm.c')
-rw-r--r--ipc/shm.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index 3f5b14365f33..fdaf8be65b75 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -239,7 +239,23 @@ static int shm_try_destroy_current(int id, void *p, void *data)
239 if (IS_ERR(shp)) 239 if (IS_ERR(shp))
240 return 0; 240 return 0;
241 241
242 if (shp->shm_cprid != task_tgid_vnr(current)) { 242 if (shp->shm_creator != current) {
243 shm_unlock(shp);
244 return 0;
245 }
246
247 /*
248 * Mark it as orphaned to destroy the segment when
249 * kernel.shm_rmid_forced is changed.
250 * It is noop if the following shm_may_destroy() returns true.
251 */
252 shp->shm_creator = NULL;
253
254 /*
255 * Don't even try to destroy it. If shm_rmid_forced=0 and IPC_RMID
256 * is not set, it shouldn't be deleted here.
257 */
258 if (!ns->shm_rmid_forced) {
243 shm_unlock(shp); 259 shm_unlock(shp);
244 return 0; 260 return 0;
245 } 261 }
@@ -255,7 +271,6 @@ static int shm_try_destroy_orphaned(int id, void *p, void *data)
255{ 271{
256 struct ipc_namespace *ns = data; 272 struct ipc_namespace *ns = data;
257 struct shmid_kernel *shp = shm_lock(ns, id); 273 struct shmid_kernel *shp = shm_lock(ns, id);
258 struct task_struct *task;
259 274
260 if (IS_ERR(shp)) 275 if (IS_ERR(shp))
261 return 0; 276 return 0;
@@ -263,11 +278,8 @@ static int shm_try_destroy_orphaned(int id, void *p, void *data)
263 /* 278 /*
264 * We want to destroy segments without users and with already 279 * We want to destroy segments without users and with already
265 * exit'ed originating process. 280 * exit'ed originating process.
266 *
267 * XXX: the originating process may exist in another pid namespace.
268 */ 281 */
269 task = find_task_by_vpid(shp->shm_cprid); 282 if (shp->shm_creator != NULL) {
270 if (task != NULL) {
271 shm_unlock(shp); 283 shm_unlock(shp);
272 return 0; 284 return 0;
273 } 285 }
@@ -295,7 +307,7 @@ void exit_shm(struct task_struct *task)
295 if (!nsp) 307 if (!nsp)
296 return; 308 return;
297 ns = nsp->ipc_ns; 309 ns = nsp->ipc_ns;
298 if (!ns || !ns->shm_rmid_forced) 310 if (!ns)
299 return; 311 return;
300 312
301 /* Destroy all already created segments, but not mapped yet */ 313 /* Destroy all already created segments, but not mapped yet */
@@ -494,6 +506,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
494 shp->shm_segsz = size; 506 shp->shm_segsz = size;
495 shp->shm_nattch = 0; 507 shp->shm_nattch = 0;
496 shp->shm_file = file; 508 shp->shm_file = file;
509 shp->shm_creator = current;
497 /* 510 /*
498 * shmid gets reported as "inode#" in /proc/pid/maps. 511 * shmid gets reported as "inode#" in /proc/pid/maps.
499 * proc-ps tools use this. Changing this will break them. 512 * proc-ps tools use this. Changing this will break them.