From 156d9ed1260ee566f2be09c13254b58247edfb29 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 9 Jul 2017 07:57:34 -0400 Subject: msgctl(): split the actual work from copyin/copyout Signed-off-by: Al Viro --- ipc/msg.c | 202 +++++++++++++++++++++++++++++--------------------------------- 1 file changed, 96 insertions(+), 106 deletions(-) (limited to 'ipc/msg.c') diff --git a/ipc/msg.c b/ipc/msg.c index 5b25e0755656..322e7bf8b8d1 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -361,23 +361,17 @@ copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) * 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) + struct msqid64_ds *msqid64) { struct kern_ipc_perm *ipcp; - struct msqid64_ds uninitialized_var(msqid64); struct msg_queue *msq; int err; - if (cmd == IPC_SET) { - if (copy_msqid_from_user(&msqid64, buf, version)) - return -EFAULT; - } - down_write(&msg_ids(ns).rwsem); rcu_read_lock(); ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd, - &msqid64.msg_perm, msqid64.msg_qbytes); + &msqid64->msg_perm, msqid64->msg_qbytes); if (IS_ERR(ipcp)) { err = PTR_ERR(ipcp); goto out_unlock1; @@ -399,18 +393,18 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, { DEFINE_WAKE_Q(wake_q); - if (msqid64.msg_qbytes > ns->msg_ctlmnb && + if (msqid64->msg_qbytes > ns->msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) { err = -EPERM; goto out_unlock1; } ipc_lock_object(&msq->q_perm); - err = ipc_update_perm(&msqid64.msg_perm, ipcp); + err = ipc_update_perm(&msqid64->msg_perm, ipcp); if (err) goto out_unlock0; - msq->q_qbytes = msqid64.msg_qbytes; + msq->q_qbytes = msqid64->msg_qbytes; msq->q_ctime = get_seconds(); /* @@ -442,111 +436,89 @@ out_up: return err; } -static int msgctl_nolock(struct ipc_namespace *ns, int msqid, - int cmd, int version, void __user *buf) +static int msgctl_info(struct ipc_namespace *ns, int msqid, + int cmd, struct msginfo *msginfo) { int err; - struct msg_queue *msq; - - switch (cmd) { - case IPC_INFO: - case MSG_INFO: - { - struct msginfo msginfo; - int max_id; - - if (!buf) - return -EFAULT; + int max_id; - /* - * We must not return kernel stack data. - * due to padding, it's not enough - * to set all member fields. - */ - err = security_msg_queue_msgctl(NULL, cmd); - if (err) - return err; - - memset(&msginfo, 0, sizeof(msginfo)); - msginfo.msgmni = ns->msg_ctlmni; - msginfo.msgmax = ns->msg_ctlmax; - msginfo.msgmnb = ns->msg_ctlmnb; - msginfo.msgssz = MSGSSZ; - msginfo.msgseg = MSGSEG; - down_read(&msg_ids(ns).rwsem); - if (cmd == MSG_INFO) { - msginfo.msgpool = msg_ids(ns).in_use; - msginfo.msgmap = atomic_read(&ns->msg_hdrs); - msginfo.msgtql = atomic_read(&ns->msg_bytes); - } else { - msginfo.msgmap = MSGMAP; - msginfo.msgpool = MSGPOOL; - msginfo.msgtql = MSGTQL; - } - max_id = ipc_get_maxid(&msg_ids(ns)); - up_read(&msg_ids(ns).rwsem); - if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) - return -EFAULT; - return (max_id < 0) ? 0 : max_id; + /* + * We must not return kernel stack data. + * due to padding, it's not enough + * to set all member fields. + */ + err = security_msg_queue_msgctl(NULL, cmd); + if (err) + return err; + + memset(msginfo, 0, sizeof(*msginfo)); + msginfo->msgmni = ns->msg_ctlmni; + msginfo->msgmax = ns->msg_ctlmax; + msginfo->msgmnb = ns->msg_ctlmnb; + msginfo->msgssz = MSGSSZ; + msginfo->msgseg = MSGSEG; + down_read(&msg_ids(ns).rwsem); + if (cmd == MSG_INFO) { + msginfo->msgpool = msg_ids(ns).in_use; + msginfo->msgmap = atomic_read(&ns->msg_hdrs); + msginfo->msgtql = atomic_read(&ns->msg_bytes); + } else { + msginfo->msgmap = MSGMAP; + msginfo->msgpool = MSGPOOL; + msginfo->msgtql = MSGTQL; } + max_id = ipc_get_maxid(&msg_ids(ns)); + up_read(&msg_ids(ns).rwsem); + return (max_id < 0) ? 0 : max_id; +} - case MSG_STAT: - case IPC_STAT: - { - struct msqid64_ds tbuf; - int success_return; - - if (!buf) - return -EFAULT; - - memset(&tbuf, 0, sizeof(tbuf)); +static int msgctl_stat(struct ipc_namespace *ns, int msqid, + int cmd, struct msqid64_ds *p) +{ + int err; + struct msg_queue *msq; + int success_return; - rcu_read_lock(); - if (cmd == MSG_STAT) { - msq = msq_obtain_object(ns, msqid); - if (IS_ERR(msq)) { - err = PTR_ERR(msq); - goto out_unlock; - } - success_return = msq->q_perm.id; - } else { - msq = msq_obtain_object_check(ns, msqid); - if (IS_ERR(msq)) { - err = PTR_ERR(msq); - goto out_unlock; - } - success_return = 0; - } + memset(p, 0, sizeof(*p)); - err = -EACCES; - if (ipcperms(ns, &msq->q_perm, S_IRUGO)) + rcu_read_lock(); + if (cmd == MSG_STAT) { + msq = msq_obtain_object(ns, msqid); + if (IS_ERR(msq)) { + err = PTR_ERR(msq); goto out_unlock; - - err = security_msg_queue_msgctl(msq, cmd); - if (err) + } + success_return = msq->q_perm.id; + } else { + msq = msq_obtain_object_check(ns, msqid); + if (IS_ERR(msq)) { + err = PTR_ERR(msq); goto out_unlock; + } + success_return = 0; + } - kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm); - tbuf.msg_stime = msq->q_stime; - tbuf.msg_rtime = msq->q_rtime; - tbuf.msg_ctime = msq->q_ctime; - tbuf.msg_cbytes = msq->q_cbytes; - tbuf.msg_qnum = msq->q_qnum; - tbuf.msg_qbytes = msq->q_qbytes; - tbuf.msg_lspid = msq->q_lspid; - tbuf.msg_lrpid = msq->q_lrpid; - rcu_read_unlock(); + err = -EACCES; + if (ipcperms(ns, &msq->q_perm, S_IRUGO)) + goto out_unlock; - if (copy_msqid_to_user(buf, &tbuf, version)) - return -EFAULT; - return success_return; - } + err = security_msg_queue_msgctl(msq, cmd); + if (err) + goto out_unlock; + + kernel_to_ipc64_perm(&msq->q_perm, &p->msg_perm); + p->msg_stime = msq->q_stime; + p->msg_rtime = msq->q_rtime; + p->msg_ctime = msq->q_ctime; + p->msg_cbytes = msq->q_cbytes; + p->msg_qnum = msq->q_qnum; + p->msg_qbytes = msq->q_qbytes; + p->msg_lspid = msq->q_lspid; + p->msg_lrpid = msq->q_lrpid; + rcu_read_unlock(); - default: - return -EINVAL; - } + return success_return; - return err; out_unlock: rcu_read_unlock(); return err; @@ -556,6 +528,8 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) { int version; struct ipc_namespace *ns; + struct msqid64_ds msqid64; + int err; if (msqid < 0 || cmd < 0) return -EINVAL; @@ -565,13 +539,29 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) switch (cmd) { case IPC_INFO: - case MSG_INFO: + case MSG_INFO: { + struct msginfo msginfo; + err = msgctl_info(ns, msqid, cmd, &msginfo); + if (err < 0) + return err; + if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) + err = -EFAULT; + return err; + } case MSG_STAT: /* msqid is an index rather than a msg queue id */ case IPC_STAT: - return msgctl_nolock(ns, msqid, cmd, version, buf); + err = msgctl_stat(ns, msqid, cmd, &msqid64); + if (err < 0) + return err; + if (copy_msqid_to_user(buf, &msqid64, version)) + err = -EFAULT; + return err; case IPC_SET: + if (copy_msqid_from_user(&msqid64, buf, version)) + return -EFAULT; + /* fallthru */ case IPC_RMID: - return msgctl_down(ns, msqid, cmd, buf, version); + return msgctl_down(ns, msqid, cmd, &msqid64); default: return -EINVAL; } -- cgit v1.2.3 From 4693916846269d633a3664586650dbfac2c5562f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 9 Jul 2017 08:31:16 -0400 Subject: msgctl(): move compat to native Signed-off-by: Al Viro --- ipc/compat.c | 132 ---------------------------------------------------------- ipc/msg.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 132 deletions(-) (limited to 'ipc/msg.c') diff --git a/ipc/compat.c b/ipc/compat.c index fbfd6fb0a68d..c83099a3b265 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -50,22 +50,6 @@ struct compat_semid_ds { unsigned short sem_nsems; }; -struct compat_msqid_ds { - struct compat_ipc_perm msg_perm; - compat_uptr_t msg_first; - compat_uptr_t msg_last; - compat_time_t msg_stime; - compat_time_t msg_rtime; - compat_time_t msg_ctime; - compat_ulong_t msg_lcbytes; - compat_ulong_t msg_lqbytes; - unsigned short msg_cbytes; - unsigned short msg_qnum; - unsigned short msg_qbytes; - compat_ipc_pid_t msg_lspid; - compat_ipc_pid_t msg_lrpid; -}; - struct compat_ipc_kludge { compat_uptr_t msgp; compat_long_t msgtyp; @@ -391,122 +375,6 @@ COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp, msgflg, compat_do_msg_fill); } -static inline int get_compat_msqid64(struct msqid64_ds *m64, - struct compat_msqid64_ds __user *up64) -{ - int err; - - if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) - return -EFAULT; - err = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm); - err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes); - return err; -} - -static inline int get_compat_msqid(struct msqid64_ds *m, - struct compat_msqid_ds __user *up) -{ - int err; - - if (!access_ok(VERIFY_READ, up, sizeof(*up))) - return -EFAULT; - err = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm); - err |= __get_user(m->msg_qbytes, &up->msg_qbytes); - return err; -} - -static inline int put_compat_msqid64_ds(struct msqid64_ds *m64, - struct compat_msqid64_ds __user *up64) -{ - int err; - - if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) - return -EFAULT; - err = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm); - err |= __put_user(m64->msg_stime, &up64->msg_stime); - err |= __put_user(m64->msg_rtime, &up64->msg_rtime); - err |= __put_user(m64->msg_ctime, &up64->msg_ctime); - err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes); - err |= __put_user(m64->msg_qnum, &up64->msg_qnum); - err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes); - err |= __put_user(m64->msg_lspid, &up64->msg_lspid); - err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid); - return err; -} - -static inline int put_compat_msqid_ds(struct msqid64_ds *m, - struct compat_msqid_ds __user *up) -{ - int err; - - if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) - return -EFAULT; - err = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm); - err |= __put_user(m->msg_stime, &up->msg_stime); - err |= __put_user(m->msg_rtime, &up->msg_rtime); - err |= __put_user(m->msg_ctime, &up->msg_ctime); - err |= __put_user(m->msg_cbytes, &up->msg_cbytes); - err |= __put_user(m->msg_qnum, &up->msg_qnum); - err |= __put_user(m->msg_qbytes, &up->msg_qbytes); - err |= __put_user(m->msg_lspid, &up->msg_lspid); - err |= __put_user(m->msg_lrpid, &up->msg_lrpid); - return err; -} - -COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr) -{ - int err, err2; - struct msqid64_ds m64; - int version = __compat_ipc_parse_version(&second); - void __user *p; - - memset(&m64, 0, sizeof(m64)); - - switch (second & (~IPC_64)) { - case IPC_INFO: - case IPC_RMID: - case MSG_INFO: - err = sys_msgctl(first, second, uptr); - break; - - case IPC_SET: - if (version == IPC_64) - err = get_compat_msqid64(&m64, uptr); - else - err = get_compat_msqid(&m64, uptr); - - if (err) - break; - p = compat_alloc_user_space(sizeof(m64)); - if (copy_to_user(p, &m64, sizeof(m64))) - err = -EFAULT; - else - err = sys_msgctl(first, second, p); - break; - - case IPC_STAT: - case MSG_STAT: - p = compat_alloc_user_space(sizeof(m64)); - err = sys_msgctl(first, second, p); - if (err < 0) - break; - if (copy_from_user(&m64, p, sizeof(m64))) - err2 = -EFAULT; - else if (version == IPC_64) - err2 = put_compat_msqid64_ds(&m64, uptr); - else - err2 = put_compat_msqid_ds(&m64, uptr); - if (err2) - err = -EFAULT; - break; - - default: - err = -EINVAL; - break; - } - return err; -} - COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg) { unsigned long ret; diff --git a/ipc/msg.c b/ipc/msg.c index 322e7bf8b8d1..3400012e1ce8 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -567,6 +567,139 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) } } +#ifdef CONFIG_COMPAT + +struct compat_msqid_ds { + struct compat_ipc_perm msg_perm; + compat_uptr_t msg_first; + compat_uptr_t msg_last; + compat_time_t msg_stime; + compat_time_t msg_rtime; + compat_time_t msg_ctime; + compat_ulong_t msg_lcbytes; + compat_ulong_t msg_lqbytes; + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + compat_ipc_pid_t msg_lspid; + compat_ipc_pid_t msg_lrpid; +}; + +static int copy_compat_msqid_from_user(struct msqid64_ds *out, void __user *buf, + int version) +{ + memset(out, 0, sizeof(*out)); + if (version == IPC_64) { + struct compat_msqid64_ds *p = buf; + struct compat_ipc64_perm v; + if (copy_from_user(&v, &p->msg_perm, sizeof(v))) + return -EFAULT; + out->msg_perm.uid = v.uid; + out->msg_perm.gid = v.gid; + out->msg_perm.mode = v.mode; + if (get_user(out->msg_qbytes, &p->msg_qbytes)) + return -EFAULT; + } else { + struct compat_msqid_ds *p = buf; + struct compat_ipc_perm v; + if (copy_from_user(&v, &p->msg_perm, sizeof(v))) + return -EFAULT; + out->msg_perm.uid = v.uid; + out->msg_perm.gid = v.gid; + out->msg_perm.mode = v.mode; + if (get_user(out->msg_qbytes, &p->msg_qbytes)) + return -EFAULT; + } + return 0; +} + +static int copy_compat_msqid_to_user(void __user *buf, struct msqid64_ds *in, + int version) +{ + if (version == IPC_64) { + struct compat_msqid64_ds v; + memset(&v, 0, sizeof(v)); + v.msg_perm.key = in->msg_perm.key; + v.msg_perm.uid = in->msg_perm.uid; + v.msg_perm.gid = in->msg_perm.gid; + v.msg_perm.cuid = in->msg_perm.cuid; + v.msg_perm.cgid = in->msg_perm.cgid; + v.msg_perm.mode = in->msg_perm.mode; + v.msg_perm.seq = in->msg_perm.seq; + v.msg_stime = in->msg_stime; + v.msg_rtime = in->msg_rtime; + v.msg_ctime = in->msg_ctime; + v.msg_cbytes = in->msg_cbytes; + v.msg_qnum = in->msg_qnum; + v.msg_qbytes = in->msg_qbytes; + v.msg_lspid = in->msg_lspid; + v.msg_lrpid = in->msg_lrpid; + return copy_to_user(buf, &v, sizeof(v)); + } else { + struct compat_msqid_ds v; + memset(&v, 0, sizeof(v)); + v.msg_perm.key = in->msg_perm.key; + SET_UID(v.msg_perm.uid, in->msg_perm.uid); + SET_GID(v.msg_perm.gid, in->msg_perm.gid); + SET_UID(v.msg_perm.cuid, in->msg_perm.cuid); + SET_GID(v.msg_perm.cgid, in->msg_perm.cgid); + v.msg_perm.mode = in->msg_perm.mode; + v.msg_perm.seq = in->msg_perm.seq; + v.msg_stime = in->msg_stime; + v.msg_rtime = in->msg_rtime; + v.msg_ctime = in->msg_ctime; + v.msg_cbytes = in->msg_cbytes; + v.msg_qnum = in->msg_qnum; + v.msg_qbytes = in->msg_qbytes; + v.msg_lspid = in->msg_lspid; + v.msg_lrpid = in->msg_lrpid; + return copy_to_user(buf, &v, sizeof(v)); + } +} + +COMPAT_SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, void __user *, uptr) +{ + struct ipc_namespace *ns; + int err; + struct msqid64_ds msqid64; + int version = compat_ipc_parse_version(&cmd); + + ns = current->nsproxy->ipc_ns; + + if (msqid < 0 || cmd < 0) + return -EINVAL; + + switch (cmd & (~IPC_64)) { + case IPC_INFO: + case MSG_INFO: { + struct msginfo msginfo; + err = msgctl_info(ns, msqid, cmd, &msginfo); + if (err < 0) + return err; + if (copy_to_user(uptr, &msginfo, sizeof(struct msginfo))) + err = -EFAULT; + return err; + } + case IPC_STAT: + case MSG_STAT: + err = msgctl_stat(ns, msqid, cmd, &msqid64); + if (err < 0) + return err; + if (copy_compat_msqid_to_user(uptr, &msqid64, version)) + err = -EFAULT; + return err; + case IPC_SET: + if (copy_compat_msqid_from_user(&msqid64, uptr, version)) + return -EFAULT; + /* fallthru */ + case IPC_RMID: + return msgctl_down(ns, msqid, cmd, &msqid64); + default: + return -EINVAL; + } +} +#endif + static int testmsg(struct msg_msg *msg, long type, int mode) { switch (mode) { -- cgit v1.2.3 From 28327fae62b011216026b66299882c53b95b4500 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 9 Jul 2017 10:10:32 -0400 Subject: ipc: make use of compat ipc_perm helpers Signed-off-by: Al Viro --- ipc/msg.c | 28 ++++------------------------ ipc/shm.c | 30 ++++-------------------------- 2 files changed, 8 insertions(+), 50 deletions(-) (limited to 'ipc/msg.c') diff --git a/ipc/msg.c b/ipc/msg.c index 3400012e1ce8..94690fb53f66 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -591,22 +591,14 @@ static int copy_compat_msqid_from_user(struct msqid64_ds *out, void __user *buf, memset(out, 0, sizeof(*out)); if (version == IPC_64) { struct compat_msqid64_ds *p = buf; - struct compat_ipc64_perm v; - if (copy_from_user(&v, &p->msg_perm, sizeof(v))) + if (get_compat_ipc64_perm(&out->msg_perm, &p->msg_perm)) return -EFAULT; - out->msg_perm.uid = v.uid; - out->msg_perm.gid = v.gid; - out->msg_perm.mode = v.mode; if (get_user(out->msg_qbytes, &p->msg_qbytes)) return -EFAULT; } else { struct compat_msqid_ds *p = buf; - struct compat_ipc_perm v; - if (copy_from_user(&v, &p->msg_perm, sizeof(v))) + if (get_compat_ipc_perm(&out->msg_perm, &p->msg_perm)) return -EFAULT; - out->msg_perm.uid = v.uid; - out->msg_perm.gid = v.gid; - out->msg_perm.mode = v.mode; if (get_user(out->msg_qbytes, &p->msg_qbytes)) return -EFAULT; } @@ -619,13 +611,7 @@ static int copy_compat_msqid_to_user(void __user *buf, struct msqid64_ds *in, if (version == IPC_64) { struct compat_msqid64_ds v; memset(&v, 0, sizeof(v)); - v.msg_perm.key = in->msg_perm.key; - v.msg_perm.uid = in->msg_perm.uid; - v.msg_perm.gid = in->msg_perm.gid; - v.msg_perm.cuid = in->msg_perm.cuid; - v.msg_perm.cgid = in->msg_perm.cgid; - v.msg_perm.mode = in->msg_perm.mode; - v.msg_perm.seq = in->msg_perm.seq; + to_compat_ipc64_perm(&v.msg_perm, &in->msg_perm); v.msg_stime = in->msg_stime; v.msg_rtime = in->msg_rtime; v.msg_ctime = in->msg_ctime; @@ -638,13 +624,7 @@ static int copy_compat_msqid_to_user(void __user *buf, struct msqid64_ds *in, } else { struct compat_msqid_ds v; memset(&v, 0, sizeof(v)); - v.msg_perm.key = in->msg_perm.key; - SET_UID(v.msg_perm.uid, in->msg_perm.uid); - SET_GID(v.msg_perm.gid, in->msg_perm.gid); - SET_UID(v.msg_perm.cuid, in->msg_perm.cuid); - SET_GID(v.msg_perm.cgid, in->msg_perm.cgid); - v.msg_perm.mode = in->msg_perm.mode; - v.msg_perm.seq = in->msg_perm.seq; + to_compat_ipc_perm(&v.msg_perm, &in->msg_perm); v.msg_stime = in->msg_stime; v.msg_rtime = in->msg_rtime; v.msg_ctime = in->msg_ctime; diff --git a/ipc/shm.c b/ipc/shm.c index 87334ee3acb3..2e31545035a6 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1161,13 +1161,7 @@ static int copy_compat_shmid_to_user(void __user *buf, struct shmid64_ds *in, if (version == IPC_64) { struct compat_shmid64_ds v; memset(&v, 0, sizeof(v)); - v.shm_perm.key = in->shm_perm.key; - v.shm_perm.uid = in->shm_perm.uid; - v.shm_perm.gid = in->shm_perm.gid; - v.shm_perm.cuid = in->shm_perm.cuid; - v.shm_perm.cgid = in->shm_perm.cgid; - v.shm_perm.mode = in->shm_perm.mode; - v.shm_perm.seq = in->shm_perm.seq; + to_compat_ipc64_perm(&v.shm_perm, &in->shm_perm); v.shm_atime = in->shm_atime; v.shm_dtime = in->shm_dtime; v.shm_ctime = in->shm_ctime; @@ -1179,13 +1173,8 @@ static int copy_compat_shmid_to_user(void __user *buf, struct shmid64_ds *in, } else { struct compat_shmid_ds v; memset(&v, 0, sizeof(v)); + to_compat_ipc_perm(&v.shm_perm, &in->shm_perm); v.shm_perm.key = in->shm_perm.key; - SET_UID(v.shm_perm.uid, in->shm_perm.uid); - SET_GID(v.shm_perm.gid, in->shm_perm.gid); - SET_UID(v.shm_perm.cuid, in->shm_perm.cuid); - SET_GID(v.shm_perm.cgid, in->shm_perm.cgid); - v.shm_perm.mode = in->shm_perm.mode; - v.shm_perm.seq = in->shm_perm.seq; v.shm_atime = in->shm_atime; v.shm_dtime = in->shm_dtime; v.shm_ctime = in->shm_ctime; @@ -1203,22 +1192,11 @@ static int copy_compat_shmid_from_user(struct shmid64_ds *out, void __user *buf, memset(out, 0, sizeof(*out)); if (version == IPC_64) { struct compat_shmid64_ds *p = buf; - struct compat_ipc64_perm v; - if (copy_from_user(&v, &p->shm_perm, sizeof(v))) - return -EFAULT; - out->shm_perm.uid = v.uid; - out->shm_perm.gid = v.gid; - out->shm_perm.mode = v.mode; + return get_compat_ipc64_perm(&out->shm_perm, &p->shm_perm); } else { struct compat_shmid_ds *p = buf; - struct compat_ipc_perm v; - if (copy_from_user(&v, &p->shm_perm, sizeof(v))) - return -EFAULT; - out->shm_perm.uid = v.uid; - out->shm_perm.gid = v.gid; - out->shm_perm.mode = v.mode; + return get_compat_ipc_perm(&out->shm_perm, &p->shm_perm); } - return 0; } COMPAT_SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, void __user *, uptr) -- cgit v1.2.3 From 9b1404c24a357332cb2a6df7c4337e943a4545fd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 9 Jul 2017 10:34:35 -0400 Subject: msgrcv(2), msgsnd(2): move compat to native Signed-off-by: Al Viro --- include/linux/msg.h | 8 -------- ipc/compat.c | 37 ------------------------------------- ipc/msg.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 43 insertions(+), 47 deletions(-) (limited to 'ipc/msg.c') diff --git a/include/linux/msg.h b/include/linux/msg.h index f3f302f9c197..4e5ec3cbf464 100644 --- a/include/linux/msg.h +++ b/include/linux/msg.h @@ -31,12 +31,4 @@ struct msg_queue { struct list_head q_senders; }; -/* Helper routines for sys_msgsnd and sys_msgrcv */ -extern long do_msgsnd(int msqid, long mtype, void __user *mtext, - size_t msgsz, int msgflg); -extern long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, - int msgflg, - long (*msg_fill)(void __user *, struct msg_msg *, - size_t)); - #endif /* _LINUX_MSG_H */ diff --git a/ipc/compat.c b/ipc/compat.c index 00c2e3beccc8..0586687c3e31 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -34,11 +34,6 @@ #include "util.h" -struct compat_msgbuf { - compat_long_t mtype; - char mtext[1]; -}; - int get_compat_ipc64_perm(struct ipc64_perm *to, struct compat_ipc64_perm __user *from) { @@ -85,38 +80,6 @@ void to_compat_ipc_perm(struct compat_ipc_perm *to, struct ipc64_perm *from) to->seq = from->seq; } -static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) -{ - struct compat_msgbuf __user *msgp = dest; - size_t msgsz; - - if (put_user(msg->m_type, &msgp->mtype)) - return -EFAULT; - - msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz; - if (store_msg(msgp->mtext, msg, msgsz)) - return -EFAULT; - return msgsz; -} - -COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp, - compat_ssize_t, msgsz, int, msgflg) -{ - struct compat_msgbuf __user *up = compat_ptr(msgp); - compat_long_t mtype; - - if (get_user(mtype, &up->mtype)) - return -EFAULT; - return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg); -} - -COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp, - compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg) -{ - return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp, - msgflg, compat_do_msg_fill); -} - #ifndef COMPAT_SHMLBA #define COMPAT_SHMLBA SHMLBA #endif diff --git a/ipc/msg.c b/ipc/msg.c index 94690fb53f66..855da19c765a 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -730,7 +730,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg, return 0; } -long do_msgsnd(int msqid, long mtype, void __user *mtext, +static long do_msgsnd(int msqid, long mtype, void __user *mtext, size_t msgsz, int msgflg) { struct msg_queue *msq; @@ -853,6 +853,25 @@ SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg); } +#ifdef CONFIG_COMPAT + +struct compat_msgbuf { + compat_long_t mtype; + char mtext[1]; +}; + +COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp, + compat_ssize_t, msgsz, int, msgflg) +{ + struct compat_msgbuf __user *up = compat_ptr(msgp); + compat_long_t mtype; + + if (get_user(mtype, &up->mtype)) + return -EFAULT; + return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg); +} +#endif + static inline int convert_mode(long *msgtyp, int msgflg) { if (msgflg & MSG_COPY) @@ -949,7 +968,7 @@ static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode) return found ?: ERR_PTR(-EAGAIN); } -long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg, +static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg, long (*msg_handler)(void __user *, struct msg_msg *, size_t)) { int mode; @@ -1113,6 +1132,28 @@ SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill); } +#ifdef CONFIG_COMPAT +static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) +{ + struct compat_msgbuf __user *msgp = dest; + size_t msgsz; + + if (put_user(msg->m_type, &msgp->mtype)) + return -EFAULT; + + msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz; + if (store_msg(msgp->mtext, msg, msgsz)) + return -EFAULT; + return msgsz; +} + +COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp, + compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg) +{ + return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp, + msgflg, compat_do_msg_fill); +} +#endif void msg_init_ns(struct ipc_namespace *ns) { -- cgit v1.2.3 From 50578ea97a2a352c109bd1657e667b212faf2cbb Mon Sep 17 00:00:00 2001 From: Deepa Dinamani Date: Wed, 2 Aug 2017 19:51:12 -0700 Subject: ipc: msg: Make msg_queue timestamps y2038 safe time_t is not y2038 safe. Replace all uses of time_t by y2038 safe time64_t. Similarly, replace the calls to get_seconds() with y2038 safe ktime_get_real_seconds(). Note that this preserves fast access on 64 bit systems, but 32 bit systems need sequence counters. The syscall interfaces themselves are not changed as part of the patch. They will be part of a different series. Signed-off-by: Deepa Dinamani Reviewed-by: Arnd Bergmann Signed-off-by: Al Viro --- include/linux/msg.h | 7 ++++--- ipc/msg.c | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'ipc/msg.c') diff --git a/include/linux/msg.h b/include/linux/msg.h index 4e5ec3cbf464..05115342daa3 100644 --- a/include/linux/msg.h +++ b/include/linux/msg.h @@ -2,6 +2,7 @@ #define _LINUX_MSG_H #include +#include #include /* one msg_msg structure for each message */ @@ -17,9 +18,9 @@ struct msg_msg { /* one msq_queue structure for each present queue on the system */ struct msg_queue { struct kern_ipc_perm q_perm; - time_t q_stime; /* last msgsnd time */ - time_t q_rtime; /* last msgrcv time */ - time_t q_ctime; /* last change time */ + time64_t q_stime; /* last msgsnd time */ + time64_t q_rtime; /* last msgrcv time */ + time64_t q_ctime; /* last change time */ unsigned long q_cbytes; /* current number of bytes on queue */ unsigned long q_qnum; /* number of messages in queue */ unsigned long q_qbytes; /* max number of bytes on queue */ diff --git a/ipc/msg.c b/ipc/msg.c index 855da19c765a..0e7ccfc0700b 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -133,7 +133,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params) } msq->q_stime = msq->q_rtime = 0; - msq->q_ctime = get_seconds(); + msq->q_ctime = ktime_get_real_seconds(); msq->q_cbytes = msq->q_qnum = 0; msq->q_qbytes = ns->msg_ctlmnb; msq->q_lspid = msq->q_lrpid = 0; @@ -406,7 +406,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, msq->q_qbytes = msqid64->msg_qbytes; - msq->q_ctime = get_seconds(); + msq->q_ctime = ktime_get_real_seconds(); /* * Sleeping receivers might be excluded by * stricter permissions. @@ -1181,7 +1181,7 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it) struct msg_queue *msq = it; seq_printf(s, - "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n", + "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10llu %10llu %10llu\n", msq->q_perm.key, msq->q_perm.id, msq->q_perm.mode, -- cgit v1.2.3