Commit 283bb7fada7e33a759d8fc9bd7a44532e4ad420e

Authored by Pierre Peiffer
Committed by Linus Torvalds
1 parent 3ac88a41ff

IPC: fix error case when idr-cache is empty in ipcget()

With the use of idr to store the ipc, the case where the idr cache is
empty, when idr_get_new is called (this may happen even if we call
idr_pre_get() before), is not well handled: it lets
semget()/shmget()/msgget() return ENOSPC when this cache is empty, what 1.
does not reflect the facts and 2.  does not conform to the man(s).

This patch fixes this by retrying the whole process of allocation in this case.

Signed-off-by: Pierre Peiffer <pierre.peiffer@bull.net>
Cc: Nadia Derbey <Nadia.Derbey@bull.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 4 changed files with 18 additions and 11 deletions Side-by-side Diff

... ... @@ -203,10 +203,10 @@
203 203 * ipc_addid() locks msq
204 204 */
205 205 id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
206   - if (id == -1) {
  206 + if (id < 0) {
207 207 security_msg_queue_free(msq);
208 208 ipc_rcu_putref(msq);
209   - return -ENOSPC;
  209 + return id;
210 210 }
211 211  
212 212 msq->q_perm.id = msg_buildid(id, msq->q_perm.seq);
... ... @@ -283,10 +283,10 @@
283 283 }
284 284  
285 285 id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
286   - if(id == -1) {
  286 + if (id < 0) {
287 287 security_sem_free(sma);
288 288 ipc_rcu_putref(sma);
289   - return -ENOSPC;
  289 + return id;
290 290 }
291 291 ns->used_sems += nsems;
292 292  
... ... @@ -433,10 +433,11 @@
433 433 if (IS_ERR(file))
434 434 goto no_file;
435 435  
436   - error = -ENOSPC;
437 436 id = shm_addid(ns, shp);
438   - if(id == -1)
  437 + if (id < 0) {
  438 + error = id;
439 439 goto no_id;
  440 + }
440 441  
441 442 shp->shm_cprid = task_tgid_vnr(current);
442 443 shp->shm_lprid = 0;
... ... @@ -262,7 +262,7 @@
262 262 * Add an entry 'new' to the IPC ids idr. The permissions object is
263 263 * initialised and the first free entry is set up and the id assigned
264 264 * is returned. The 'new' entry is returned in a locked state on success.
265   - * On failure the entry is not locked and -1 is returned.
  265 + * On failure the entry is not locked and a negative err-code is returned.
266 266 *
267 267 * Called with ipc_ids.rw_mutex held as a writer.
268 268 */
269 269  
... ... @@ -275,11 +275,11 @@
275 275 size = IPCMNI;
276 276  
277 277 if (ids->in_use >= size)
278   - return -1;
  278 + return -ENOSPC;
279 279  
280 280 err = idr_get_new(&ids->ipcs_idr, new, &id);
281 281 if (err)
282   - return -1;
  282 + return err;
283 283  
284 284 ids->in_use++;
285 285  
... ... @@ -311,7 +311,7 @@
311 311 struct ipc_ops *ops, struct ipc_params *params)
312 312 {
313 313 int err;
314   -
  314 +retry:
315 315 err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
316 316  
317 317 if (!err)
... ... @@ -321,6 +321,9 @@
321 321 err = ops->getnew(ns, params);
322 322 up_write(&ids->rw_mutex);
323 323  
  324 + if (err == -EAGAIN)
  325 + goto retry;
  326 +
324 327 return err;
325 328 }
326 329  
... ... @@ -374,7 +377,7 @@
374 377 struct kern_ipc_perm *ipcp;
375 378 int flg = params->flg;
376 379 int err;
377   -
  380 +retry:
378 381 err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
379 382  
380 383 /*
... ... @@ -410,6 +413,9 @@
410 413 ipc_unlock(ipcp);
411 414 }
412 415 up_write(&ids->rw_mutex);
  416 +
  417 + if (err == -EAGAIN)
  418 + goto retry;
413 419  
414 420 return err;
415 421 }