diff options
| author | Kees Cook <keescook@chromium.org> | 2017-07-12 17:35:02 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-12 19:26:01 -0400 |
| commit | 101ede01dfd5072651965e974bc6e30c8d0748e2 (patch) | |
| tree | de85b9884a50812354b9f9ccdc3193a30239fa4d /ipc/sem.c | |
| parent | 5ccc8fb54f1c083f1dc7e073150ec18d43457872 (diff) | |
ipc/sem: avoid ipc_rcu_alloc()
Instead of using ipc_rcu_alloc() which only performs the refcount bump,
open code it to perform better sem-specific checks. This also allows
for sem_array structure layout to be randomized in the future.
[manfred@colorfullife.com: Rediff, because the memset was temporarily inside ipc_rcu_alloc()]
Link: http://lkml.kernel.org/r/20170525185107.12869-10-manfred@colorfullife.com
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc/sem.c')
| -rw-r--r-- | ipc/sem.c | 25 |
1 files changed, 20 insertions, 5 deletions
| @@ -451,6 +451,25 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s) | |||
| 451 | ipc_rmid(&sem_ids(ns), &s->sem_perm); | 451 | ipc_rmid(&sem_ids(ns), &s->sem_perm); |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | static struct sem_array *sem_alloc(size_t nsems) | ||
| 455 | { | ||
| 456 | struct sem_array *sma; | ||
| 457 | size_t size; | ||
| 458 | |||
| 459 | if (nsems > (INT_MAX - sizeof(*sma)) / sizeof(sma->sems[0])) | ||
| 460 | return NULL; | ||
| 461 | |||
| 462 | size = sizeof(*sma) + nsems * sizeof(sma->sems[0]); | ||
| 463 | sma = kvmalloc(size, GFP_KERNEL); | ||
| 464 | if (unlikely(!sma)) | ||
| 465 | return NULL; | ||
| 466 | |||
| 467 | memset(sma, 0, size); | ||
| 468 | atomic_set(&sma->sem_perm.refcount, 1); | ||
| 469 | |||
| 470 | return sma; | ||
| 471 | } | ||
| 472 | |||
| 454 | /** | 473 | /** |
| 455 | * newary - Create a new semaphore set | 474 | * newary - Create a new semaphore set |
| 456 | * @ns: namespace | 475 | * @ns: namespace |
| @@ -463,7 +482,6 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
| 463 | int id; | 482 | int id; |
| 464 | int retval; | 483 | int retval; |
| 465 | struct sem_array *sma; | 484 | struct sem_array *sma; |
| 466 | int size; | ||
| 467 | key_t key = params->key; | 485 | key_t key = params->key; |
| 468 | int nsems = params->u.nsems; | 486 | int nsems = params->u.nsems; |
| 469 | int semflg = params->flg; | 487 | int semflg = params->flg; |
| @@ -474,10 +492,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
| 474 | if (ns->used_sems + nsems > ns->sc_semmns) | 492 | if (ns->used_sems + nsems > ns->sc_semmns) |
| 475 | return -ENOSPC; | 493 | return -ENOSPC; |
| 476 | 494 | ||
| 477 | BUILD_BUG_ON(offsetof(struct sem_array, sem_perm) != 0); | 495 | sma = sem_alloc(nsems); |
| 478 | |||
| 479 | size = sizeof(*sma) + nsems * sizeof(sma->sems[0]); | ||
| 480 | sma = container_of(ipc_rcu_alloc(size), struct sem_array, sem_perm); | ||
| 481 | if (!sma) | 496 | if (!sma) |
| 482 | return -ENOMEM; | 497 | return -ENOMEM; |
| 483 | 498 | ||
