projects
/
GitHub
/
mt8127
/
android_kernel_alcatel_ttab.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
ipc: modify message queue accounting to not take kernel data structures into account
[GitHub/mt8127/android_kernel_alcatel_ttab.git]
/
ipc
/
msg.c
diff --git
a/ipc/msg.c
b/ipc/msg.c
index b65fdf1a09dd1f81b32731bfa2fcb455389ea63c..52770bfde2a5afe9eaf2f9694ed4a74250ac89c1 100644
(file)
--- 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_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
static void freeque(struct ipc_namespace *, struct kern_ipc_perm *);
static int newque(struct ipc_namespace *, struct ipc_params *);
#ifdef CONFIG_PROC_FS
@@
-167,12
+165,21
@@
static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
ipc_rmid(&msg_ids(ns), &s->q_perm);
}
ipc_rmid(&msg_ids(ns), &s->q_perm);
}
+static void msg_rcu_free(struct rcu_head *head)
+{
+ struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
+ struct msg_queue *msq = ipc_rcu_to_struct(p);
+
+ security_msg_queue_free(msq);
+ ipc_rcu_free(head);
+}
+
/**
* newque - Create a new msg queue
* @ns: namespace
* @params: ptr to the structure that contains the key and msgflg
*
/**
* newque - Create a new msg queue
* @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.rw
sem
held (writer)
*/
static int newque(struct ipc_namespace *ns, struct ipc_params *params)
{
*/
static int newque(struct ipc_namespace *ns, struct ipc_params *params)
{
@@
-191,15
+198,14
@@
static int newque(struct ipc_namespace *ns, struct ipc_params *params)
msq->q_perm.security = NULL;
retval = security_msg_queue_alloc(msq);
if (retval) {
msq->q_perm.security = NULL;
retval = security_msg_queue_alloc(msq);
if (retval) {
- ipc_rcu_putref(msq);
+ ipc_rcu_putref(msq
, ipc_rcu_free
);
return retval;
}
/* ipc_addid() locks msq upon success. */
id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
if (id < 0) {
return retval;
}
/* ipc_addid() locks msq upon success. */
id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
if (id < 0) {
- security_msg_queue_free(msq);
- ipc_rcu_putref(msq);
+ ipc_rcu_putref(msq, msg_rcu_free);
return id;
}
return id;
}
@@
-259,8
+265,8
@@
static void expunge_all(struct msg_queue *msq, int res)
* removes the message queue from message queue ID IDR, and cleans up all the
* messages associated with this 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.rw
sem
(writer) and the spinlock for this message queue are held
+ * before freeque() is called. msg_ids.rw
sem
remains locked on exit.
*/
static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
{
*/
static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
{
@@
-270,19
+276,19
@@
static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
expunge_all(msq, -EIDRM);
ss_wakeup(&msq->q_senders, 1);
msg_rmid(ns, msq);
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);
free_msg(msg);
}
atomic_sub(msq->q_cbytes, &ns->msg_bytes);
list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
atomic_dec(&ns->msg_hdrs);
free_msg(msg);
}
atomic_sub(msq->q_cbytes, &ns->msg_bytes);
- security_msg_queue_free(msq);
- ipc_rcu_putref(msq);
+ ipc_rcu_putref(msq, msg_rcu_free);
}
/*
}
/*
- * Called with msg_ids.rw
_mutex
and ipcp locked.
+ * Called with msg_ids.rw
sem
and ipcp locked.
*/
static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
{
*/
static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
{
@@
-386,9
+392,9
@@
copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
}
/*
}
/*
- * This function handles some msgctl commands which require the rw
_mutex
+ * This function handles some msgctl commands which require the rw
sem
* to be held in write mode.
* 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 rw
sem
is taken inside this function.
*/
static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
struct msqid_ds __user *buf, int version)
*/
static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
struct msqid_ds __user *buf, int version)
@@
-403,7
+409,7
@@
static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
return -EFAULT;
}
return -EFAULT;
}
- down_write(&msg_ids(ns).rw
_mutex
);
+ down_write(&msg_ids(ns).rw
sem
);
rcu_read_lock();
ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
rcu_read_lock();
ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
@@
-459,7
+465,7
@@
out_unlock0:
out_unlock1:
rcu_read_unlock();
out_up:
out_unlock1:
rcu_read_unlock();
out_up:
- up_write(&msg_ids(ns).rw
_mutex
);
+ up_write(&msg_ids(ns).rw
sem
);
return err;
}
return err;
}
@@
-494,7
+500,7
@@
static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
msginfo.msgmnb = ns->msg_ctlmnb;
msginfo.msgssz = MSGSSZ;
msginfo.msgseg = MSGSEG;
msginfo.msgmnb = ns->msg_ctlmnb;
msginfo.msgssz = MSGSSZ;
msginfo.msgseg = MSGSEG;
- down_read(&msg_ids(ns).rw
_mutex
);
+ down_read(&msg_ids(ns).rw
sem
);
if (cmd == MSG_INFO) {
msginfo.msgpool = msg_ids(ns).in_use;
msginfo.msgmap = atomic_read(&ns->msg_hdrs);
if (cmd == MSG_INFO) {
msginfo.msgpool = msg_ids(ns).in_use;
msginfo.msgmap = atomic_read(&ns->msg_hdrs);
@@
-505,7
+511,7
@@
static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
msginfo.msgtql = MSGTQL;
}
max_id = ipc_get_maxid(&msg_ids(ns));
msginfo.msgtql = MSGTQL;
}
max_id = ipc_get_maxid(&msg_ids(ns));
- up_read(&msg_ids(ns).rw
_mutex
);
+ up_read(&msg_ids(ns).rw
sem
);
if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
return -EFAULT;
return (max_id < 0) ? 0 : max_id;
if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
return -EFAULT;
return (max_id < 0) ? 0 : max_id;
@@
-689,6
+695,12
@@
long do_msgsnd(int msqid, long mtype, void __user *mtext,
if (ipcperms(ns, &msq->q_perm, S_IWUGO))
goto out_unlock0;
if (ipcperms(ns, &msq->q_perm, S_IWUGO))
goto out_unlock0;
+ /* raced with RMID? */
+ if (msq->q_perm.deleted) {
+ err = -EIDRM;
+ goto out_unlock0;
+ }
+
err = security_msg_queue_msgsnd(msq, msg, msgflg);
if (err)
goto out_unlock0;
err = security_msg_queue_msgsnd(msq, msg, msgflg);
if (err)
goto out_unlock0;
@@
-718,7
+730,7
@@
long do_msgsnd(int msqid, long mtype, void __user *mtext,
rcu_read_lock();
ipc_lock_object(&msq->q_perm);
rcu_read_lock();
ipc_lock_object(&msq->q_perm);
- ipc_rcu_putref(msq);
+ ipc_rcu_putref(msq
, ipc_rcu_free
);
if (msq->q_perm.deleted) {
err = -EIDRM;
goto out_unlock0;
if (msq->q_perm.deleted) {
err = -EIDRM;
goto out_unlock0;
@@
-873,6
+885,8
@@
long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
return -EINVAL;
if (msgflg & MSG_COPY) {
return -EINVAL;
if (msgflg & MSG_COPY) {
+ if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT))
+ return -EINVAL;
copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
if (IS_ERR(copy))
return PTR_ERR(copy);
copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
if (IS_ERR(copy))
return PTR_ERR(copy);
@@
-895,6
+909,13
@@
long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
goto out_unlock1;
ipc_lock_object(&msq->q_perm);
goto out_unlock1;
ipc_lock_object(&msq->q_perm);
+
+ /* raced with RMID? */
+ if (msq->q_perm.deleted) {
+ msg = ERR_PTR(-EIDRM);
+ goto out_unlock0;
+ }
+
msg = find_msg(msq, &msgtyp, mode);
if (!IS_ERR(msg)) {
/*
msg = find_msg(msq, &msgtyp, mode);
if (!IS_ERR(msg)) {
/*