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
This commit is contained in:
Maxim Sobolev 2005-01-26 00:46:36 +00:00
parent 372ef8405c
commit f4b6eb045f
3 changed files with 50 additions and 38 deletions

View File

@ -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)));
}

View File

@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/msg.h>
#include <sys/syscall.h>
#include <sys/syscallsubr.h>
#include <sys/sysent.h>
#include <sys/sysctl.h>
#include <sys/malloc.h>
@ -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);
}

View File

@ -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,