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:
parent
372ef8405c
commit
f4b6eb045f
@ -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)));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user