From f4b6eb045fa7cefa3062479048dea9f5d397f276 Mon Sep 17 00:00:00 2001 From: Maxim Sobolev Date: Wed, 26 Jan 2005 00:46:36 +0000 Subject: [PATCH] Split out kernel side of msgctl(2) into two parts: the first that pops data from the userland and pushes results back and the second which does actual processing. Use the latter to eliminate stackgap in the linux wrapper of that syscall. MFC after: 2 weeks --- sys/compat/linux/linux_ipc.c | 27 +++++++---------- sys/kern/sysv_msg.c | 58 +++++++++++++++++++++++------------- sys/sys/syscallsubr.h | 3 ++ 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c index 662669d4853..8fc338786d2 100644 --- a/sys/compat/linux/linux_ipc.c +++ b/sys/compat/linux/linux_ipc.c @@ -634,33 +634,26 @@ linux_msgget(struct thread *td, struct linux_msgget_args *args) int linux_msgctl(struct thread *td, struct linux_msgctl_args *args) { - struct msgctl_args /* { - int msqid; - int cmd; - struct msqid_ds *buf; - } */ bsd_args; - int error; + int error, bsd_cmd; struct l_msqid_ds linux_msqid; - caddr_t sg = stackgap_init(); + struct msqid_ds bsd_msqid; + struct msqid_ds *bsd_msqptr; error = linux_msqid_pullup(args->cmd & LINUX_IPC_64, &linux_msqid, (caddr_t)PTRIN(args->buf)); if (error != 0) return (error); - bsd_args.buf = (struct msqid_ds*)stackgap_alloc(&sg, - sizeof(struct l_msqid_ds)); - bsd_args.msqid = args->msqid; - bsd_args.cmd = args->cmd & ~LINUX_IPC_64; - if (bsd_args.cmd == LINUX_IPC_SET) - linux_to_bsd_msqid_ds(&linux_msqid, bsd_args.buf); + bsd_cmd = args->cmd & ~LINUX_IPC_64; + if (bsd_cmd == LINUX_IPC_SET) + linux_to_bsd_msqid_ds(&linux_msqid, &bsd_msqid); - error = msgctl(td, &bsd_args); + error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid, &bsd_msqptr); if (error != 0) - if (bsd_args.cmd != LINUX_IPC_RMID || error != EINVAL) + if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL) return (error); - if (bsd_args.cmd == LINUX_IPC_STAT) { - bsd_to_linux_msqid_ds(bsd_args.buf, &linux_msqid); + if (bsd_cmd == LINUX_IPC_STAT) { + bsd_to_linux_msqid_ds(bsd_msqptr, &linux_msqid); return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64, &linux_msqid, (caddr_t)PTRIN(args->buf))); } diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c index 90bb5d6cc8f..efd630e027c 100644 --- a/sys/kern/sysv_msg.c +++ b/sys/kern/sysv_msg.c @@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -395,27 +396,43 @@ msgctl(td, uap) { int msqid = uap->msqid; int cmd = uap->cmd; - struct msqid_ds *user_msqptr = uap->buf; - int rval, error; struct msqid_ds msqbuf; + struct msqid_ds *msqptr; + int error; + + DPRINTF(("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, uap->buf)); + if (cmd == IPC_SET && + (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0) + return (error); + error = kern_msgctl(td, msqid, cmd, &msqbuf, &msqptr); + if (cmd == IPC_STAT && error == 0) + error = copyout(msqptr, uap->buf, sizeof(struct msqid_ds)); + return (error); +} + +int +kern_msgctl(td, msqid, cmd, msqbuf, msqptr) + struct thread *td; + int msqid; + int cmd; + struct msqid_ds *msqbuf; + struct msqid_ds **msqptr; +{ + int rval, error, msqix; register struct msqid_kernel *msqkptr; - DPRINTF(("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr)); if (!jail_sysvipc_allowed && jailed(td->td_ucred)) return (ENOSYS); - msqid = IPCID_TO_IX(msqid); + msqix = IPCID_TO_IX(msqid); - if (msqid < 0 || msqid >= msginfo.msgmni) { - DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid, + if (msqix < 0 || msqix >= msginfo.msgmni) { + DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix, msginfo.msgmni)); return (EINVAL); } - if (cmd == IPC_SET && - (error = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0) - return (error); - msqkptr = &msqids[msqid]; + msqkptr = &msqids[msqix]; mtx_lock(&msq_mtx); if (msqkptr->u.msg_qbytes == 0) { @@ -423,7 +440,7 @@ msgctl(td, uap) error = EINVAL; goto done2; } - if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) { + if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) { DPRINTF(("wrong sequence number\n")); error = EINVAL; goto done2; @@ -500,26 +517,26 @@ msgctl(td, uap) case IPC_SET: if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M))) goto done2; - if (msqbuf.msg_qbytes > msqkptr->u.msg_qbytes) { + if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) { error = suser(td); if (error) goto done2; } - if (msqbuf.msg_qbytes > msginfo.msgmnb) { + if (msqbuf->msg_qbytes > msginfo.msgmnb) { DPRINTF(("can't increase msg_qbytes beyond %d" "(truncating)\n", msginfo.msgmnb)); - msqbuf.msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */ + msqbuf->msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */ } - if (msqbuf.msg_qbytes == 0) { + if (msqbuf->msg_qbytes == 0) { DPRINTF(("can't reduce msg_qbytes to 0\n")); error = EINVAL; /* non-standard errno! */ goto done2; } - msqkptr->u.msg_perm.uid = msqbuf.msg_perm.uid; /* change the owner */ - msqkptr->u.msg_perm.gid = msqbuf.msg_perm.gid; /* change the owner */ + msqkptr->u.msg_perm.uid = msqbuf->msg_perm.uid; /* change the owner */ + msqkptr->u.msg_perm.gid = msqbuf->msg_perm.gid; /* change the owner */ msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) | - (msqbuf.msg_perm.mode & 0777); - msqkptr->u.msg_qbytes = msqbuf.msg_qbytes; + (msqbuf->msg_perm.mode & 0777); + msqkptr->u.msg_qbytes = msqbuf->msg_qbytes; msqkptr->u.msg_ctime = time_second; break; @@ -528,6 +545,7 @@ msgctl(td, uap) DPRINTF(("requester doesn't have read access\n")); goto done2; } + *msqptr = &(msqkptr->u); break; default: @@ -540,8 +558,6 @@ msgctl(td, uap) td->td_retval[0] = rval; done2: mtx_unlock(&msq_mtx); - if (cmd == IPC_STAT && error == 0) - error = copyout(&(msqkptr->u), user_msqptr, sizeof(struct msqid_ds)); return(error); } diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index 4b9447dc2db..d161c7a0642 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -39,6 +39,7 @@ struct rlimit; struct rusage; struct sockaddr; struct itimerval; +struct msqid_ds; int kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg, u_int buflen); @@ -72,6 +73,8 @@ int kern_mkfifo(struct thread *td, char *path, enum uio_seg pathseg, int mode); int kern_mknod(struct thread *td, char *path, enum uio_seg pathseg, int mode, int dev); +int kern_msgctl(struct thread *, int, int, struct msqid_ds *, + struct msqid_ds **); int kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt); int kern_open(struct thread *td, char *path, enum uio_seg pathseg,