mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
ipc/util.c: use ipc_rcu_putref() for failues in ipc_addid()
ipc_addid() is impossible to use: - for certain failures, the caller must not use ipc_rcu_putref(), because the reference counter is not yet initialized. - for other failures, the caller must use ipc_rcu_putref(), because parallel operations could be ongoing already. The patch cleans that up, by initializing the refcount early, and by modifying all callers. The issues is related to the finding of [email protected]: syzbot found an issue with reading kern_ipc_perm.seq, here both read and write to already released memory could happen. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Manfred Spraul <[email protected]> Cc: Dmitry Vyukov <[email protected]> Cc: Kees Cook <[email protected]> Cc: Davidlohr Bueso <[email protected]> Cc: Davidlohr Bueso <[email protected]> Cc: Herbert Xu <[email protected]> Cc: Michael Kerrisk <[email protected]> Cc: Michal Hocko <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
parent
e2652ae6bd
commit
39cfffd774
4 changed files with 12 additions and 4 deletions
10
ipc/util.c
10
ipc/util.c
|
|
@ -251,7 +251,9 @@ static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new)
|
|||
* Add an entry 'new' to the ipc ids idr. The permissions object is
|
||||
* initialised and the first free entry is set up and the id assigned
|
||||
* is returned. The 'new' entry is returned in a locked state on success.
|
||||
*
|
||||
* On failure the entry is not locked and a negative err-code is returned.
|
||||
* The caller must use ipc_rcu_putref() to free the identifier.
|
||||
*
|
||||
* Called with writer ipc_ids.rwsem held.
|
||||
*/
|
||||
|
|
@ -261,6 +263,9 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
|
|||
kgid_t egid;
|
||||
int idx, err;
|
||||
|
||||
/* 1) Initialize the refcount so that ipc_rcu_putref works */
|
||||
refcount_set(&new->refcount, 1);
|
||||
|
||||
if (limit > IPCMNI)
|
||||
limit = IPCMNI;
|
||||
|
||||
|
|
@ -269,9 +274,7 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
|
|||
|
||||
idr_preload(GFP_KERNEL);
|
||||
|
||||
refcount_set(&new->refcount, 1);
|
||||
spin_lock_init(&new->lock);
|
||||
new->deleted = false;
|
||||
rcu_read_lock();
|
||||
spin_lock(&new->lock);
|
||||
|
||||
|
|
@ -279,6 +282,8 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
|
|||
new->cuid = new->uid = euid;
|
||||
new->gid = new->cgid = egid;
|
||||
|
||||
new->deleted = false;
|
||||
|
||||
idx = ipc_idr_alloc(ids, new);
|
||||
idr_preload_end();
|
||||
|
||||
|
|
@ -291,6 +296,7 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
|
|||
}
|
||||
}
|
||||
if (idx < 0) {
|
||||
new->deleted = true;
|
||||
spin_unlock(&new->lock);
|
||||
rcu_read_unlock();
|
||||
return idx;
|
||||
|
|
|
|||
Loading…
Reference in a new issue