From b1ed88b47f5e18c6efb8041275c16eeead5377df Mon Sep 17 00:00:00 2001 From: Pierre Peiffer Date: Wed, 6 Feb 2008 01:36:23 -0800 Subject: IPC: fix error check in all new xxx_lock() and xxx_exit_ns() functions In the new implementation of the [sem|shm|msg]_lock[_check]() routines, we use the return value of ipc_lock() in container_of() without any check. But ipc_lock may return a errcode. The use of this errcode in container_of() may alter this errcode, and we don't want this. And in xxx_exit_ns, the pointer return by idr_find is of type 'struct kern_ipc_per'... Today, the code will work as is because the member used in these container_of() is the first member of its container (offset == 0), the errcode isn't changed then. But in the general case, we can't count on this assumption and this may lead later to a real bug if we don't correct this. Again, the proposed solution is simple and correct. But, as pointed by Nadia, with this solution, the same check will be done several times (in all sub-callers...), what is not very funny/optimal... Signed-off-by: Pierre Peiffer Cc: Nadia Derbey Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/shm.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'ipc/shm.c') diff --git a/ipc/shm.c b/ipc/shm.c index 3818fae625c..65c3a294aba 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -111,6 +111,7 @@ int shm_init_ns(struct ipc_namespace *ns) void shm_exit_ns(struct ipc_namespace *ns) { struct shmid_kernel *shp; + struct kern_ipc_perm *perm; int next_id; int total, in_use; @@ -119,10 +120,11 @@ void shm_exit_ns(struct ipc_namespace *ns) in_use = shm_ids(ns).in_use; for (total = 0, next_id = 0; total < in_use; next_id++) { - shp = idr_find(&shm_ids(ns).ipcs_idr, next_id); - if (shp == NULL) + perm = idr_find(&shm_ids(ns).ipcs_idr, next_id); + if (perm == NULL) continue; - ipc_lock_by_ptr(&shp->shm_perm); + ipc_lock_by_ptr(perm); + shp = container_of(perm, struct shmid_kernel, shm_perm); do_shm_rmid(ns, shp); total++; } @@ -149,6 +151,9 @@ static inline struct shmid_kernel *shm_lock_down(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_down(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -158,6 +163,9 @@ static inline struct shmid_kernel *shm_lock_check_down( { struct kern_ipc_perm *ipcp = ipc_lock_check_down(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -169,6 +177,9 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -177,6 +188,9 @@ static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } -- cgit v1.2.3