From: Greg Kroah-Hartman Date: Wed, 16 Oct 2013 00:01:32 +0000 (-0700) Subject: 3.11-stable patches X-Git-Tag: v3.10.17~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=025e71a5570b2a32c65ba060de723db7c687213c;p=thirdparty%2Fkernel%2Fstable-queue.git 3.11-stable patches added patches: ipc-document-general-ipc-locking-scheme.patch ipc-drop-ipc_lock_by_ptr.patch ipc-drop-ipc_lock_check.patch ipc-msg-drop-msg_unlock.patch ipc-rename-ids-rw_mutex.patch ipc-shm-drop-shm_lock_check.patch ipc-shm-guard-against-non-existant-vma-in-shmdt-2.patch --- diff --git a/queue-3.11/ipc-document-general-ipc-locking-scheme.patch b/queue-3.11/ipc-document-general-ipc-locking-scheme.patch new file mode 100644 index 00000000000..50a9a45a4a9 --- /dev/null +++ b/queue-3.11/ipc-document-general-ipc-locking-scheme.patch @@ -0,0 +1,46 @@ +From 05603c44a7627793219b0bd9a7b236099dc9cd9d Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:26 -0700 +Subject: ipc: document general ipc locking scheme + +From: Davidlohr Bueso + +commit 05603c44a7627793219b0bd9a7b236099dc9cd9d upstream. + +As suggested by Andrew, add a generic initial locking scheme used +throughout all sysv ipc mechanisms. Documenting the ids rwsem, how rcu +can be enough to do the initial checks and when to actually acquire the +kern_ipc_perm.lock spinlock. + +I found that adding it to util.c was generic enough. + +Signed-off-by: Davidlohr Bueso +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + ipc/util.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -15,6 +15,14 @@ + * Jun 2006 - namespaces ssupport + * OpenVZ, SWsoft Inc. + * Pavel Emelianov ++ * ++ * General sysv ipc locking scheme: ++ * when doing ipc id lookups, take the ids->rwsem ++ * rcu_read_lock() ++ * obtain the ipc object (kern_ipc_perm) ++ * perform security, capabilities, auditing and permission checks, etc. ++ * acquire the ipc lock (kern_ipc_perm.lock) throught ipc_lock_object() ++ * perform data updates (ie: SET, RMID, LOCK/UNLOCK commands) + */ + + #include diff --git a/queue-3.11/ipc-drop-ipc_lock_by_ptr.patch b/queue-3.11/ipc-drop-ipc_lock_by_ptr.patch new file mode 100644 index 00000000000..6cdd9e3c7e4 --- /dev/null +++ b/queue-3.11/ipc-drop-ipc_lock_by_ptr.patch @@ -0,0 +1,77 @@ +From 32a2750010981216fb788c5190fb0e646abfab30 Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:29 -0700 +Subject: ipc: drop ipc_lock_by_ptr + +From: Davidlohr Bueso + +commit 32a2750010981216fb788c5190fb0e646abfab30 upstream. + +After previous cleanups and optimizations, this function is no longer +heavily used and we don't have a good reason to keep it. Update the few +remaining callers and get rid of it. + +Signed-off-by: Davidlohr Bueso +Cc: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + ipc/namespace.c | 3 ++- + ipc/util.c | 6 ++++-- + ipc/util.h | 6 ------ + 3 files changed, 6 insertions(+), 9 deletions(-) + +--- a/ipc/namespace.c ++++ b/ipc/namespace.c +@@ -89,7 +89,8 @@ void free_ipcs(struct ipc_namespace *ns, + perm = idr_find(&ids->ipcs_idr, next_id); + if (perm == NULL) + continue; +- ipc_lock_by_ptr(perm); ++ rcu_read_lock(); ++ ipc_lock_object(perm); + free(ns, perm); + total++; + } +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -205,7 +205,8 @@ static struct kern_ipc_perm *ipc_findkey + continue; + } + +- ipc_lock_by_ptr(ipc); ++ rcu_read_lock(); ++ ipc_lock_object(ipc); + return ipc; + } + +@@ -830,7 +831,8 @@ static struct kern_ipc_perm *sysvipc_fin + ipc = idr_find(&ids->ipcs_idr, pos); + if (ipc != NULL) { + *new_pos = pos + 1; +- ipc_lock_by_ptr(ipc); ++ rcu_read_lock(); ++ ipc_lock_object(ipc); + return ipc; + } + } +--- a/ipc/util.h ++++ b/ipc/util.h +@@ -179,12 +179,6 @@ static inline void ipc_assert_locked_obj + assert_spin_locked(&perm->lock); + } + +-static inline void ipc_lock_by_ptr(struct kern_ipc_perm *perm) +-{ +- rcu_read_lock(); +- ipc_lock_object(perm); +-} +- + static inline void ipc_unlock(struct kern_ipc_perm *perm) + { + ipc_unlock_object(perm); diff --git a/queue-3.11/ipc-drop-ipc_lock_check.patch b/queue-3.11/ipc-drop-ipc_lock_check.patch new file mode 100644 index 00000000000..27ac1bb4de6 --- /dev/null +++ b/queue-3.11/ipc-drop-ipc_lock_check.patch @@ -0,0 +1,60 @@ +From 20b8875abcf2daa1dda5cf70bd6369df5e85d4c1 Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:31 -0700 +Subject: ipc: drop ipc_lock_check + +From: Davidlohr Bueso + +commit 20b8875abcf2daa1dda5cf70bd6369df5e85d4c1 upstream. + +No remaining users, we now use ipc_obtain_object_check(). + +Signed-off-by: Davidlohr Bueso +Cc: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + ipc/util.c | 16 ---------------- + ipc/util.h | 1 - + 2 files changed, 17 deletions(-) + +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -678,22 +678,6 @@ out: + return out; + } + +-struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id) +-{ +- struct kern_ipc_perm *out; +- +- out = ipc_lock(ids, id); +- if (IS_ERR(out)) +- return out; +- +- if (ipc_checkid(out, id)) { +- ipc_unlock(out); +- return ERR_PTR(-EIDRM); +- } +- +- return out; +-} +- + /** + * ipcget - Common sys_*get() code + * @ns : namsepace +--- a/ipc/util.h ++++ b/ipc/util.h +@@ -185,7 +185,6 @@ static inline void ipc_unlock(struct ker + rcu_read_unlock(); + } + +-struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id); + struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id); + int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, + struct ipc_ops *ops, struct ipc_params *params); diff --git a/queue-3.11/ipc-msg-drop-msg_unlock.patch b/queue-3.11/ipc-msg-drop-msg_unlock.patch new file mode 100644 index 00000000000..f144ef6b875 --- /dev/null +++ b/queue-3.11/ipc-msg-drop-msg_unlock.patch @@ -0,0 +1,46 @@ +From 4718787d1f626f45ddb239912bc07266b9880044 Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:25 -0700 +Subject: ipc,msg: drop msg_unlock + +From: Davidlohr Bueso + +commit 4718787d1f626f45ddb239912bc07266b9880044 upstream. + +There is only one user left, drop this function and just call +ipc_unlock_object() and rcu_read_unlock(). + +Signed-off-by: Davidlohr Bueso +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + ipc/msg.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/ipc/msg.c ++++ b/ipc/msg.c +@@ -70,8 +70,6 @@ struct msg_sender { + + #define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS]) + +-#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) +- + static void freeque(struct ipc_namespace *, struct kern_ipc_perm *); + static int newque(struct ipc_namespace *, struct ipc_params *); + #ifdef CONFIG_PROC_FS +@@ -278,7 +276,8 @@ static void freeque(struct ipc_namespace + expunge_all(msq, -EIDRM); + ss_wakeup(&msq->q_senders, 1); + msg_rmid(ns, msq); +- msg_unlock(msq); ++ ipc_unlock_object(&msq->q_perm); ++ rcu_read_unlock(); + + list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) { + atomic_dec(&ns->msg_hdrs); diff --git a/queue-3.11/ipc-rename-ids-rw_mutex.patch b/queue-3.11/ipc-rename-ids-rw_mutex.patch new file mode 100644 index 00000000000..8d3602ee8f4 --- /dev/null +++ b/queue-3.11/ipc-rename-ids-rw_mutex.patch @@ -0,0 +1,594 @@ +From d9a605e40b1376eb02b067d7690580255a0df68f Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:24 -0700 +Subject: ipc: rename ids->rw_mutex + +From: Davidlohr Bueso + +commit d9a605e40b1376eb02b067d7690580255a0df68f upstream. + +Since in some situations the lock can be shared for readers, we shouldn't +be calling it a mutex, rename it to rwsem. + +Signed-off-by: Davidlohr Bueso +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/ipc_namespace.h | 2 - + ipc/msg.c | 20 +++++++-------- + ipc/namespace.c | 4 +-- + ipc/sem.c | 24 +++++++++--------- + ipc/shm.c | 56 +++++++++++++++++++++--------------------- + ipc/util.c | 28 ++++++++++----------- + ipc/util.h | 4 +-- + 7 files changed, 69 insertions(+), 69 deletions(-) + +--- a/include/linux/ipc_namespace.h ++++ b/include/linux/ipc_namespace.h +@@ -22,7 +22,7 @@ struct ipc_ids { + int in_use; + unsigned short seq; + unsigned short seq_max; +- struct rw_semaphore rw_mutex; ++ struct rw_semaphore rwsem; + struct idr ipcs_idr; + int next_id; + }; +--- a/ipc/msg.c ++++ b/ipc/msg.c +@@ -181,7 +181,7 @@ static void msg_rcu_free(struct rcu_head + * @ns: namespace + * @params: ptr to the structure that contains the key and msgflg + * +- * Called with msg_ids.rw_mutex held (writer) ++ * Called with msg_ids.rwsem held (writer) + */ + static int newque(struct ipc_namespace *ns, struct ipc_params *params) + { +@@ -267,8 +267,8 @@ static void expunge_all(struct msg_queue + * removes the message queue from message queue ID IDR, and cleans up all the + * messages associated with this queue. + * +- * msg_ids.rw_mutex (writer) and the spinlock for this message queue are held +- * before freeque() is called. msg_ids.rw_mutex remains locked on exit. ++ * msg_ids.rwsem (writer) and the spinlock for this message queue are held ++ * before freeque() is called. msg_ids.rwsem remains locked on exit. + */ + static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) + { +@@ -289,7 +289,7 @@ static void freeque(struct ipc_namespace + } + + /* +- * Called with msg_ids.rw_mutex and ipcp locked. ++ * Called with msg_ids.rwsem and ipcp locked. + */ + static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg) + { +@@ -393,9 +393,9 @@ copy_msqid_from_user(struct msqid64_ds * + } + + /* +- * This function handles some msgctl commands which require the rw_mutex ++ * This function handles some msgctl commands which require the rwsem + * to be held in write mode. +- * NOTE: no locks must be held, the rw_mutex is taken inside this function. ++ * NOTE: no locks must be held, the rwsem is taken inside this function. + */ + static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, + struct msqid_ds __user *buf, int version) +@@ -410,7 +410,7 @@ static int msgctl_down(struct ipc_namesp + return -EFAULT; + } + +- down_write(&msg_ids(ns).rw_mutex); ++ down_write(&msg_ids(ns).rwsem); + rcu_read_lock(); + + ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd, +@@ -466,7 +466,7 @@ out_unlock0: + out_unlock1: + rcu_read_unlock(); + out_up: +- up_write(&msg_ids(ns).rw_mutex); ++ up_write(&msg_ids(ns).rwsem); + return err; + } + +@@ -501,7 +501,7 @@ static int msgctl_nolock(struct ipc_name + msginfo.msgmnb = ns->msg_ctlmnb; + msginfo.msgssz = MSGSSZ; + msginfo.msgseg = MSGSEG; +- down_read(&msg_ids(ns).rw_mutex); ++ down_read(&msg_ids(ns).rwsem); + if (cmd == MSG_INFO) { + msginfo.msgpool = msg_ids(ns).in_use; + msginfo.msgmap = atomic_read(&ns->msg_hdrs); +@@ -512,7 +512,7 @@ static int msgctl_nolock(struct ipc_name + msginfo.msgtql = MSGTQL; + } + max_id = ipc_get_maxid(&msg_ids(ns)); +- up_read(&msg_ids(ns).rw_mutex); ++ up_read(&msg_ids(ns).rwsem); + if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) + return -EFAULT; + return (max_id < 0) ? 0 : max_id; +--- a/ipc/namespace.c ++++ b/ipc/namespace.c +@@ -81,7 +81,7 @@ void free_ipcs(struct ipc_namespace *ns, + int next_id; + int total, in_use; + +- down_write(&ids->rw_mutex); ++ down_write(&ids->rwsem); + + in_use = ids->in_use; + +@@ -93,7 +93,7 @@ void free_ipcs(struct ipc_namespace *ns, + free(ns, perm); + total++; + } +- up_write(&ids->rw_mutex); ++ up_write(&ids->rwsem); + } + + static void free_ipc_ns(struct ipc_namespace *ns) +--- a/ipc/sem.c ++++ b/ipc/sem.c +@@ -365,7 +365,7 @@ static inline void sem_unlock(struct sem + } + + /* +- * sem_lock_(check_) routines are called in the paths where the rw_mutex ++ * sem_lock_(check_) routines are called in the paths where the rwsem + * is not held. + * + * The caller holds the RCU read lock. +@@ -464,7 +464,7 @@ static inline void sem_rmid(struct ipc_n + * @ns: namespace + * @params: ptr to the structure that contains key, semflg and nsems + * +- * Called with sem_ids.rw_mutex held (as a writer) ++ * Called with sem_ids.rwsem held (as a writer) + */ + + static int newary(struct ipc_namespace *ns, struct ipc_params *params) +@@ -529,7 +529,7 @@ static int newary(struct ipc_namespace * + + + /* +- * Called with sem_ids.rw_mutex and ipcp locked. ++ * Called with sem_ids.rwsem and ipcp locked. + */ + static inline int sem_security(struct kern_ipc_perm *ipcp, int semflg) + { +@@ -540,7 +540,7 @@ static inline int sem_security(struct ke + } + + /* +- * Called with sem_ids.rw_mutex and ipcp locked. ++ * Called with sem_ids.rwsem and ipcp locked. + */ + static inline int sem_more_checks(struct kern_ipc_perm *ipcp, + struct ipc_params *params) +@@ -1031,8 +1031,8 @@ static int count_semzcnt (struct sem_arr + return semzcnt; + } + +-/* Free a semaphore set. freeary() is called with sem_ids.rw_mutex locked +- * as a writer and the spinlock for this semaphore set hold. sem_ids.rw_mutex ++/* Free a semaphore set. freeary() is called with sem_ids.rwsem locked ++ * as a writer and the spinlock for this semaphore set hold. sem_ids.rwsem + * remains locked on exit. + */ + static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) +@@ -1152,7 +1152,7 @@ static int semctl_nolock(struct ipc_name + seminfo.semmnu = SEMMNU; + seminfo.semmap = SEMMAP; + seminfo.semume = SEMUME; +- down_read(&sem_ids(ns).rw_mutex); ++ down_read(&sem_ids(ns).rwsem); + if (cmd == SEM_INFO) { + seminfo.semusz = sem_ids(ns).in_use; + seminfo.semaem = ns->used_sems; +@@ -1161,7 +1161,7 @@ static int semctl_nolock(struct ipc_name + seminfo.semaem = SEMAEM; + } + max_id = ipc_get_maxid(&sem_ids(ns)); +- up_read(&sem_ids(ns).rw_mutex); ++ up_read(&sem_ids(ns).rwsem); + if (copy_to_user(p, &seminfo, sizeof(struct seminfo))) + return -EFAULT; + return (max_id < 0) ? 0: max_id; +@@ -1467,9 +1467,9 @@ copy_semid_from_user(struct semid64_ds * + } + + /* +- * This function handles some semctl commands which require the rw_mutex ++ * This function handles some semctl commands which require the rwsem + * to be held in write mode. +- * NOTE: no locks must be held, the rw_mutex is taken inside this function. ++ * NOTE: no locks must be held, the rwsem is taken inside this function. + */ + static int semctl_down(struct ipc_namespace *ns, int semid, + int cmd, int version, void __user *p) +@@ -1484,7 +1484,7 @@ static int semctl_down(struct ipc_namesp + return -EFAULT; + } + +- down_write(&sem_ids(ns).rw_mutex); ++ down_write(&sem_ids(ns).rwsem); + rcu_read_lock(); + + ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd, +@@ -1523,7 +1523,7 @@ out_unlock0: + out_unlock1: + rcu_read_unlock(); + out_up: +- up_write(&sem_ids(ns).rw_mutex); ++ up_write(&sem_ids(ns).rwsem); + return err; + } + +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -83,8 +83,8 @@ void shm_init_ns(struct ipc_namespace *n + } + + /* +- * Called with shm_ids.rw_mutex (writer) and the shp structure locked. +- * Only shm_ids.rw_mutex remains locked on exit. ++ * Called with shm_ids.rwsem (writer) and the shp structure locked. ++ * Only shm_ids.rwsem remains locked on exit. + */ + static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) + { +@@ -148,7 +148,7 @@ static inline struct shmid_kernel *shm_o + } + + /* +- * shm_lock_(check_) routines are called in the paths where the rw_mutex ++ * shm_lock_(check_) routines are called in the paths where the rwsem + * is not necessarily held. + */ + static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) +@@ -214,7 +214,7 @@ static void shm_open(struct vm_area_stru + * @ns: namespace + * @shp: struct to free + * +- * It has to be called with shp and shm_ids.rw_mutex (writer) locked, ++ * It has to be called with shp and shm_ids.rwsem (writer) locked, + * but returns with shp unlocked and freed. + */ + static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) +@@ -261,7 +261,7 @@ static void shm_close(struct vm_area_str + struct shmid_kernel *shp; + struct ipc_namespace *ns = sfd->ns; + +- down_write(&shm_ids(ns).rw_mutex); ++ down_write(&shm_ids(ns).rwsem); + /* remove from the list of attaches of the shm segment */ + shp = shm_lock(ns, sfd->id); + BUG_ON(IS_ERR(shp)); +@@ -272,10 +272,10 @@ static void shm_close(struct vm_area_str + shm_destroy(ns, shp); + else + shm_unlock(shp); +- up_write(&shm_ids(ns).rw_mutex); ++ up_write(&shm_ids(ns).rwsem); + } + +-/* Called with ns->shm_ids(ns).rw_mutex locked */ ++/* Called with ns->shm_ids(ns).rwsem locked */ + static int shm_try_destroy_current(int id, void *p, void *data) + { + struct ipc_namespace *ns = data; +@@ -306,7 +306,7 @@ static int shm_try_destroy_current(int i + return 0; + } + +-/* Called with ns->shm_ids(ns).rw_mutex locked */ ++/* Called with ns->shm_ids(ns).rwsem locked */ + static int shm_try_destroy_orphaned(int id, void *p, void *data) + { + struct ipc_namespace *ns = data; +@@ -317,7 +317,7 @@ static int shm_try_destroy_orphaned(int + * We want to destroy segments without users and with already + * exit'ed originating process. + * +- * As shp->* are changed under rw_mutex, it's safe to skip shp locking. ++ * As shp->* are changed under rwsem, it's safe to skip shp locking. + */ + if (shp->shm_creator != NULL) + return 0; +@@ -331,10 +331,10 @@ static int shm_try_destroy_orphaned(int + + void shm_destroy_orphaned(struct ipc_namespace *ns) + { +- down_write(&shm_ids(ns).rw_mutex); ++ down_write(&shm_ids(ns).rwsem); + if (shm_ids(ns).in_use) + idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns); +- up_write(&shm_ids(ns).rw_mutex); ++ up_write(&shm_ids(ns).rwsem); + } + + +@@ -346,10 +346,10 @@ void exit_shm(struct task_struct *task) + return; + + /* Destroy all already created segments, but not mapped yet */ +- down_write(&shm_ids(ns).rw_mutex); ++ down_write(&shm_ids(ns).rwsem); + if (shm_ids(ns).in_use) + idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns); +- up_write(&shm_ids(ns).rw_mutex); ++ up_write(&shm_ids(ns).rwsem); + } + + static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +@@ -483,7 +483,7 @@ static const struct vm_operations_struct + * @ns: namespace + * @params: ptr to the structure that contains key, size and shmflg + * +- * Called with shm_ids.rw_mutex held as a writer. ++ * Called with shm_ids.rwsem held as a writer. + */ + + static int newseg(struct ipc_namespace *ns, struct ipc_params *params) +@@ -590,7 +590,7 @@ no_file: + } + + /* +- * Called with shm_ids.rw_mutex and ipcp locked. ++ * Called with shm_ids.rwsem and ipcp locked. + */ + static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg) + { +@@ -601,7 +601,7 @@ static inline int shm_security(struct ke + } + + /* +- * Called with shm_ids.rw_mutex and ipcp locked. ++ * Called with shm_ids.rwsem and ipcp locked. + */ + static inline int shm_more_checks(struct kern_ipc_perm *ipcp, + struct ipc_params *params) +@@ -714,7 +714,7 @@ static inline unsigned long copy_shminfo + + /* + * Calculate and add used RSS and swap pages of a shm. +- * Called with shm_ids.rw_mutex held as a reader ++ * Called with shm_ids.rwsem held as a reader + */ + static void shm_add_rss_swap(struct shmid_kernel *shp, + unsigned long *rss_add, unsigned long *swp_add) +@@ -741,7 +741,7 @@ static void shm_add_rss_swap(struct shmi + } + + /* +- * Called with shm_ids.rw_mutex held as a reader ++ * Called with shm_ids.rwsem held as a reader + */ + static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, + unsigned long *swp) +@@ -770,9 +770,9 @@ static void shm_get_stat(struct ipc_name + } + + /* +- * This function handles some shmctl commands which require the rw_mutex ++ * This function handles some shmctl commands which require the rwsem + * to be held in write mode. +- * NOTE: no locks must be held, the rw_mutex is taken inside this function. ++ * NOTE: no locks must be held, the rwsem is taken inside this function. + */ + static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd, + struct shmid_ds __user *buf, int version) +@@ -787,7 +787,7 @@ static int shmctl_down(struct ipc_namesp + return -EFAULT; + } + +- down_write(&shm_ids(ns).rw_mutex); ++ down_write(&shm_ids(ns).rwsem); + rcu_read_lock(); + + ipcp = ipcctl_pre_down_nolock(ns, &shm_ids(ns), shmid, cmd, +@@ -826,7 +826,7 @@ out_unlock0: + out_unlock1: + rcu_read_unlock(); + out_up: +- up_write(&shm_ids(ns).rw_mutex); ++ up_write(&shm_ids(ns).rwsem); + return err; + } + +@@ -857,9 +857,9 @@ static int shmctl_nolock(struct ipc_name + if(copy_shminfo_to_user (buf, &shminfo, version)) + return -EFAULT; + +- down_read(&shm_ids(ns).rw_mutex); ++ down_read(&shm_ids(ns).rwsem); + err = ipc_get_maxid(&shm_ids(ns)); +- up_read(&shm_ids(ns).rw_mutex); ++ up_read(&shm_ids(ns).rwsem); + + if(err<0) + err = 0; +@@ -870,14 +870,14 @@ static int shmctl_nolock(struct ipc_name + struct shm_info shm_info; + + memset(&shm_info, 0, sizeof(shm_info)); +- down_read(&shm_ids(ns).rw_mutex); ++ down_read(&shm_ids(ns).rwsem); + shm_info.used_ids = shm_ids(ns).in_use; + shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp); + shm_info.shm_tot = ns->shm_tot; + shm_info.swap_attempts = 0; + shm_info.swap_successes = 0; + err = ipc_get_maxid(&shm_ids(ns)); +- up_read(&shm_ids(ns).rw_mutex); ++ up_read(&shm_ids(ns).rwsem); + if (copy_to_user(buf, &shm_info, sizeof(shm_info))) { + err = -EFAULT; + goto out; +@@ -1176,7 +1176,7 @@ out_fput: + fput(file); + + out_nattch: +- down_write(&shm_ids(ns).rw_mutex); ++ down_write(&shm_ids(ns).rwsem); + shp = shm_lock(ns, shmid); + BUG_ON(IS_ERR(shp)); + shp->shm_nattch--; +@@ -1184,7 +1184,7 @@ out_nattch: + shm_destroy(ns, shp); + else + shm_unlock(shp); +- up_write(&shm_ids(ns).rw_mutex); ++ up_write(&shm_ids(ns).rwsem); + return err; + + out_unlock: +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -119,7 +119,7 @@ __initcall(ipc_init); + + void ipc_init_ids(struct ipc_ids *ids) + { +- init_rwsem(&ids->rw_mutex); ++ init_rwsem(&ids->rwsem); + + ids->in_use = 0; + ids->seq = 0; +@@ -174,7 +174,7 @@ void __init ipc_init_proc_interface(cons + * @ids: Identifier set + * @key: The key to find + * +- * Requires ipc_ids.rw_mutex locked. ++ * Requires ipc_ids.rwsem locked. + * Returns the LOCKED pointer to the ipc structure if found or NULL + * if not. + * If key is found ipc points to the owning ipc structure +@@ -208,7 +208,7 @@ static struct kern_ipc_perm *ipc_findkey + * ipc_get_maxid - get the last assigned id + * @ids: IPC identifier set + * +- * Called with ipc_ids.rw_mutex held. ++ * Called with ipc_ids.rwsem held. + */ + + int ipc_get_maxid(struct ipc_ids *ids) +@@ -246,7 +246,7 @@ int ipc_get_maxid(struct ipc_ids *ids) + * 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. + * +- * Called with writer ipc_ids.rw_mutex held. ++ * Called with writer ipc_ids.rwsem held. + */ + int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) + { +@@ -312,9 +312,9 @@ static int ipcget_new(struct ipc_namespa + { + int err; + +- down_write(&ids->rw_mutex); ++ down_write(&ids->rwsem); + err = ops->getnew(ns, params); +- up_write(&ids->rw_mutex); ++ up_write(&ids->rwsem); + return err; + } + +@@ -331,7 +331,7 @@ static int ipcget_new(struct ipc_namespa + * + * On success, the IPC id is returned. + * +- * It is called with ipc_ids.rw_mutex and ipcp->lock held. ++ * It is called with ipc_ids.rwsem and ipcp->lock held. + */ + static int ipc_check_perms(struct ipc_namespace *ns, + struct kern_ipc_perm *ipcp, +@@ -376,7 +376,7 @@ static int ipcget_public(struct ipc_name + * Take the lock as a writer since we are potentially going to add + * a new entry + read locks are not "upgradable" + */ +- down_write(&ids->rw_mutex); ++ down_write(&ids->rwsem); + ipcp = ipc_findkey(ids, params->key); + if (ipcp == NULL) { + /* key not used */ +@@ -402,7 +402,7 @@ static int ipcget_public(struct ipc_name + } + ipc_unlock(ipcp); + } +- up_write(&ids->rw_mutex); ++ up_write(&ids->rwsem); + + return err; + } +@@ -413,7 +413,7 @@ static int ipcget_public(struct ipc_name + * @ids: IPC identifier set + * @ipcp: ipc perm structure containing the identifier to remove + * +- * ipc_ids.rw_mutex (as a writer) and the spinlock for this ID are held ++ * ipc_ids.rwsem (as a writer) and the spinlock for this ID are held + * before this function is called, and remain locked on the exit. + */ + +@@ -613,7 +613,7 @@ struct kern_ipc_perm *ipc_obtain_object( + } + + /** +- * ipc_lock - Lock an ipc structure without rw_mutex held ++ * ipc_lock - Lock an ipc structure without rwsem held + * @ids: IPC identifier set + * @id: ipc id to look for + * +@@ -740,7 +740,7 @@ int ipc_update_perm(struct ipc64_perm *i + * - performs some audit and permission check, depending on the given cmd + * - returns a pointer to the ipc object or otherwise, the corresponding error. + * +- * Call holding the both the rw_mutex and the rcu read lock. ++ * Call holding the both the rwsem and the rcu read lock. + */ + struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns, + struct ipc_ids *ids, int id, int cmd, +@@ -860,7 +860,7 @@ static void *sysvipc_proc_start(struct s + * Take the lock - this will be released by the corresponding + * call to stop(). + */ +- down_read(&ids->rw_mutex); ++ down_read(&ids->rwsem); + + /* pos < 0 is invalid */ + if (*pos < 0) +@@ -887,7 +887,7 @@ static void sysvipc_proc_stop(struct seq + + ids = &iter->ns->ids[iface->ids]; + /* Release the lock we took in start() */ +- up_read(&ids->rw_mutex); ++ up_read(&ids->rwsem); + } + + static int sysvipc_proc_show(struct seq_file *s, void *it) +--- a/ipc/util.h ++++ b/ipc/util.h +@@ -101,10 +101,10 @@ void __init ipc_init_proc_interface(cons + #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) + #define ipcid_to_seqx(id) ((id) / SEQ_MULTIPLIER) + +-/* must be called with ids->rw_mutex acquired for writing */ ++/* must be called with ids->rwsem acquired for writing */ + int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); + +-/* must be called with ids->rw_mutex acquired for reading */ ++/* must be called with ids->rwsem acquired for reading */ + int ipc_get_maxid(struct ipc_ids *); + + /* must be called with both locks acquired. */ diff --git a/queue-3.11/ipc-shm-drop-shm_lock_check.patch b/queue-3.11/ipc-shm-drop-shm_lock_check.patch new file mode 100644 index 00000000000..70313536aa3 --- /dev/null +++ b/queue-3.11/ipc-shm-drop-shm_lock_check.patch @@ -0,0 +1,45 @@ +From 7a25dd9e042b2b94202a67e5551112f4ac87285a Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:30 -0700 +Subject: ipc, shm: drop shm_lock_check + +From: Davidlohr Bueso + +commit 7a25dd9e042b2b94202a67e5551112f4ac87285a upstream. + +This function was replaced by a the lockless shm_obtain_object_check(), +and no longer has any users. + +Signed-off-by: Davidlohr Bueso +Cc: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + ipc/shm.c | 11 ----------- + 1 file changed, 11 deletions(-) + +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -167,17 +167,6 @@ static inline void shm_lock_by_ptr(struc + ipc_lock_object(&ipcp->shm_perm); + } + +-static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns, +- int id) +-{ +- 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); +-} +- + static void shm_rcu_free(struct rcu_head *head) + { + struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu); diff --git a/queue-3.11/ipc-shm-guard-against-non-existant-vma-in-shmdt-2.patch b/queue-3.11/ipc-shm-guard-against-non-existant-vma-in-shmdt-2.patch new file mode 100644 index 00000000000..544175985c5 --- /dev/null +++ b/queue-3.11/ipc-shm-guard-against-non-existant-vma-in-shmdt-2.patch @@ -0,0 +1,40 @@ +From 530fcd16d87cd2417c472a581ba5a1e501556c86 Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:28 -0700 +Subject: ipc, shm: guard against non-existant vma in shmdt(2) + +From: Davidlohr Bueso + +commit 530fcd16d87cd2417c472a581ba5a1e501556c86 upstream. + +When !CONFIG_MMU there's a chance we can derefence a NULL pointer when the +VM area isn't found - check the return value of find_vma(). + +Also, remove the redundant -EINVAL return: retval is set to the proper +return code and *only* changed to 0, when we actually unmap the segments. + +Signed-off-by: Davidlohr Bueso +Cc: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + ipc/shm.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -1295,8 +1295,7 @@ SYSCALL_DEFINE1(shmdt, char __user *, sh + #else /* CONFIG_MMU */ + /* under NOMMU conditions, the exact address to be destroyed must be + * given */ +- retval = -EINVAL; +- if (vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) { ++ if (vma && vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) { + do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start); + retval = 0; + } diff --git a/queue-3.11/series b/queue-3.11/series index 4b1e035ee5b..df3ee059fb0 100644 --- a/queue-3.11/series +++ b/queue-3.11/series @@ -37,3 +37,10 @@ ipc-shm-make-shmctl_nolock-lockless.patch ipc-shm-shorten-critical-region-for-shmctl.patch ipc-shm-cleanup-do_shmat-pasta.patch ipc-shm-shorten-critical-region-for-shmat.patch +ipc-rename-ids-rw_mutex.patch +ipc-msg-drop-msg_unlock.patch +ipc-document-general-ipc-locking-scheme.patch +ipc-shm-guard-against-non-existant-vma-in-shmdt-2.patch +ipc-drop-ipc_lock_by_ptr.patch +ipc-shm-drop-shm_lock_check.patch +ipc-drop-ipc_lock_check.patch