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,