diff options
author | jhb <jhb@FreeBSD.org> | 2009-06-24 21:10:52 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2009-06-24 21:10:52 +0000 |
commit | 6f52fe78fb1fc421bc6abb38286a4483aac9cdc0 (patch) | |
tree | 9bcf2215ae277f261cc7bf33f2dde8db38fe41c4 /sys/kern | |
parent | ce189363a0ec4e65f27076207a88142a8554bfbb (diff) | |
download | FreeBSD-src-6f52fe78fb1fc421bc6abb38286a4483aac9cdc0.zip FreeBSD-src-6f52fe78fb1fc421bc6abb38286a4483aac9cdc0.tar.gz |
Change the ABI of some of the structures used by the SYSV IPC API:
- The uid/cuid members of struct ipc_perm are now uid_t instead of unsigned
short.
- The gid/cgid members of struct ipc_perm are now gid_t instead of unsigned
short.
- The mode member of struct ipc_perm is now mode_t instead of unsigned short
(this is merely a style bug).
- The rather dubious padding fields for ABI compat with SV/I386 have been
removed from struct msqid_ds and struct semid_ds.
- The shm_segsz member of struct shmid_ds is now a size_t instead of an
int. This removes the need for the shm_bsegsz member in struct
shmid_kernel and should allow for complete support of SYSV SHM regions
>= 2GB.
- The shm_nattch member of struct shmid_ds is now an int instead of a
short.
- The shm_internal member of struct shmid_ds is now gone. The internal
VM object pointer for SHM regions has been moved into struct
shmid_kernel.
- The existing __semctl(), msgctl(), and shmctl() system call entries are
now marked COMPAT7 and new versions of those system calls which support
the new ABI are now present.
- The new system calls are assigned to the FBSD-1.1 version in libc. The
FBSD-1.0 symbols in libc now refer to the old COMPAT7 system calls.
- A simplistic framework for tagging system calls with compatibility
symbol versions has been added to libc. Version tags are added to
system calls by adding an appropriate __sym_compat() entry to
src/lib/libc/incldue/compat.h. [1]
PR: kern/16195 kern/113218 bin/129855
Reviewed by: arch@, rwatson
Discussed with: kan, kib [1]
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/syscalls.master | 18 | ||||
-rw-r--r-- | sys/kern/sysv_ipc.c | 31 | ||||
-rw-r--r-- | sys/kern/sysv_msg.c | 63 | ||||
-rw-r--r-- | sys/kern/sysv_sem.c | 87 | ||||
-rw-r--r-- | sys/kern/sysv_shm.c | 111 |
5 files changed, 290 insertions, 20 deletions
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 204e7da..940f13d 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -417,15 +417,15 @@ ; ; The following were introduced with NetBSD/4.4Lite-2 -220 AUE_SEMCTL NOSTD { int __semctl(int semid, int semnum, \ - int cmd, union semun *arg); } +220 AUE_SEMCTL COMPAT7|NOSTD { int __semctl(int semid, int semnum, \ + int cmd, union semun_old *arg); } 221 AUE_SEMGET NOSTD { int semget(key_t key, int nsems, \ int semflg); } 222 AUE_SEMOP NOSTD { int semop(int semid, struct sembuf *sops, \ size_t nsops); } 223 AUE_NULL UNIMPL semconfig -224 AUE_MSGCTL NOSTD { int msgctl(int msqid, int cmd, \ - struct msqid_ds *buf); } +224 AUE_MSGCTL COMPAT7|NOSTD { int msgctl(int msqid, int cmd, \ + struct msqid_ds_old *buf); } 225 AUE_MSGGET NOSTD { int msgget(key_t key, int msgflg); } 226 AUE_MSGSND NOSTD { int msgsnd(int msqid, const void *msgp, \ size_t msgsz, int msgflg); } @@ -433,8 +433,8 @@ size_t msgsz, long msgtyp, int msgflg); } 228 AUE_SHMAT NOSTD { int shmat(int shmid, const void *shmaddr, \ int shmflg); } -229 AUE_SHMCTL NOSTD { int shmctl(int shmid, int cmd, \ - struct shmid_ds *buf); } +229 AUE_SHMCTL COMPAT7|NOSTD { int shmctl(int shmid, int cmd, \ + struct shmid_ds_old *buf); } 230 AUE_SHMDT NOSTD { int shmdt(const void *shmaddr); } 231 AUE_SHMGET NOSTD { int shmget(key_t key, size_t size, \ int shmflg); } @@ -904,5 +904,11 @@ unsigned int iovcnt, int flags); } 508 AUE_NULL STD { int jail_remove(int jid); } 509 AUE_CLOSEFROM STD { int closefrom(int lowfd); } +510 AUE_SEMCTL NOSTD { int __semctl(int semid, int semnum, \ + int cmd, union semun *arg); } +511 AUE_MSGCTL NOSTD { int msgctl(int msqid, int cmd, \ + struct msqid_ds *buf); } +512 AUE_SHMCTL NOSTD { int shmctl(int shmid, int cmd, \ + struct shmid_ds *buf); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master diff --git a/sys/kern/sysv_ipc.c b/sys/kern/sysv_ipc.c index 0cbb4bb..d33fdb0 100644 --- a/sys/kern/sysv_ipc.c +++ b/sys/kern/sysv_ipc.c @@ -36,6 +36,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_compat.h" #include "opt_sysvipc.h" #include <sys/param.h> @@ -147,3 +148,33 @@ ipcperm(struct thread *td, struct ipc_perm *perm, int acc_mode) else return (EACCES); } + +#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ + defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) +void +ipcperm_old2new(struct ipc_perm_old *old, struct ipc_perm *new) +{ + + new->cuid = old->cuid; + new->cgid = old->cgid; + new->uid = old->uid; + new->gid = old->gid; + new->mode = old->mode; + new->seq = old->seq; + new->key = old->key; +} + +void +ipcperm_new2old(struct ipc_perm *new, struct ipc_perm_old *old) +{ + + /* XXX: How to handle ID's > USHORT_MAX? */ + old->cuid = new->cuid; + old->cgid = new->cgid; + old->uid = new->uid; + old->gid = new->gid; + old->mode = new->mode; + old->seq = new->seq; + old->key = new->key; +} +#endif diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c index e2f0c5d..c7c67d4 100644 --- a/sys/kern/sysv_msg.c +++ b/sys/kern/sysv_msg.c @@ -1260,10 +1260,11 @@ SYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLFLAG_RD, #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) SYSCALL_MODULE_HELPER(msgsys); +SYSCALL_MODULE_HELPER(freebsd7_msgctl); /* XXX casting to (sy_call_t *) is bogus, as usual. */ static sy_call_t *msgcalls[] = { - (sy_call_t *)msgctl, (sy_call_t *)msgget, + (sy_call_t *)freebsd7_msgctl, (sy_call_t *)msgget, (sy_call_t *)msgsnd, (sy_call_t *)msgrcv }; @@ -1293,5 +1294,65 @@ msgsys(td, uap) error = (*msgcalls[uap->which])(td, &uap->a2); return (error); } + +#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) + +#ifndef _SYS_SYSPROTO_H_ +struct freebsd7_msgctl_args { + int msqid; + int cmd; + struct msqid_ds_old *buf; +}; +#endif +int +freebsd7_msgctl(td, uap) + struct thread *td; + struct freebsd7_msgctl_args *uap; +{ + struct msqid_ds_old msqold; + struct msqid_ds msqbuf; + int error; + + DPRINTF(("call to freebsd7_msgctl(%d, %d, %p)\n", uap->msqid, uap->cmd, + uap->buf)); + if (uap->cmd == IPC_SET) { + error = copyin(uap->buf, &msqold, sizeof(msqold)); + if (error) + return (error); + ipcperm_old2new(&msqold.msg_perm, &msqbuf.msg_perm); + CP(msqold, msqbuf, msg_first); + CP(msqold, msqbuf, msg_last); + CP(msqold, msqbuf, msg_cbytes); + CP(msqold, msqbuf, msg_qnum); + CP(msqold, msqbuf, msg_qbytes); + CP(msqold, msqbuf, msg_lspid); + CP(msqold, msqbuf, msg_lrpid); + CP(msqold, msqbuf, msg_stime); + CP(msqold, msqbuf, msg_rtime); + CP(msqold, msqbuf, msg_ctime); + } + error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf); + if (error) + return (error); + if (uap->cmd == IPC_STAT) { + bzero(&msqold, sizeof(msqold)); + ipcperm_new2old(&msqbuf.msg_perm, &msqold.msg_perm); + CP(msqbuf, msqold, msg_first); + CP(msqbuf, msqold, msg_last); + CP(msqbuf, msqold, msg_cbytes); + CP(msqbuf, msqold, msg_qnum); + CP(msqbuf, msqold, msg_qbytes); + CP(msqbuf, msqold, msg_lspid); + CP(msqbuf, msqold, msg_lrpid); + CP(msqbuf, msqold, msg_stime); + CP(msqbuf, msqold, msg_rtime); + CP(msqbuf, msqold, msg_ctime); + error = copyout(&msqold, uap->buf, sizeof(struct msqid_ds_old)); + } + return (error); +} + +#undef CP + #endif /* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 || COMPAT_FREEBSD7 */ diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c index 719295d..2f2b528 100644 --- a/sys/kern/sysv_sem.c +++ b/sys/kern/sysv_sem.c @@ -1317,10 +1317,11 @@ sysctl_sema(SYSCTL_HANDLER_ARGS) #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) SYSCALL_MODULE_HELPER(semsys); +SYSCALL_MODULE_HELPER(freebsd7___semctl); /* XXX casting to (sy_call_t *) is bogus, as usual. */ static sy_call_t *semcalls[] = { - (sy_call_t *)__semctl, (sy_call_t *)semget, + (sy_call_t *)freebsd7___semctl, (sy_call_t *)semget, (sy_call_t *)semop }; @@ -1349,5 +1350,89 @@ semsys(td, uap) error = (*semcalls[uap->which])(td, &uap->a2); return (error); } + +#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) + +#ifndef _SYS_SYSPROTO_H_ +struct freebsd7___semctl_args { + int semid; + int semnum; + int cmd; + union semun_old *arg; +}; +#endif +int +freebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) +{ + struct semid_ds_old dsold; + struct semid_ds dsbuf; + union semun_old arg; + union semun semun; + register_t rval; + int error; + + switch (uap->cmd) { + case SEM_STAT: + case IPC_SET: + case IPC_STAT: + case GETALL: + case SETVAL: + case SETALL: + error = copyin(uap->arg, &arg, sizeof(arg)); + if (error) + return (error); + break; + } + + switch (uap->cmd) { + case SEM_STAT: + case IPC_STAT: + semun.buf = &dsbuf; + break; + case IPC_SET: + error = copyin(arg.buf, &dsold, sizeof(dsold)); + if (error) + return (error); + ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); + CP(dsold, dsbuf, sem_base); + CP(dsold, dsbuf, sem_nsems); + CP(dsold, dsbuf, sem_otime); + CP(dsold, dsbuf, sem_ctime); + semun.buf = &dsbuf; + break; + case GETALL: + case SETALL: + semun.array = arg.array; + break; + case SETVAL: + semun.val = arg.val; + break; + } + + error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, + &rval); + if (error) + return (error); + + switch (uap->cmd) { + case SEM_STAT: + case IPC_STAT: + bzero(&dsold, sizeof(dsold)); + ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); + CP(dsbuf, dsold, sem_base); + CP(dsbuf, dsold, sem_nsems); + CP(dsbuf, dsold, sem_otime); + CP(dsbuf, dsold, sem_ctime); + error = copyout(&dsold, arg.buf, sizeof(dsold)); + break; + } + + if (error == 0) + td->td_retval[0] = rval; + return (error); +} + +#undef CP + #endif /* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 || COMPAT_FREEBSD7 */ diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c index 2ea9830..bfcbebf 100644 --- a/sys/kern/sysv_shm.c +++ b/sys/kern/sysv_shm.c @@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/limits.h> #include <sys/lock.h> #include <sys/sysctl.h> #include <sys/shm.h> @@ -234,9 +235,9 @@ shm_deallocate_segment(shmseg) GIANT_REQUIRED; - vm_object_deallocate(shmseg->u.shm_internal); - shmseg->u.shm_internal = NULL; - size = round_page(shmseg->shm_bsegsz); + vm_object_deallocate(shmseg->object); + shmseg->object = NULL; + size = round_page(shmseg->u.shm_segsz); shm_committed -= btoc(size); shm_nused--; shmseg->u.shm_perm.mode = SHMSEG_FREE; @@ -256,7 +257,7 @@ shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s) segnum = IPCID_TO_IX(shmmap_s->shmid); shmseg = &shmsegs[segnum]; - size = round_page(shmseg->shm_bsegsz); + size = round_page(shmseg->u.shm_segsz); result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size); if (result != KERN_SUCCESS) return (EINVAL); @@ -376,7 +377,7 @@ kern_shmat(td, shmid, shmaddr, shmflg) error = EMFILE; goto done2; } - size = round_page(shmseg->shm_bsegsz); + size = round_page(shmseg->u.shm_segsz); prot = VM_PROT_READ; if ((shmflg & SHM_RDONLY) == 0) prot |= VM_PROT_WRITE; @@ -402,12 +403,12 @@ kern_shmat(td, shmid, shmaddr, shmflg) PROC_UNLOCK(p); } - vm_object_reference(shmseg->u.shm_internal); - rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->u.shm_internal, + vm_object_reference(shmseg->object); + rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->object, 0, &attach_va, size, (flags & MAP_FIXED) ? VMFS_NO_SPACE : VMFS_ANY_SPACE, prot, prot, 0); if (rv != KERN_SUCCESS) { - vm_object_deallocate(shmseg->u.shm_internal); + vm_object_deallocate(shmseg->object); error = ENOMEM; goto done2; } @@ -624,7 +625,7 @@ shmget_existing(td, uap, mode, segnum) if (error != 0) return (error); #endif - if (uap->size != 0 && uap->size > shmseg->shm_bsegsz) + if (uap->size != 0 && uap->size > shmseg->u.shm_segsz) return (EINVAL); td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm); return (0); @@ -686,13 +687,12 @@ shmget_allocate_segment(td, uap, mode) vm_object_set_flag(shm_object, OBJ_NOSPLIT); VM_OBJECT_UNLOCK(shm_object); - shmseg->u.shm_internal = shm_object; + shmseg->object = shm_object; shmseg->u.shm_perm.cuid = shmseg->u.shm_perm.uid = cred->cr_uid; shmseg->u.shm_perm.cgid = shmseg->u.shm_perm.gid = cred->cr_gid; shmseg->u.shm_perm.mode = (shmseg->u.shm_perm.mode & SHMSEG_WANTED) | (mode & ACCESSPERMS) | SHMSEG_ALLOCATED; shmseg->u.shm_segsz = uap->size; - shmseg->shm_bsegsz = uap->size; shmseg->u.shm_cpid = td->td_proc->p_pid; shmseg->u.shm_lpid = shmseg->u.shm_nattch = 0; shmseg->u.shm_atime = shmseg->u.shm_dtime = 0; @@ -953,7 +953,7 @@ done2: static sy_call_t *shmcalls[] = { (sy_call_t *)shmat, (sy_call_t *)oshmctl, (sy_call_t *)shmdt, (sy_call_t *)shmget, - (sy_call_t *)shmctl + (sy_call_t *)freebsd7_shmctl }; int @@ -983,6 +983,93 @@ shmsys(td, uap) SYSCALL_MODULE_HELPER(shmsys); #endif /* i386 && (COMPAT_FREEBSD4 || COMPAT_43) */ +#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ + defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) + +#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) + + +#ifndef _SYS_SYSPROTO_H_ +struct freebsd7_shmctl_args { + int shmid; + int cmd; + struct shmid_ds_old *buf; +}; +#endif +int +freebsd7_shmctl(td, uap) + struct thread *td; + struct freebsd7_shmctl_args *uap; +{ + int error = 0; + struct shmid_ds_old old; + struct shmid_ds buf; + size_t bufsz; + + /* + * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support + * Linux binaries. If we see the call come through the FreeBSD ABI, + * return an error back to the user since we do not to support this. + */ + if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO || + uap->cmd == SHM_STAT) + return (EINVAL); + + /* IPC_SET needs to copyin the buffer before calling kern_shmctl */ + if (uap->cmd == IPC_SET) { + if ((error = copyin(uap->buf, &old, sizeof(old)))) + goto done; + ipcperm_old2new(&old.shm_perm, &buf.shm_perm); + CP(old, buf, shm_segsz); + CP(old, buf, shm_lpid); + CP(old, buf, shm_cpid); + CP(old, buf, shm_nattch); + CP(old, buf, shm_atime); + CP(old, buf, shm_dtime); + CP(old, buf, shm_ctime); + } + + error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz); + if (error) + goto done; + + /* Cases in which we need to copyout */ + switch (uap->cmd) { + case IPC_STAT: + ipcperm_new2old(&buf.shm_perm, &old.shm_perm); + if (buf.shm_segsz > INT_MAX) + old.shm_segsz = INT_MAX; + else + CP(buf, old, shm_segsz); + CP(buf, old, shm_lpid); + CP(buf, old, shm_cpid); + if (buf.shm_nattch > SHRT_MAX) + old.shm_nattch = SHRT_MAX; + else + CP(buf, old, shm_nattch); + CP(buf, old, shm_atime); + CP(buf, old, shm_dtime); + CP(buf, old, shm_ctime); + old.shm_internal = NULL; + error = copyout(&old, uap->buf, sizeof(old)); + break; + } + +done: + if (error) { + /* Invalidate the return value */ + td->td_retval[0] = -1; + } + return (error); +} + +SYSCALL_MODULE_HELPER(freebsd7_shmctl); + +#undef CP + +#endif /* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 || + COMPAT_FREEBSD7 */ + static int sysvshm_modload(struct module *module, int cmd, void *arg) { |