diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-11-07 18:52:28 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-11-07 18:52:28 +0000 |
| commit | c06e7b66a147edf55f4241fbfbfa32856550cd15 (patch) | |
| tree | bb0300c3cdd104f8d1a9445142dda9913e9bd055 /sys | |
| parent | f46f6c14b4bcb6eb831d7d4d1a877a3a4e034c62 (diff) | |
| parent | 36d2d637dd0ad3227083b5ebd9e38c17c6c934a1 (diff) | |
Notes
Diffstat (limited to 'sys')
62 files changed, 2606 insertions, 328 deletions
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index f74db37a283e..34fb1e8e4370 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -100,6 +100,8 @@ options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones options VERBOSE_SYSINIT=0 # Support debug.verbose_sysinit, off by default +# Warning: KUBSAN can result in a kernel too large for loader to load +#options KUBSAN # Kernel Undefined Behavior Sanitizer # Kernel dump features. options EKCD # Support for encrypted kernel dumps diff --git a/sys/amd64/include/cpu.h b/sys/amd64/include/cpu.h index db3554fad84f..1b8a552d3e7c 100644 --- a/sys/amd64/include/cpu.h +++ b/sys/amd64/include/cpu.h @@ -77,6 +77,7 @@ extern char etext[]; extern void (*vmm_resume_p)(void); void cpu_halt(void); +void cpu_lock_delay(void); void cpu_reset(void); void fork_trampoline(void); void swi_vm(void *); diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c index 66d441e96c68..bcaa0cd45459 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -32,6 +32,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "opt_compat.h" + #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -1071,7 +1073,7 @@ linux_elf_modevent(module_t mod, int type, void *data) error = EINVAL; if (error == 0) { SET_FOREACH(lihp, linux_ioctl_handler_set) - linux_ioctl_register_handler(*lihp); + linux32_ioctl_register_handler(*lihp); LIST_INIT(&futex_list); mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF); stclohz = (stathz ? stathz : hz); @@ -1093,7 +1095,7 @@ linux_elf_modevent(module_t mod, int type, void *data) } if (error == 0) { SET_FOREACH(lihp, linux_ioctl_handler_set) - linux_ioctl_unregister_handler(*lihp); + linux32_ioctl_unregister_handler(*lihp); mtx_destroy(&futex_mtx); if (bootverbose) printf("Linux ELF exec handler removed\n"); diff --git a/sys/arm/include/cpu.h b/sys/arm/include/cpu.h index 1ef5798ecddb..7c7de38a2536 100644 --- a/sys/arm/include/cpu.h +++ b/sys/arm/include/cpu.h @@ -61,6 +61,7 @@ get_cyclecount(void) #define cpu_getstack(td) ((td)->td_frame->tf_usr_sp) #define cpu_setstack(td, sp) ((td)->td_frame->tf_usr_sp = (sp)) #define cpu_spinwait() /* nothing */ +#define cpu_lock_delay() DELAY(1) #define ARM_NVEC 8 #define ARM_VEC_ALL 0xffffffff diff --git a/sys/arm/include/elf.h b/sys/arm/include/elf.h index 7424b45e78f4..28fc14e3dae3 100644 --- a/sys/arm/include/elf.h +++ b/sys/arm/include/elf.h @@ -84,7 +84,7 @@ __ElfType(Auxinfo); */ #define MAGIC_TRAMP_NUMBER 0x5c000003 -#define ET_DYN_LOAD_ADDR 0x12000 +#define ET_DYN_LOAD_ADDR 0x500000 /* Flags passed in AT_HWCAP. */ #define HWCAP_SWP 0x00000001 /* Unsupported, never set. */ diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC index ee4ab292928f..c626727d5209 100644 --- a/sys/arm64/conf/GENERIC +++ b/sys/arm64/conf/GENERIC @@ -92,6 +92,8 @@ options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones options ALT_BREAK_TO_DEBUGGER # Enter debugger on keyboard escape sequence options USB_DEBUG # enable debug msgs options VERBOSE_SYSINIT=0 # Support debug.verbose_sysinit, off by default +# Warning: KUBSAN can result in a kernel too large for loader to load +#options KUBSAN # Kernel Undefined Behavior Sanitizer # Kernel dump features. options EKCD # Support for encrypted kernel dumps diff --git a/sys/arm64/include/cpu.h b/sys/arm64/include/cpu.h index f5d7909b7899..3cfc59c25bff 100644 --- a/sys/arm64/include/cpu.h +++ b/sys/arm64/include/cpu.h @@ -51,6 +51,7 @@ #define cpu_getstack(td) ((td)->td_frame->tf_sp) #define cpu_setstack(td, sp) ((td)->td_frame->tf_sp = (sp)) #define cpu_spinwait() __asm __volatile("yield" ::: "memory") +#define cpu_lock_delay() DELAY(1) /* Extract CPU affinity levels 0-3 */ #define CPU_AFF0(mpidr) (u_int)(((mpidr) >> 0) & 0xff) diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 2483c5e7633e..a1ac49d146db 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -2005,7 +2005,7 @@ daasync(void *callback_arg, u_int32_t code, periph = (struct cam_periph *)callback_arg; switch (code) { - case AC_FOUND_DEVICE: + case AC_FOUND_DEVICE: /* callback to create periph, no locking yet */ { struct ccb_getdev *cgd; cam_status status; @@ -2041,7 +2041,7 @@ daasync(void *callback_arg, u_int32_t code, "due to status 0x%x\n", status); return; } - case AC_ADVINFO_CHANGED: + case AC_ADVINFO_CHANGED: /* Doesn't touch periph */ { uintptr_t buftype; @@ -2064,8 +2064,10 @@ daasync(void *callback_arg, u_int32_t code, ccb = (union ccb *)arg; /* - * Handle all UNIT ATTENTIONs except our own, - * as they will be handled by daerror(). + * Handle all UNIT ATTENTIONs except our own, as they will be + * handled by daerror(). Since this comes from a different periph, + * that periph's lock is held, not ours, so we have to take it ours + * out to touch softc flags. */ if (xpt_path_periph(ccb->ccb_h.path) != periph && scsi_extract_sense_ccb(ccb, @@ -2093,9 +2095,13 @@ daasync(void *callback_arg, u_int32_t code, } break; } - case AC_SCSI_AEN: + case AC_SCSI_AEN: /* Called for this path: periph locked */ + /* + * Appears to be currently unused for SCSI devices, only ata SIMs + * generate this. + */ + cam_periph_assert(periph, MA_OWNED); softc = (struct da_softc *)periph->softc; - cam_periph_lock(periph); if (!cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR) && (softc->flags & DA_FLAG_TUR_PENDING) == 0) { if (da_periph_acquire(periph, DA_REF_TUR) == 0) { @@ -2103,31 +2109,28 @@ daasync(void *callback_arg, u_int32_t code, daschedule(periph); } } - cam_periph_unlock(periph); /* FALLTHROUGH */ - case AC_SENT_BDR: - case AC_BUS_RESET: + case AC_SENT_BDR: /* Called for this path: periph locked */ + case AC_BUS_RESET: /* Called for this path: periph locked */ { struct ccb_hdr *ccbh; + cam_periph_assert(periph, MA_OWNED); softc = (struct da_softc *)periph->softc; /* * Don't fail on the expected unit attention * that will occur. */ - cam_periph_lock(periph); softc->flags |= DA_FLAG_RETRY_UA; LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) ccbh->ccb_state |= DA_CCB_RETRY_UA; - cam_periph_unlock(periph); break; } - case AC_INQ_CHANGED: - cam_periph_lock(periph); + case AC_INQ_CHANGED: /* Called for this path: periph locked */ + cam_periph_assert(periph, MA_OWNED); softc = (struct da_softc *)periph->softc; softc->flags &= ~DA_FLAG_PROBED; dareprobe(periph); - cam_periph_unlock(periph); break; default: break; diff --git a/sys/compat/freebsd32/capabilities.conf b/sys/compat/freebsd32/capabilities.conf index c96dab7aa9d4..8d7105cef948 100644 --- a/sys/compat/freebsd32/capabilities.conf +++ b/sys/compat/freebsd32/capabilities.conf @@ -203,6 +203,7 @@ pdkill freebsd32_pipe pipe2 poll +freebsd32_ppoll freebsd32_posix_fallocate freebsd32_pread freebsd32_preadv diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h index ed48baf7295f..9f15277fc77c 100644 --- a/sys/compat/freebsd32/freebsd32_proto.h +++ b/sys/compat/freebsd32/freebsd32_proto.h @@ -55,10 +55,10 @@ struct freebsd32_sendmsg_args { }; struct freebsd32_recvfrom_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char buf_l_[PADL_(uint32_t)]; uint32_t buf; char buf_r_[PADR_(uint32_t)]; + char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)]; char len_l_[PADL_(uint32_t)]; uint32_t len; char len_r_[PADR_(uint32_t)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; - char from_l_[PADL_(uint32_t)]; uint32_t from; char from_r_[PADR_(uint32_t)]; + char from_l_[PADL_(struct sockaddr *)]; struct sockaddr * from; char from_r_[PADR_(struct sockaddr *)]; char fromlenaddr_l_[PADL_(uint32_t)]; uint32_t fromlenaddr; char fromlenaddr_r_[PADR_(uint32_t)]; }; struct freebsd10_freebsd32_pipe_args { @@ -417,7 +417,7 @@ struct freebsd32_pwrite_args { char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)]; }; struct freebsd32_mmap_args { - char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; + char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)]; char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; @@ -461,7 +461,7 @@ struct freebsd32_pwrite_args { char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)]; }; struct freebsd32_mmap_args { - char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; + char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)]; char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; @@ -1020,7 +1020,7 @@ struct freebsd6_freebsd32_pwrite_args { char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)]; }; struct freebsd6_freebsd32_mmap_args { - char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; + char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)]; char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c index 1a6ff314dfa2..de97d29af51e 100644 --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -624,7 +624,7 @@ struct sysent freebsd32_sysent[] = { #else { AS(freebsd32_procctl_args), (sy_call_t *)freebsd32_procctl, AUE_PROCCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 544 = freebsd32_procctl */ #endif - { AS(freebsd32_ppoll_args), (sy_call_t *)freebsd32_ppoll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 545 = freebsd32_ppoll */ + { AS(freebsd32_ppoll_args), (sy_call_t *)freebsd32_ppoll, AUE_POLL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 545 = freebsd32_ppoll */ { AS(freebsd32_futimens_args), (sy_call_t *)freebsd32_futimens, AUE_FUTIMES, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 546 = freebsd32_futimens */ { AS(freebsd32_utimensat_args), (sy_call_t *)freebsd32_utimensat, AUE_FUTIMESAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 547 = freebsd32_utimensat */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 548 = obsolete numa_getaffinity */ diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c index 59d97c7a74ce..116d6c40716d 100644 --- a/sys/compat/freebsd32/freebsd32_systrace_args.c +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -139,7 +139,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) uarg[0] = (intptr_t) p->type; /* const char * */ uarg[1] = (intptr_t) p->path; /* const char * */ iarg[2] = p->flags; /* int */ - uarg[3] = (intptr_t) p->data; /* caddr_t */ + uarg[3] = (intptr_t) p->data; /* void * */ *n_args = 4; break; } @@ -200,10 +200,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 29: { struct freebsd32_recvfrom_args *p = params; iarg[0] = p->s; /* int */ - uarg[1] = p->buf; /* uint32_t */ + uarg[1] = (intptr_t) p->buf; /* void * */ uarg[2] = p->len; /* uint32_t */ iarg[3] = p->flags; /* int */ - uarg[4] = p->from; /* uint32_t */ + uarg[4] = (intptr_t) p->from; /* struct sockaddr * */ uarg[5] = p->fromlenaddr; /* uint32_t */ *n_args = 6; break; @@ -212,7 +212,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 30: { struct accept_args *p = params; iarg[0] = p->s; /* int */ - uarg[1] = (intptr_t) p->name; /* caddr_t */ + uarg[1] = (intptr_t) p->name; /* struct sockaddr * */ uarg[2] = (intptr_t) p->anamelen; /* int * */ *n_args = 3; break; @@ -221,7 +221,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 31: { struct getpeername_args *p = params; iarg[0] = p->fdes; /* int */ - uarg[1] = (intptr_t) p->asa; /* caddr_t */ + uarg[1] = (intptr_t) p->asa; /* struct sockaddr * */ uarg[2] = (intptr_t) p->alen; /* int * */ *n_args = 3; break; @@ -230,7 +230,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 32: { struct getsockname_args *p = params; iarg[0] = p->fdes; /* int */ - uarg[1] = (intptr_t) p->asa; /* caddr_t */ + uarg[1] = (intptr_t) p->asa; /* struct sockaddr * */ uarg[2] = (intptr_t) p->alen; /* int * */ *n_args = 3; break; @@ -292,7 +292,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* profil */ case 44: { struct profil_args *p = params; - uarg[0] = (intptr_t) p->samples; /* caddr_t */ + uarg[0] = (intptr_t) p->samples; /* char * */ uarg[1] = p->size; /* size_t */ uarg[2] = p->offset; /* size_t */ uarg[3] = p->scale; /* u_int */ @@ -585,7 +585,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 98: { struct connect_args *p = params; iarg[0] = p->s; /* int */ - uarg[1] = (intptr_t) p->name; /* caddr_t */ + uarg[1] = (intptr_t) p->name; /* const struct sockaddr * */ iarg[2] = p->namelen; /* int */ *n_args = 3; break; @@ -602,7 +602,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 104: { struct bind_args *p = params; iarg[0] = p->s; /* int */ - uarg[1] = (intptr_t) p->name; /* caddr_t */ + uarg[1] = (intptr_t) p->name; /* const struct sockaddr * */ iarg[2] = p->namelen; /* int */ *n_args = 3; break; @@ -613,7 +613,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[0] = p->s; /* int */ iarg[1] = p->level; /* int */ iarg[2] = p->name; /* int */ - uarg[3] = (intptr_t) p->val; /* caddr_t */ + uarg[3] = (intptr_t) p->val; /* const void * */ iarg[4] = p->valsize; /* int */ *n_args = 5; break; @@ -648,7 +648,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[0] = p->s; /* int */ iarg[1] = p->level; /* int */ iarg[2] = p->name; /* int */ - uarg[3] = (intptr_t) p->val; /* caddr_t */ + uarg[3] = (intptr_t) p->val; /* void * */ uarg[4] = (intptr_t) p->avalsize; /* int * */ *n_args = 5; break; @@ -740,10 +740,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 133: { struct sendto_args *p = params; iarg[0] = p->s; /* int */ - uarg[1] = (intptr_t) p->buf; /* caddr_t */ + uarg[1] = (intptr_t) p->buf; /* const void * */ uarg[2] = p->len; /* size_t */ iarg[3] = p->flags; /* int */ - uarg[4] = (intptr_t) p->to; /* caddr_t */ + uarg[4] = (intptr_t) p->to; /* const struct sockaddr * */ iarg[5] = p->tolen; /* int */ *n_args = 6; break; @@ -808,7 +808,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) uarg[0] = (intptr_t) p->path; /* const char * */ iarg[1] = p->cmd; /* int */ iarg[2] = p->uid; /* int */ - uarg[3] = (intptr_t) p->arg; /* caddr_t */ + uarg[3] = (intptr_t) p->arg; /* void * */ *n_args = 4; break; } @@ -2312,9 +2312,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 472: { struct sctp_generic_sendmsg_args *p = params; iarg[0] = p->sd; /* int */ - uarg[1] = (intptr_t) p->msg; /* caddr_t */ + uarg[1] = (intptr_t) p->msg; /* void * */ iarg[2] = p->mlen; /* int */ - uarg[3] = (intptr_t) p->to; /* caddr_t */ + uarg[3] = (intptr_t) p->to; /* struct sockaddr * */ iarg[4] = p->tolen; /* __socklen_t */ uarg[5] = (intptr_t) p->sinfo; /* struct sctp_sndrcvinfo * */ iarg[6] = p->flags; /* int */ @@ -2327,7 +2327,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[0] = p->sd; /* int */ uarg[1] = (intptr_t) p->iov; /* struct iovec * */ iarg[2] = p->iovlen; /* int */ - uarg[3] = (intptr_t) p->to; /* caddr_t */ + uarg[3] = (intptr_t) p->to; /* struct sockaddr * */ iarg[4] = p->tolen; /* __socklen_t */ uarg[5] = (intptr_t) p->sinfo; /* struct sctp_sndrcvinfo * */ iarg[6] = p->flags; /* int */ @@ -2375,7 +2375,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* freebsd32_mmap */ case 477: { struct freebsd32_mmap_args *p = params; - uarg[0] = (intptr_t) p->addr; /* caddr_t */ + uarg[0] = (intptr_t) p->addr; /* void * */ uarg[1] = p->len; /* size_t */ iarg[2] = p->prot; /* int */ iarg[3] = p->flags; /* int */ @@ -2443,7 +2443,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* freebsd32_mmap */ case 477: { struct freebsd32_mmap_args *p = params; - uarg[0] = (intptr_t) p->addr; /* caddr_t */ + uarg[0] = (intptr_t) p->addr; /* void * */ uarg[1] = p->len; /* size_t */ iarg[2] = p->prot; /* int */ iarg[3] = p->flags; /* int */ @@ -3021,7 +3021,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct bindat_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->s; /* int */ - uarg[2] = (intptr_t) p->name; /* caddr_t */ + uarg[2] = (intptr_t) p->name; /* const struct sockaddr * */ iarg[3] = p->namelen; /* int */ *n_args = 4; break; @@ -3031,7 +3031,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct connectat_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->s; /* int */ - uarg[2] = (intptr_t) p->name; /* caddr_t */ + uarg[2] = (intptr_t) p->name; /* const struct sockaddr * */ iarg[3] = p->namelen; /* int */ *n_args = 4; break; @@ -3462,7 +3462,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 3: - p = "caddr_t"; + p = "userland void *"; break; default: break; @@ -3555,7 +3555,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "uint32_t"; + p = "userland void *"; break; case 2: p = "uint32_t"; @@ -3564,7 +3564,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 4: - p = "uint32_t"; + p = "userland struct sockaddr *"; break; case 5: p = "uint32_t"; @@ -3580,7 +3580,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland struct sockaddr *"; break; case 2: p = "userland int *"; @@ -3596,7 +3596,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland struct sockaddr *"; break; case 2: p = "userland int *"; @@ -3612,7 +3612,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland struct sockaddr *"; break; case 2: p = "userland int *"; @@ -3696,7 +3696,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 44: switch(ndx) { case 0: - p = "caddr_t"; + p = "userland char *"; break; case 1: p = "size_t"; @@ -4164,7 +4164,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland const struct sockaddr *"; break; case 2: p = "int"; @@ -4193,7 +4193,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland const struct sockaddr *"; break; case 2: p = "int"; @@ -4215,7 +4215,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 3: - p = "caddr_t"; + p = "userland const void *"; break; case 4: p = "int"; @@ -4276,7 +4276,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 3: - p = "caddr_t"; + p = "userland void *"; break; case 4: p = "userland int *"; @@ -4431,7 +4431,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland const void *"; break; case 2: p = "size_t"; @@ -4440,7 +4440,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 4: - p = "caddr_t"; + p = "userland const struct sockaddr *"; break; case 5: p = "int"; @@ -4546,7 +4546,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 3: - p = "caddr_t"; + p = "userland void *"; break; default: break; @@ -6996,13 +6996,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland void *"; break; case 2: p = "int"; break; case 3: - p = "caddr_t"; + p = "userland struct sockaddr *"; break; case 4: p = "__socklen_t"; @@ -7030,7 +7030,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 3: - p = "caddr_t"; + p = "userland struct sockaddr *"; break; case 4: p = "__socklen_t"; @@ -7128,7 +7128,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 477: switch(ndx) { case 0: - p = "caddr_t"; + p = "userland void *"; break; case 1: p = "size_t"; @@ -7264,7 +7264,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 477: switch(ndx) { case 0: - p = "caddr_t"; + p = "userland void *"; break; case 1: p = "size_t"; @@ -8323,7 +8323,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 2: - p = "caddr_t"; + p = "userland const struct sockaddr *"; break; case 3: p = "int"; @@ -8342,7 +8342,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 2: - p = "caddr_t"; + p = "userland const struct sockaddr *"; break; case 3: p = "int"; diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 36d2d65fa3ce..980c4194f184 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -97,7 +97,7 @@ 20 AUE_GETPID NOPROTO { pid_t getpid(void); } 21 AUE_MOUNT NOPROTO { int mount(const char *type, \ const char *path, \ - int flags, caddr_t data); } + int flags, void *data); } 22 AUE_UMOUNT NOPROTO { int unmount(const char *path, int flags); } 23 AUE_SETUID NOPROTO { int setuid(uid_t uid); } 24 AUE_GETUID NOPROTO { uid_t getuid(void); } @@ -108,14 +108,17 @@ int flags); } 28 AUE_SENDMSG STD { int freebsd32_sendmsg(int s, struct msghdr32 *msg, \ int flags); } -29 AUE_RECVFROM STD { int freebsd32_recvfrom(int s, uint32_t buf, \ - uint32_t len, int flags, uint32_t from, \ +29 AUE_RECVFROM STD { int freebsd32_recvfrom(int s, void *buf, \ + uint32_t len, int flags, \ + struct sockaddr *from, \ uint32_t fromlenaddr); } -30 AUE_ACCEPT NOPROTO { int accept(int s, caddr_t name, \ +30 AUE_ACCEPT NOPROTO { int accept(int s, struct sockaddr *name, \ int *anamelen); } -31 AUE_GETPEERNAME NOPROTO { int getpeername(int fdes, caddr_t asa, \ +31 AUE_GETPEERNAME NOPROTO { int getpeername(int fdes, \ + struct sockaddr *asa, \ int *alen); } -32 AUE_GETSOCKNAME NOPROTO { int getsockname(int fdes, caddr_t asa, \ +32 AUE_GETSOCKNAME NOPROTO { int getsockname(int fdes, \ + struct sockaddr *asa, \ int *alen); } 33 AUE_ACCESS NOPROTO { int access(const char *path, int amode); } 34 AUE_CHFLAGS NOPROTO { int chflags(const char *path, u_long flags); } @@ -130,7 +133,7 @@ 41 AUE_DUP NOPROTO { int dup(u_int fd); } 42 AUE_PIPE COMPAT10 { int freebsd32_pipe(void); } 43 AUE_GETEGID NOPROTO { gid_t getegid(void); } -44 AUE_PROFILE NOPROTO { int profil(caddr_t samples, size_t size, \ +44 AUE_PROFILE NOPROTO { int profil(char *samples, size_t size, \ size_t offset, u_int scale); } 45 AUE_KTRACE NOPROTO { int ktrace(const char *fname, int ops, \ int facs, int pid); } @@ -214,7 +217,8 @@ int prio); } 97 AUE_SOCKET NOPROTO { int socket(int domain, int type, \ int protocol); } -98 AUE_CONNECT NOPROTO { int connect(int s, caddr_t name, \ +98 AUE_CONNECT NOPROTO { int connect(int s, \ + const struct sockaddr *name, \ int namelen); } 99 AUE_NULL OBSOL oaccept 100 AUE_GETPRIORITY NOPROTO { int getpriority(int which, int who); } @@ -222,10 +226,10 @@ 102 AUE_NULL OBSOL orecv 103 AUE_SIGRETURN COMPAT { int freebsd32_sigreturn( \ struct ia32_sigcontext3 *sigcntxp); } -104 AUE_BIND NOPROTO { int bind(int s, caddr_t name, \ +104 AUE_BIND NOPROTO { int bind(int s, const struct sockaddr *name, \ int namelen); } 105 AUE_SETSOCKOPT NOPROTO { int setsockopt(int s, int level, \ - int name, caddr_t val, int valsize); } + int name, const void *val, int valsize); } 106 AUE_LISTEN NOPROTO { int listen(int s, int backlog); } 107 AUE_NULL OBSOL vtimes 108 AUE_O_SIGVEC COMPAT { int freebsd32_sigvec(int signum, \ @@ -246,7 +250,7 @@ 117 AUE_GETRUSAGE STD { int freebsd32_getrusage(int who, \ struct rusage32 *rusage); } 118 AUE_GETSOCKOPT NOPROTO { int getsockopt(int s, int level, \ - int name, caddr_t val, int *avalsize); } + int name, void *val, int *avalsize); } 119 AUE_NULL UNIMPL resuba (BSD/OS 2.x) 120 AUE_READV STD { int freebsd32_readv(int fd, \ struct iovec32 *iovp, u_int iovcnt); } @@ -267,8 +271,9 @@ 130 AUE_FTRUNCATE COMPAT|NOPROTO { int ftruncate(int fd, int length); } 131 AUE_FLOCK NOPROTO { int flock(int fd, int how); } 132 AUE_MKFIFO NOPROTO { int mkfifo(const char *path, mode_t mode); } -133 AUE_SENDTO NOPROTO { int sendto(int s, caddr_t buf, \ - size_t len, int flags, caddr_t to, \ +133 AUE_SENDTO NOPROTO { int sendto(int s, const void *buf, \ + size_t len, int flags, \ + const struct sockaddr *to, \ int tolen); } 134 AUE_SHUTDOWN NOPROTO { int shutdown(int s, int how); } 135 AUE_SOCKETPAIR NOPROTO { int socketpair(int domain, int type, \ @@ -289,7 +294,7 @@ 146 AUE_KILLPG OBSOL killpg 147 AUE_SETSID NOPROTO { int setsid(void); } 148 AUE_QUOTACTL NOPROTO { int quotactl(const char *path, int cmd, \ - int uid, caddr_t arg); } + int uid, void *arg); } 149 AUE_O_QUOTA OBSOL oquota 150 AUE_GETSOCKNAME OBSOL ogetsockname @@ -368,7 +373,7 @@ __setrlimit_args int 196 AUE_GETDIRENTRIES COMPAT11 { int freebsd32_getdirentries(int fd, \ char *buf, u_int count, int32_t *basep); } -197 AUE_MMAP COMPAT6 { caddr_t freebsd32_mmap(caddr_t addr, \ +197 AUE_MMAP COMPAT6 { caddr_t freebsd32_mmap(void *addr, \ size_t len, int prot, int flags, int fd, \ int pad, uint32_t pos1, uint32_t pos2); } 198 AUE_NULL NOPROTO { int nosys(void); } __syscall \ @@ -852,11 +857,12 @@ 469 AUE_NULL UNIMPL __getpath_fromfd 470 AUE_NULL UNIMPL __getpath_fromaddr 471 AUE_SCTP_PEELOFF NOPROTO|NOSTD { int sctp_peeloff(int sd, uint32_t name); } -472 AUE_SCTP_GENERIC_SENDMSG NOPROTO|NOSTD { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, \ - caddr_t to, __socklen_t tolen, \ +472 AUE_SCTP_GENERIC_SENDMSG NOPROTO|NOSTD { int sctp_generic_sendmsg( \ + int sd, void *msg, int mlen, \ + struct sockaddr *to, __socklen_t tolen, \ struct sctp_sndrcvinfo *sinfo, int flags); } 473 AUE_SCTP_GENERIC_SENDMSG_IOV NOPROTO|NOSTD { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, \ - caddr_t to, __socklen_t tolen, \ + struct sockaddr *to, __socklen_t tolen, \ struct sctp_sndrcvinfo *sinfo, int flags); } 474 AUE_SCTP_GENERIC_RECVMSG NOPROTO|NOSTD { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, \ struct sockaddr * from, __socklen_t *fromlenaddr, \ @@ -870,7 +876,7 @@ const void *buf, size_t nbyte, \ int pad, \ uint32_t offset1, uint32_t offset2); } -477 AUE_MMAP STD { caddr_t freebsd32_mmap(caddr_t addr, \ +477 AUE_MMAP STD { caddr_t freebsd32_mmap(void *addr, \ size_t len, int prot, int flags, int fd, \ int pad, \ uint32_t pos1, uint32_t pos2); } @@ -891,7 +897,7 @@ 476 AUE_PWRITE STD { ssize_t freebsd32_pwrite(int fd, \ const void *buf, size_t nbyte, \ uint32_t offset1, uint32_t offset2); } -477 AUE_MMAP STD { caddr_t freebsd32_mmap(caddr_t addr, \ +477 AUE_MMAP STD { caddr_t freebsd32_mmap(void *addr, \ size_t len, int prot, int flags, int fd, \ uint32_t pos1, uint32_t pos2); } 478 AUE_LSEEK STD { off_t freebsd32_lseek(int fd, \ @@ -1054,9 +1060,11 @@ uint32_t fcntlrights); } 537 AUE_CAP_FCNTLS_GET NOPROTO { int cap_fcntls_get(int fd, \ uint32_t *fcntlrightsp); } -538 AUE_BINDAT NOPROTO { int bindat(int fd, int s, caddr_t name, \ +538 AUE_BINDAT NOPROTO { int bindat(int fd, int s, \ + const struct sockaddr *name, \ int namelen); } -539 AUE_CONNECTAT NOPROTO { int connectat(int fd, int s, caddr_t name, \ +539 AUE_CONNECTAT NOPROTO { int connectat(int fd, int s, \ + const struct sockaddr *name, \ int namelen); } 540 AUE_CHFLAGSAT NOPROTO { int chflagsat(int fd, const char *path, \ u_long flags, int atflag); } diff --git a/sys/compat/linux/linux_common.c b/sys/compat/linux/linux_common.c index b9e35311bdfe..551823d7e0de 100644 --- a/sys/compat/linux/linux_common.c +++ b/sys/compat/linux/linux_common.c @@ -35,9 +35,11 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/eventhandler.h> +#include <sys/sx.h> #include <sys/sysctl.h> #include <compat/linux/linux_emul.h> +#include <compat/linux/linux_ioctl.h> #include <compat/linux/linux_mib.h> #include <compat/linux/linux_util.h> @@ -48,6 +50,11 @@ MODULE_VERSION(linux_common, 1); SET_DECLARE(linux_device_handler_set, struct linux_device_handler); +TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers = + TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers); +struct sx linux_ioctl_sx; +SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers"); + static eventhandler_tag linux_exec_tag; static eventhandler_tag linux_thread_dtor_tag; static eventhandler_tag linux_exit_tag; diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index cea8721f096e..0a8e5087984b 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -161,17 +161,19 @@ DATA_SET(linux_ioctl_handler_set, video2_handler); DATA_SET(linux_ioctl_handler_set, fbsd_usb); DATA_SET(linux_ioctl_handler_set, evdev_handler); -struct handler_element -{ - TAILQ_ENTRY(handler_element) list; - int (*func)(struct thread *, struct linux_ioctl_args *); - int low, high, span; -}; - -static TAILQ_HEAD(, handler_element) handlers = - TAILQ_HEAD_INITIALIZER(handlers); +#ifdef __i386__ +static TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers = + TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers); static struct sx linux_ioctl_sx; SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers"); +#else +extern TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers; +extern struct sx linux_ioctl_sx; +#endif +#ifdef COMPAT_LINUX32 +static TAILQ_HEAD(, linux_ioctl_handler_element) linux32_ioctl_handlers = + TAILQ_HEAD_INITIALIZER(linux32_ioctl_handlers); +#endif /* * hdio related ioctls for VMWare support @@ -3684,7 +3686,7 @@ int linux_ioctl(struct thread *td, struct linux_ioctl_args *args) { struct file *fp; - struct handler_element *he; + struct linux_ioctl_handler_element *he; int error, cmd; #ifdef DEBUG @@ -3705,7 +3707,20 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args *args) cmd = args->cmd & 0xffff; sx_slock(&linux_ioctl_sx); mtx_lock(&Giant); - TAILQ_FOREACH(he, &handlers, list) { +#ifdef COMPAT_LINUX32 + TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) { + if (cmd >= he->low && cmd <= he->high) { + error = (*he->func)(td, args); + if (error != ENOIOCTL) { + mtx_unlock(&Giant); + sx_sunlock(&linux_ioctl_sx); + fdrop(fp, td); + return (error); + } + } + } +#endif + TAILQ_FOREACH(he, &linux_ioctl_handlers, list) { if (cmd >= he->low && cmd <= he->high) { error = (*he->func)(td, args); if (error != ENOIOCTL) { @@ -3737,7 +3752,7 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args *args) int linux_ioctl_register_handler(struct linux_ioctl_handler *h) { - struct handler_element *he, *cur; + struct linux_ioctl_handler_element *he, *cur; if (h == NULL || h->func == NULL) return (EINVAL); @@ -3747,7 +3762,7 @@ linux_ioctl_register_handler(struct linux_ioctl_handler *h) * create a new element. */ sx_xlock(&linux_ioctl_sx); - TAILQ_FOREACH(he, &handlers, list) { + TAILQ_FOREACH(he, &linux_ioctl_handlers, list) { if (he->func == h->func) break; } @@ -3756,7 +3771,7 @@ linux_ioctl_register_handler(struct linux_ioctl_handler *h) M_LINUX, M_WAITOK); he->func = h->func; } else - TAILQ_REMOVE(&handlers, he, list); + TAILQ_REMOVE(&linux_ioctl_handlers, he, list); /* Initialize range information. */ he->low = h->low; @@ -3764,14 +3779,14 @@ linux_ioctl_register_handler(struct linux_ioctl_handler *h) he->span = h->high - h->low + 1; /* Add the element to the list, sorted on span. */ - TAILQ_FOREACH(cur, &handlers, list) { + TAILQ_FOREACH(cur, &linux_ioctl_handlers, list) { if (cur->span > he->span) { TAILQ_INSERT_BEFORE(cur, he, list); sx_xunlock(&linux_ioctl_sx); return (0); } } - TAILQ_INSERT_TAIL(&handlers, he, list); + TAILQ_INSERT_TAIL(&linux_ioctl_handlers, he, list); sx_xunlock(&linux_ioctl_sx); return (0); @@ -3780,15 +3795,80 @@ linux_ioctl_register_handler(struct linux_ioctl_handler *h) int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h) { - struct handler_element *he; + struct linux_ioctl_handler_element *he; + + if (h == NULL || h->func == NULL) + return (EINVAL); + + sx_xlock(&linux_ioctl_sx); + TAILQ_FOREACH(he, &linux_ioctl_handlers, list) { + if (he->func == h->func) { + TAILQ_REMOVE(&linux_ioctl_handlers, he, list); + sx_xunlock(&linux_ioctl_sx); + free(he, M_LINUX); + return (0); + } + } + sx_xunlock(&linux_ioctl_sx); + + return (EINVAL); +} + +#ifdef COMPAT_LINUX32 +int +linux32_ioctl_register_handler(struct linux_ioctl_handler *h) +{ + struct linux_ioctl_handler_element *he, *cur; if (h == NULL || h->func == NULL) return (EINVAL); + /* + * Reuse the element if the handler is already on the list, otherwise + * create a new element. + */ sx_xlock(&linux_ioctl_sx); - TAILQ_FOREACH(he, &handlers, list) { + TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) { + if (he->func == h->func) + break; + } + if (he == NULL) { + he = malloc(sizeof(*he), M_LINUX, M_WAITOK); + he->func = h->func; + } else + TAILQ_REMOVE(&linux32_ioctl_handlers, he, list); + + /* Initialize range information. */ + he->low = h->low; + he->high = h->high; + he->span = h->high - h->low + 1; + + /* Add the element to the list, sorted on span. */ + TAILQ_FOREACH(cur, &linux32_ioctl_handlers, list) { + if (cur->span > he->span) { + TAILQ_INSERT_BEFORE(cur, he, list); + sx_xunlock(&linux_ioctl_sx); + return (0); + } + } + TAILQ_INSERT_TAIL(&linux32_ioctl_handlers, he, list); + sx_xunlock(&linux_ioctl_sx); + + return (0); +} + +int +linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h) +{ + struct linux_ioctl_handler_element *he; + + if (h == NULL || h->func == NULL) + return (EINVAL); + + sx_xlock(&linux_ioctl_sx); + TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) { if (he->func == h->func) { - TAILQ_REMOVE(&handlers, he, list); + TAILQ_REMOVE(&linux32_ioctl_handlers, he, list); sx_xunlock(&linux_ioctl_sx); free(he, M_LINUX); return (0); @@ -3798,3 +3878,4 @@ linux_ioctl_unregister_handler(struct linux_ioctl_handler *h) return (EINVAL); } +#endif diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h index d8aaadd62ddd..519f55e6c161 100644 --- a/sys/compat/linux/linux_ioctl.h +++ b/sys/compat/linux/linux_ioctl.h @@ -770,7 +770,18 @@ struct linux_ioctl_handler { int low, high; }; +struct linux_ioctl_handler_element +{ + TAILQ_ENTRY(linux_ioctl_handler_element) list; + int (*func)(struct thread *, struct linux_ioctl_args *); + int low, high, span; +}; + int linux_ioctl_register_handler(struct linux_ioctl_handler *h); int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h); +#ifdef COMPAT_LINUX32 +int linux32_ioctl_register_handler(struct linux_ioctl_handler *h); +int linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h); +#endif #endif /* !_LINUX_IOCTL_H_ */ diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c index 415bc1024252..15a137a5dd73 100644 --- a/sys/compat/linux/linux_socket.c +++ b/sys/compat/linux/linux_socket.c @@ -1520,7 +1520,7 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) int s; int level; int name; - caddr_t val; + const void *val; int valsize; } */ bsd_args; l_timeval linux_tv; @@ -1570,10 +1570,11 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) bsd_args.valsize = args->optlen; if (name == IPV6_NEXTHOP) { - linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val, - bsd_args.valsize); + linux_to_bsd_sockaddr(__DECONST(struct sockaddr *, + bsd_args.val), bsd_args.valsize); error = sys_setsockopt(td, &bsd_args); - bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); + bsd_to_linux_sockaddr(__DECONST(struct sockaddr *, + bsd_args.val)); } else error = sys_setsockopt(td, &bsd_args); diff --git a/sys/conf/files b/sys/conf/files index 1ca735ba9957..9294d67aa172 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3824,6 +3824,7 @@ kern/kern_thread.c standard kern/kern_time.c standard kern/kern_timeout.c standard kern/kern_tslog.c optional tslog +kern/kern_ubsan.c optional kubsan kern/kern_umtx.c standard kern/kern_uuid.c standard kern/kern_xxx.c standard diff --git a/sys/conf/kern.post.mk b/sys/conf/kern.post.mk index 98d179446905..398dc7165984 100644 --- a/sys/conf/kern.post.mk +++ b/sys/conf/kern.post.mk @@ -28,6 +28,10 @@ MKMODULESENV+= WITH_CTF="${WITH_CTF}" MKMODULESENV+= WITH_EXTRA_TCP_STACKS="${WITH_EXTRA_TCP_STACKS}" .endif +.if defined(SAN_CFLAGS) +MKMODULESENV+= SAN_CFLAGS="${SAN_CFLAGS}" +.endif + # Allow overriding the kernel debug directory, so kernel and user debug may be # installed in different directories. Setting it to "" restores the historical # behavior of installing debug files in the kernel directory. diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk index 38a9c14ddbb5..bca9ff79e756 100644 --- a/sys/conf/kern.pre.mk +++ b/sys/conf/kern.pre.mk @@ -113,6 +113,12 @@ PROF= -pg .endif DEFINED_PROF= ${PROF} +KUBSAN_ENABLED!= grep KUBSAN opt_global.h || true ; echo +.if !empty(KUBSAN_ENABLED) +SAN_CFLAGS+= -fsanitize=undefined +.endif +CFLAGS+= ${SAN_CFLAGS} + # Put configuration-specific C flags last (except for ${PROF}) so that they # can override the others. CFLAGS+= ${CONF_CFLAGS} diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk index a357c565ab5f..4f239d10bd3a 100644 --- a/sys/conf/kmod.mk +++ b/sys/conf/kmod.mk @@ -377,6 +377,9 @@ ${_src}: .endfor .endif +# Add the sanitizer C flags +CFLAGS+= ${SAN_CFLAGS} + # Respect configuration-specific C flags. CFLAGS+= ${ARCH_FLAGS} ${CONF_CFLAGS} diff --git a/sys/conf/options b/sys/conf/options index 9d86cbdfd663..240b1d606df5 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -232,6 +232,9 @@ UMTX_CHAINS opt_global.h VERBOSE_SYSINIT ZSTDIO opt_zstdio.h +# Sanitizers +KUBSAN opt_global.h + # POSIX kernel options P1003_1B_MQUEUE opt_posix.h P1003_1B_SEMAPHORES opt_posix.h diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h index dbebe5b0ece7..52734ed98246 100644 --- a/sys/dev/cxgbe/adapter.h +++ b/sys/dev/cxgbe/adapter.h @@ -574,6 +574,7 @@ struct sge_txq { uint64_t txpkts1_wrs; /* # of type1 coalesced tx work requests */ uint64_t txpkts0_pkts; /* # of frames in type0 coalesced tx WRs */ uint64_t txpkts1_pkts; /* # of frames in type1 coalesced tx WRs */ + uint64_t raw_wrs; /* # of raw work requests (alloc_wr_mbuf) */ /* stats for not-that-common events */ } __aligned(CACHE_LINE_SIZE); @@ -1170,6 +1171,7 @@ void t4_intr_err(void *); void t4_intr_evt(void *); void t4_wrq_tx_locked(struct adapter *, struct sge_wrq *, struct wrqe *); void t4_update_fl_bufsize(struct ifnet *); +struct mbuf *alloc_wr_mbuf(int, int); int parse_pkt(struct adapter *, struct mbuf **); void *start_wrq_wr(struct sge_wrq *, int, struct wrq_cookie *); void commit_wrq_wr(struct sge_wrq *, void *, struct wrq_cookie *); diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index 7593f9366f8f..3090bca5565a 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -529,9 +529,9 @@ struct intrs_and_queues { static void setup_memwin(struct adapter *); static void position_memwin(struct adapter *, int, uint32_t); -static int validate_mem_range(struct adapter *, uint32_t, int); +static int validate_mem_range(struct adapter *, uint32_t, uint32_t); static int fwmtype_to_hwmtype(int); -static int validate_mt_off_len(struct adapter *, int, uint32_t, int, +static int validate_mt_off_len(struct adapter *, int, uint32_t, uint32_t, uint32_t *); static int fixup_devlog_params(struct adapter *); static int cfg_itype_and_nqueues(struct adapter *, struct intrs_and_queues *); @@ -2826,14 +2826,14 @@ t4_range_cmp(const void *a, const void *b) * the card's address space. */ static int -validate_mem_range(struct adapter *sc, uint32_t addr, int len) +validate_mem_range(struct adapter *sc, uint32_t addr, uint32_t len) { struct t4_range mem_ranges[4], *r, *next; uint32_t em, addr_len; int i, n, remaining; /* Memory can only be accessed in naturally aligned 4 byte units */ - if (addr & 3 || len & 3 || len <= 0) + if (addr & 3 || len & 3 || len == 0) return (EINVAL); /* Enabled memories */ @@ -2972,7 +2972,7 @@ fwmtype_to_hwmtype(int mtype) * the start of the range is returned in addr. */ static int -validate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, int len, +validate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, uint32_t len, uint32_t *addr) { uint32_t em, addr_len, maddr; @@ -9804,6 +9804,7 @@ t4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, txq->txpkts1_wrs = 0; txq->txpkts0_pkts = 0; txq->txpkts1_pkts = 0; + txq->raw_wrs = 0; mp_ring_reset_stats(txq->r); } diff --git a/sys/dev/cxgbe/t4_sge.c b/sys/dev/cxgbe/t4_sge.c index 643eb29ffb9a..3660e333654e 100644 --- a/sys/dev/cxgbe/t4_sge.c +++ b/sys/dev/cxgbe/t4_sge.c @@ -82,6 +82,9 @@ __FBSDID("$FreeBSD$"); #define RX_COPY_THRESHOLD MINCLSIZE #endif +/* Internal mbuf flags stored in PH_loc.eight[1]. */ +#define MC_RAW_WR 0x02 + /* * Ethernet frames are DMA'd at this byte offset into the freelist buffer. * 0-7 are valid values. @@ -270,6 +273,7 @@ static inline u_int txpkt_len16(u_int, u_int); static inline u_int txpkt_vm_len16(u_int, u_int); static inline u_int txpkts0_len16(u_int); static inline u_int txpkts1_len16(void); +static u_int write_raw_wr(struct sge_txq *, void *, struct mbuf *, u_int); static u_int write_txpkt_wr(struct sge_txq *, struct fw_eth_tx_pkt_wr *, struct mbuf *, u_int); static u_int write_txpkt_vm_wr(struct adapter *, struct sge_txq *, @@ -2196,6 +2200,22 @@ set_mbuf_nsegs(struct mbuf *m, uint8_t nsegs) } static inline int +mbuf_cflags(struct mbuf *m) +{ + + M_ASSERTPKTHDR(m); + return (m->m_pkthdr.PH_loc.eight[4]); +} + +static inline void +set_mbuf_cflags(struct mbuf *m, uint8_t flags) +{ + + M_ASSERTPKTHDR(m); + m->m_pkthdr.PH_loc.eight[4] = flags; +} + +static inline int mbuf_len16(struct mbuf *m) { int n; @@ -2276,6 +2296,31 @@ needs_eo(struct mbuf *m) } #endif +/* + * Try to allocate an mbuf to contain a raw work request. To make it + * easy to construct the work request, don't allocate a chain but a + * single mbuf. + */ +struct mbuf * +alloc_wr_mbuf(int len, int how) +{ + struct mbuf *m; + + if (len <= MHLEN) + m = m_gethdr(how, MT_DATA); + else if (len <= MCLBYTES) + m = m_getcl(how, MT_DATA, M_PKTHDR); + else + m = NULL; + if (m == NULL) + return (NULL); + m->m_pkthdr.len = len; + m->m_len = len; + set_mbuf_cflags(m, MC_RAW_WR); + set_mbuf_len16(m, howmany(len, 16)); + return (m); +} + static inline int needs_tso(struct mbuf *m) { @@ -2449,6 +2494,7 @@ restart: goto restart; } set_mbuf_nsegs(m0, nsegs); + set_mbuf_cflags(m0, 0); if (sc->flags & IS_VF) set_mbuf_len16(m0, txpkt_vm_len16(nsegs, needs_tso(m0))); else @@ -2691,7 +2737,7 @@ cannot_use_txpkts(struct mbuf *m) { /* maybe put a GL limit too, to avoid silliness? */ - return (needs_tso(m)); + return (needs_tso(m) || (mbuf_cflags(m) & MC_RAW_WR) != 0); } static inline int @@ -2701,6 +2747,21 @@ discard_tx(struct sge_eq *eq) return ((eq->flags & (EQ_ENABLED | EQ_QFLUSH)) != EQ_ENABLED); } +static inline int +wr_can_update_eq(struct fw_eth_tx_pkts_wr *wr) +{ + + switch (G_FW_WR_OP(be32toh(wr->op_pkd))) { + case FW_ULPTX_WR: + case FW_ETH_TX_PKT_WR: + case FW_ETH_TX_PKTS_WR: + case FW_ETH_TX_PKT_VM_WR: + return (1); + default: + return (0); + } +} + /* * r->items[cidx] to r->items[pidx], with a wraparound at r->size, are ready to * be consumed. Return the actual number consumed. 0 indicates a stall. @@ -2796,6 +2857,10 @@ eth_tx(struct mp_ring *r, u_int cidx, u_int pidx) n = write_txpkts_wr(txq, wr, m0, &txp, available); total += txp.npkt; remaining -= txp.npkt; + } else if (mbuf_cflags(m0) & MC_RAW_WR) { + total++; + remaining--; + n = write_raw_wr(txq, (void *)wr, m0, available); } else { total++; remaining--; @@ -2808,14 +2873,17 @@ eth_tx(struct mp_ring *r, u_int cidx, u_int pidx) dbdiff += n; IDXINCR(eq->pidx, n, eq->sidx); - if (total_available_tx_desc(eq) < eq->sidx / 4 && - atomic_cmpset_int(&eq->equiq, 0, 1)) { - wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUIQ | - F_FW_WR_EQUEQ); - eq->equeqidx = eq->pidx; - } else if (IDXDIFF(eq->pidx, eq->equeqidx, eq->sidx) >= 32) { - wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUEQ); - eq->equeqidx = eq->pidx; + if (wr_can_update_eq(wr)) { + if (total_available_tx_desc(eq) < eq->sidx / 4 && + atomic_cmpset_int(&eq->equiq, 0, 1)) { + wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUIQ | + F_FW_WR_EQUEQ); + eq->equeqidx = eq->pidx; + } else if (IDXDIFF(eq->pidx, eq->equeqidx, eq->sidx) >= + 32) { + wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUEQ); + eq->equeqidx = eq->pidx; + } } if (dbdiff >= 16 && remaining >= 4) { @@ -4010,6 +4078,8 @@ alloc_txq(struct vi_info *vi, struct sge_txq *txq, int idx, SYSCTL_ADD_UQUAD(&vi->ctx, children, OID_AUTO, "txpkts1_pkts", CTLFLAG_RD, &txq->txpkts1_pkts, "# of frames tx'd using type1 txpkts work requests"); + SYSCTL_ADD_UQUAD(&vi->ctx, children, OID_AUTO, "raw_wrs", CTLFLAG_RD, + &txq->raw_wrs, "# of raw work requests (non-packets)"); SYSCTL_ADD_COUNTER_U64(&vi->ctx, children, OID_AUTO, "r_enqueues", CTLFLAG_RD, &txq->r->enqueues, @@ -4557,6 +4627,39 @@ write_txpkt_vm_wr(struct adapter *sc, struct sge_txq *txq, } /* + * Write a raw WR to the hardware descriptors, update the software + * descriptor, and advance the pidx. It is guaranteed that enough + * descriptors are available. + * + * The return value is the # of hardware descriptors used. + */ +static u_int +write_raw_wr(struct sge_txq *txq, void *wr, struct mbuf *m0, u_int available) +{ + struct sge_eq *eq = &txq->eq; + struct tx_sdesc *txsd; + struct mbuf *m; + caddr_t dst; + int len16, ndesc; + + len16 = mbuf_len16(m0); + ndesc = howmany(len16, EQ_ESIZE / 16); + MPASS(ndesc <= available); + + dst = wr; + for (m = m0; m != NULL; m = m->m_next) + copy_to_txd(eq, mtod(m, caddr_t), &dst, m->m_len); + + txq->raw_wrs++; + + txsd = &txq->sdesc[eq->pidx]; + txsd->m = m0; + txsd->desc_used = ndesc; + + return (ndesc); +} + +/* * Write a txpkt WR for this packet to the hardware descriptors, update the * software descriptor, and advance the pidx. It is guaranteed that enough * descriptors are available. diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c index f94f645b2e39..f0c0d41fa2b1 100644 --- a/sys/dev/hwpmc/hwpmc_mod.c +++ b/sys/dev/hwpmc/hwpmc_mod.c @@ -4949,8 +4949,11 @@ pmc_process_samples(int cpu, ring_type_t ring) /* If there is a pending AST wait for completion */ if (ps->ps_nsamples == PMC_USER_CALLCHAIN_PENDING) { - /* if sample is more than 65 ms old, drop it */ - if (ticks - ps->ps_ticks > (hz >> 4)) { + /* if we've been waiting more than 1 tick to + * collect a callchain for this record then + * drop it and move on. + */ + if (ticks - ps->ps_ticks > 1) { /* * track how often we hit this as it will * preferentially lose user samples diff --git a/sys/dev/mrsas/mrsas.h b/sys/dev/mrsas/mrsas.h index 672b177ba908..280e1ed2f27b 100644 --- a/sys/dev/mrsas/mrsas.h +++ b/sys/dev/mrsas/mrsas.h @@ -612,8 +612,8 @@ typedef union { #define mrsas_atomic_read(v) atomic_load_acq_int(&(v)->val) #define mrsas_atomic_set(v,i) atomic_store_rel_int(&(v)->val, i) -#define mrsas_atomic_dec(v) atomic_fetchadd_int(&(v)->val, -1) -#define mrsas_atomic_inc(v) atomic_fetchadd_int(&(v)->val, 1) +#define mrsas_atomic_dec(v) atomic_subtract_int(&(v)->val, 1) +#define mrsas_atomic_inc(v) atomic_add_int(&(v)->val, 1) /* IOCInit Request message */ typedef struct _MPI2_IOC_INIT_REQUEST { diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c index 6c7b52fe76a6..35ce4eee52df 100644 --- a/sys/dev/usb/controller/dwc_otg.c +++ b/sys/dev/usb/controller/dwc_otg.c @@ -1432,6 +1432,19 @@ dwc_otg_host_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) goto receive_pkt; } } else if (td->ep_type == UE_ISOCHRONOUS) { + if (td->hcsplt != 0) { + /* + * Sometimes the complete + * split packet may be queued + * too early and the + * transaction translator will + * return a NAK. Ignore + * this message and retry the + * complete split instead. + */ + DPRINTF("Retrying complete split\n"); + goto receive_pkt; + } goto complete; } td->did_nak = 1; diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index 96f93c060aba..d3587e89c552 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -1238,8 +1238,7 @@ nfs_mount(struct mount *mp) bzero(&hst[hstlen], MNAMELEN - hstlen); args.hostname = hst; /* getsockaddr() call must be after above copyin() calls */ - error = getsockaddr(&nam, (caddr_t)args.addr, - args.addrlen); + error = getsockaddr(&nam, args.addr, args.addrlen); if (error != 0) goto out; } else if (nfs_mount_parse_from(mp->mnt_optnew, diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 47fd735d3b9e..7f9eb26e6ad3 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -3030,16 +3030,16 @@ nfs_advlock(struct vop_advlock_args *ap) struct proc *p = (struct proc *)ap->a_id; struct thread *td = curthread; /* XXX */ struct vattr va; - int ret, error = EOPNOTSUPP; + int ret, error; u_quad_t size; - ret = NFSVOPLOCK(vp, LK_SHARED); - if (ret != 0) + error = NFSVOPLOCK(vp, LK_SHARED); + if (error != 0) return (EBADF); if (NFS_ISV4(vp) && (ap->a_flags & (F_POSIX | F_FLOCK)) != 0) { if (vp->v_type != VREG) { - NFSVOPUNLOCK(vp, 0); - return (EINVAL); + error = EINVAL; + goto out; } if ((ap->a_flags & F_POSIX) != 0) cred = p->p_ucred; @@ -3047,8 +3047,8 @@ nfs_advlock(struct vop_advlock_args *ap) cred = td->td_ucred; NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); if (vp->v_iflag & VI_DOOMED) { - NFSVOPUNLOCK(vp, 0); - return (EBADF); + error = EBADF; + goto out; } /* @@ -3077,21 +3077,21 @@ nfs_advlock(struct vop_advlock_args *ap) return (EINTR); NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); if (vp->v_iflag & VI_DOOMED) { - NFSVOPUNLOCK(vp, 0); - return (EBADF); + error = EBADF; + goto out; } } } while (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) && ap->a_op == F_SETLK); if (ret == NFSERR_DENIED) { - NFSVOPUNLOCK(vp, 0); - return (EAGAIN); + error = EAGAIN; + goto out; } else if (ret == EINVAL || ret == EBADF || ret == EINTR) { - NFSVOPUNLOCK(vp, 0); - return (ret); + error = ret; + goto out; } else if (ret != 0) { - NFSVOPUNLOCK(vp, 0); - return (EACCES); + error = EACCES; + goto out; } /* @@ -3121,8 +3121,6 @@ nfs_advlock(struct vop_advlock_args *ap) np->n_flag |= NHASBEENLOCKED; mtx_unlock(&np->n_mtx); } - NFSVOPUNLOCK(vp, 0); - return (0); } else if (!NFS_ISV4(vp)) { if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) { size = VTONFS(vp)->n_size; @@ -3146,8 +3144,11 @@ nfs_advlock(struct vop_advlock_args *ap) NFSVOPUNLOCK(vp, 0); } } + return (error); } else - NFSVOPUNLOCK(vp, 0); + error = EOPNOTSUPP; +out: + NFSVOPUNLOCK(vp, 0); return (error); } diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c index 9797884252ef..8a35b1e57d00 100644 --- a/sys/geom/geom_io.c +++ b/sys/geom/geom_io.c @@ -420,6 +420,8 @@ g_io_check(struct bio *bp) return (EIO); if (bp->bio_offset > pp->mediasize) return (EIO); + if (bp->bio_offset == pp->mediasize && bp->bio_length > 0) + return (EIO); /* Truncate requests to the end of providers media. */ excess = bp->bio_offset + bp->bio_length; diff --git a/sys/i386/include/cpu.h b/sys/i386/include/cpu.h index 8cd94fa7e1ff..8ba5e455f714 100644 --- a/sys/i386/include/cpu.h +++ b/sys/i386/include/cpu.h @@ -72,6 +72,7 @@ extern char btext[]; extern char etext[]; void cpu_halt(void); +void cpu_lock_delay(void); void cpu_reset(void); void fork_trampoline(void); void swi_vm(void *); diff --git a/sys/kern/capabilities.conf b/sys/kern/capabilities.conf index 7857d0862295..b5198b7a341c 100644 --- a/sys/kern/capabilities.conf +++ b/sys/kern/capabilities.conf @@ -486,9 +486,9 @@ pipe2 ## ## Allow poll(2), which will be scoped by capability rights. -## XXXRW: We don't yet do that scoping. ## poll +ppoll ## ## Allow I/O-related file descriptors, subject to capability rights. diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 885b5dc6f030..a567d0d83d95 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -594,7 +594,7 @@ struct sysent sysent[] = { { AS(pipe2_args), (sy_call_t *)sys_pipe2, AUE_PIPE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 542 = pipe2 */ { AS(aio_mlock_args), (sy_call_t *)sys_aio_mlock, AUE_AIO_MLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 543 = aio_mlock */ { AS(procctl_args), (sy_call_t *)sys_procctl, AUE_PROCCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 544 = procctl */ - { AS(ppoll_args), (sy_call_t *)sys_ppoll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 545 = ppoll */ + { AS(ppoll_args), (sy_call_t *)sys_ppoll, AUE_POLL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 545 = ppoll */ { AS(futimens_args), (sy_call_t *)sys_futimens, AUE_FUTIMES, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 546 = futimens */ { AS(utimensat_args), (sy_call_t *)sys_utimensat, AUE_FUTIMESAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 547 = utimensat */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 548 = obsolete numa_getaffinity */ diff --git a/sys/kern/kern_mutex.c b/sys/kern/kern_mutex.c index c3f566dd0279..65c2e299bbc7 100644 --- a/sys/kern/kern_mutex.c +++ b/sys/kern/kern_mutex.c @@ -1206,7 +1206,7 @@ _mtx_lock_indefinite_check(struct mtx *m, struct lock_delay_arg *ldap) ldap->spin_cnt++; if (ldap->spin_cnt < 60000000 || kdb_active || panicstr != NULL) - DELAY(1); + cpu_lock_delay(); else { td = mtx_owner(m); diff --git a/sys/kern/kern_ubsan.c b/sys/kern/kern_ubsan.c new file mode 100644 index 000000000000..d6d60c5fa89e --- /dev/null +++ b/sys/kern/kern_ubsan.c @@ -0,0 +1,1650 @@ +/* $NetBSD: ubsan.c,v 1.3 2018/08/03 16:31:04 kamil Exp $ */ + +/*- + * Copyright (c) 2018 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/* + * The micro UBSan implementation for the userland (uUBSan) and kernel (kUBSan). + * The uBSSan versions is suitable for inclusion into libc or used standalone + * with ATF tests. + * + * This file due to long symbol names generated by a compiler during the + * instrumentation process does not follow the KNF style with 80-column limit. + */ + +#include <sys/cdefs.h> +#ifdef __FreeBSD__ +__FBSDID("$FreeBSD$"); +#else +#if defined(_KERNEL) +__KERNEL_RCSID(0, "$NetBSD: ubsan.c,v 1.3 2018/08/03 16:31:04 kamil Exp $"); +#else +__RCSID("$NetBSD: ubsan.c,v 1.3 2018/08/03 16:31:04 kamil Exp $"); +#endif +#endif + +#if defined(_KERNEL) +#include <sys/param.h> +#include <sys/types.h> +#include <sys/limits.h> +#include <sys/systm.h> +#include <machine/_inttypes.h> +#include <machine/stdarg.h> +#define ASSERT(x) KASSERT(x, ("%s: " __STRING(x) " failed", __func__)) +#define __arraycount(x) nitems(x) +#define ISSET(x, y) ((x) & (y)) +#define __BIT(x) ((uintmax_t)1 << (uintmax_t)(x)) +#define __LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask)) +#define __SHIFTOUT(__x, __mask) (((__x) & (__mask)) / __LOWEST_SET_BIT(__mask)) +#else +#if defined(_LIBC) +#include "namespace.h" +#endif +#include <sys/param.h> +#include <assert.h> +#include <inttypes.h> +#include <math.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#if defined(_LIBC) +#include "extern.h" +#define ubsan_vsyslog vsyslog_ss +#define ASSERT(x) _DIAGASSERT(x) +#else +#define ubsan_vsyslog vsyslog_r +#define ASSERT(x) assert(x) +#endif +/* These macros are available in _KERNEL only */ +#define SET(t, f) ((t) |= (f)) +#define ISSET(t, f) ((t) & (f)) +#define CLR(t, f) ((t) &= ~(f)) +#endif + +#define REINTERPRET_CAST(__dt, __st) ((__dt)(__st)) +#define STATIC_CAST(__dt, __st) ((__dt)(__st)) + +#define ACK_REPORTED __BIT(31) + +#define MUL_STRING "*" +#define PLUS_STRING "+" +#define MINUS_STRING "-" +#define DIVREM_STRING "divrem" + +#define CFI_VCALL 0 +#define CFI_NVCALL 1 +#define CFI_DERIVEDCAST 2 +#define CFI_UNRELATEDCAST 3 +#define CFI_ICALL 4 +#define CFI_NVMFCALL 5 +#define CFI_VMFCALL 6 + +#define NUMBER_MAXLEN 128 +#define LOCATION_MAXLEN (PATH_MAX + 32 /* ':LINE:COLUMN' */) + +#define WIDTH_8 8 +#define WIDTH_16 16 +#define WIDTH_32 32 +#define WIDTH_64 64 +#define WIDTH_80 80 +#define WIDTH_96 96 +#define WIDTH_128 128 + +#define NUMBER_SIGNED_BIT 1U + +#if __SIZEOF_INT128__ +typedef __int128 longest; +typedef unsigned __int128 ulongest; +#else +typedef int64_t longest; +typedef uint64_t ulongest; +#endif + +#ifndef _KERNEL +static int ubsan_flags = -1; +#define UBSAN_ABORT __BIT(0) +#define UBSAN_STDOUT __BIT(1) +#define UBSAN_STDERR __BIT(2) +#define UBSAN_SYSLOG __BIT(3) +#endif + +/* Undefined Behavior specific defines and structures */ + +#define KIND_INTEGER 0 +#define KIND_FLOAT 1 +#define KIND_UNKNOWN UINT16_MAX + +struct CSourceLocation { + char *mFilename; + uint32_t mLine; + uint32_t mColumn; +}; + +struct CTypeDescriptor { + uint16_t mTypeKind; + uint16_t mTypeInfo; + uint8_t mTypeName[1]; +}; + +struct COverflowData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; +}; + +struct CUnreachableData { + struct CSourceLocation mLocation; +}; + +struct CCFICheckFailData { + uint8_t mCheckKind; + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; +}; + +struct CDynamicTypeCacheMissData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; + void *mTypeInfo; + uint8_t mTypeCheckKind; +}; + +struct CFunctionTypeMismatchData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; +}; + +struct CInvalidBuiltinData { + struct CSourceLocation mLocation; + uint8_t mKind; +}; + +struct CInvalidValueData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; +}; + +struct CNonNullArgData { + struct CSourceLocation mLocation; + struct CSourceLocation mAttributeLocation; + int mArgIndex; +}; + +struct CNonNullReturnData { + struct CSourceLocation mAttributeLocation; +}; + +struct COutOfBoundsData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mArrayType; + struct CTypeDescriptor *mIndexType; +}; + +struct CPointerOverflowData { + struct CSourceLocation mLocation; +}; + +struct CShiftOutOfBoundsData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mLHSType; + struct CTypeDescriptor *mRHSType; +}; + +struct CTypeMismatchData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; + unsigned long mLogAlignment; + uint8_t mTypeCheckKind; +}; + +struct CTypeMismatchData_v1 { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; + uint8_t mLogAlignment; + uint8_t mTypeCheckKind; +}; + +struct CVLABoundData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; +}; + +struct CFloatCastOverflowData { + struct CSourceLocation mLocation; /* This field exists in this struct since 2015 August 11th */ + struct CTypeDescriptor *mFromType; + struct CTypeDescriptor *mToType; +}; + +/* Local utility functions */ +static void Report(bool isFatal, const char *pFormat, ...) __printflike(2, 3); +static bool isAlreadyReported(struct CSourceLocation *pLocation); +static size_t zDeserializeTypeWidth(struct CTypeDescriptor *pType); +static void DeserializeLocation(char *pBuffer, size_t zBUfferLength, struct CSourceLocation *pLocation); +#ifdef __SIZEOF_INT128__ +static void DeserializeUINT128(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, __uint128_t U128); +#endif +static void DeserializeNumberSigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, longest L); +static void DeserializeNumberUnsigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, ulongest L); +#ifndef _KERNEL +static void DeserializeFloatOverPointer(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long *pNumber); +static void DeserializeFloatInlined(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber); +#endif +static longest llliGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber); +static ulongest llluGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber); +#ifndef _KERNEL +static void DeserializeNumberFloat(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber); +#endif +static void DeserializeNumber(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber); +static const char *DeserializeTypeCheckKind(uint8_t hhuTypeCheckKind); +static const char *DeserializeBuiltinCheckKind(uint8_t hhuBuiltinCheckKind); +static const char *DeserializeCFICheckKind(uint8_t hhuCFICheckKind); +static bool isNegativeNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber); +static bool isShiftExponentTooLarge(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber, size_t zWidth); + +/* Unused in this implementation, emitted by the C++ check dynamic type cast. */ +intptr_t __ubsan_vptr_type_cache[128]; + +/* Public symbols used in the instrumentation of the code generation part */ +void __ubsan_handle_add_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_add_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_builtin_unreachable(struct CUnreachableData *pData); +void __ubsan_handle_cfi_bad_type(struct CCFICheckFailData *pData, unsigned long ulVtable, bool bValidVtable, bool FromUnrecoverableHandler, unsigned long ProgramCounter, unsigned long FramePointer); +void __ubsan_handle_cfi_check_fail(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable); +void __ubsan_handle_cfi_check_fail_abort(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable); +void __ubsan_handle_divrem_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_divrem_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_dynamic_type_cache_miss(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash); +void __ubsan_handle_dynamic_type_cache_miss_abort(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash); +void __ubsan_handle_float_cast_overflow(struct CFloatCastOverflowData *pData, unsigned long ulFrom); +void __ubsan_handle_float_cast_overflow_abort(struct CFloatCastOverflowData *pData, unsigned long ulFrom); +void __ubsan_handle_function_type_mismatch(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction); +void __ubsan_handle_function_type_mismatch_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction); +void __ubsan_handle_invalid_builtin(struct CInvalidBuiltinData *pData); +void __ubsan_handle_invalid_builtin_abort(struct CInvalidBuiltinData *pData); +void __ubsan_handle_load_invalid_value(struct CInvalidValueData *pData, unsigned long ulVal); +void __ubsan_handle_load_invalid_value_abort(struct CInvalidValueData *pData, unsigned long ulVal); +void __ubsan_handle_missing_return(struct CUnreachableData *pData); +void __ubsan_handle_mul_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_mul_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_negate_overflow(struct COverflowData *pData, unsigned long ulOldVal); +void __ubsan_handle_negate_overflow_abort(struct COverflowData *pData, unsigned long ulOldVal); +void __ubsan_handle_nonnull_arg(struct CNonNullArgData *pData); +void __ubsan_handle_nonnull_arg_abort(struct CNonNullArgData *pData); +void __ubsan_handle_nonnull_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer); +void __ubsan_handle_nonnull_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer); +void __ubsan_handle_nullability_arg(struct CNonNullArgData *pData); +void __ubsan_handle_nullability_arg_abort(struct CNonNullArgData *pData); +void __ubsan_handle_nullability_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer); +void __ubsan_handle_nullability_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer); +void __ubsan_handle_out_of_bounds(struct COutOfBoundsData *pData, unsigned long ulIndex); +void __ubsan_handle_out_of_bounds_abort(struct COutOfBoundsData *pData, unsigned long ulIndex); +void __ubsan_handle_pointer_overflow(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult); +void __ubsan_handle_pointer_overflow_abort(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult); +void __ubsan_handle_shift_out_of_bounds(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_shift_out_of_bounds_abort(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_sub_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_sub_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_type_mismatch(struct CTypeMismatchData *pData, unsigned long ulPointer); +void __ubsan_handle_type_mismatch_abort(struct CTypeMismatchData *pData, unsigned long ulPointer); +void __ubsan_handle_type_mismatch_v1(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer); +void __ubsan_handle_type_mismatch_v1_abort(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer); +void __ubsan_handle_vla_bound_not_positive(struct CVLABoundData *pData, unsigned long ulBound); +void __ubsan_handle_vla_bound_not_positive_abort(struct CVLABoundData *pData, unsigned long ulBound); +void __ubsan_get_current_report_data(const char **ppOutIssueKind, const char **ppOutMessage, const char **ppOutFilename, uint32_t *pOutLine, uint32_t *pOutCol, char **ppOutMemoryAddr); + +static void HandleOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS, const char *szOperation); +static void HandleNegateOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulOldValue); +static void HandleBuiltinUnreachable(bool isFatal, struct CUnreachableData *pData); +static void HandleTypeMismatch(bool isFatal, struct CSourceLocation *mLocation, struct CTypeDescriptor *mType, unsigned long mLogAlignment, uint8_t mTypeCheckKind, unsigned long ulPointer); +static void HandleVlaBoundNotPositive(bool isFatal, struct CVLABoundData *pData, unsigned long ulBound); +static void HandleOutOfBounds(bool isFatal, struct COutOfBoundsData *pData, unsigned long ulIndex); +static void HandleShiftOutOfBounds(bool isFatal, struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS); +static void HandleLoadInvalidValue(bool isFatal, struct CInvalidValueData *pData, unsigned long ulValue); +static void HandleInvalidBuiltin(bool isFatal, struct CInvalidBuiltinData *pData); +static void HandleFunctionTypeMismatch(bool isFatal, struct CFunctionTypeMismatchData *pData, unsigned long ulFunction); +static void HandleCFIBadType(bool isFatal, struct CCFICheckFailData *pData, unsigned long ulVtable, bool *bValidVtable, bool *FromUnrecoverableHandler, unsigned long *ProgramCounter, unsigned long *FramePointer); +static void HandleDynamicTypeCacheMiss(bool isFatal, struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash); +static void HandleFloatCastOverflow(bool isFatal, struct CFloatCastOverflowData *pData, unsigned long ulFrom); +static void HandleMissingReturn(bool isFatal, struct CUnreachableData *pData); +static void HandleNonnullArg(bool isFatal, struct CNonNullArgData *pData); +static void HandleNonnullReturn(bool isFatal, struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer); +static void HandlePointerOverflow(bool isFatal, struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult); + +static void +HandleOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS, const char *szOperation) +{ + char szLocation[LOCATION_MAXLEN]; + char szLHS[NUMBER_MAXLEN]; + char szRHS[NUMBER_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + DeserializeNumber(szLocation, szLHS, NUMBER_MAXLEN, pData->mType, ulLHS); + DeserializeNumber(szLocation, szRHS, NUMBER_MAXLEN, pData->mType, ulRHS); + + Report(isFatal, "UBSan: Undefined Behavior in %s, %s integer overflow: %s %s %s cannot be represented in type %s\n", + szLocation, ISSET(pData->mType->mTypeInfo, NUMBER_SIGNED_BIT) ? "signed" : "unsigned", szLHS, szOperation, szRHS, pData->mType->mTypeName); +} + +static void +HandleNegateOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulOldValue) +{ + char szLocation[LOCATION_MAXLEN]; + char szOldValue[NUMBER_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + DeserializeNumber(szLocation, szOldValue, NUMBER_MAXLEN, pData->mType, ulOldValue); + + Report(isFatal, "UBSan: Undefined Behavior in %s, negation of %s cannot be represented in type %s\n", + szLocation, szOldValue, pData->mType->mTypeName); +} + +static void +HandleBuiltinUnreachable(bool isFatal, struct CUnreachableData *pData) +{ + char szLocation[LOCATION_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + + Report(isFatal, "UBSan: Undefined Behavior in %s, calling __builtin_unreachable()\n", + szLocation); +} + +static void +HandleTypeMismatch(bool isFatal, struct CSourceLocation *mLocation, struct CTypeDescriptor *mType, unsigned long mLogAlignment, uint8_t mTypeCheckKind, unsigned long ulPointer) +{ + char szLocation[LOCATION_MAXLEN]; + + ASSERT(mLocation); + ASSERT(mType); + + if (isAlreadyReported(mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, mLocation); + + if (ulPointer == 0) { + Report(isFatal, "UBSan: Undefined Behavior in %s, %s null pointer of type %s\n", + szLocation, DeserializeTypeCheckKind(mTypeCheckKind), mType->mTypeName); + } else if ((mLogAlignment - 1) & ulPointer) { + Report(isFatal, "UBSan: Undefined Behavior in %s, %s misaligned address %p for type %s which requires %ld byte alignment\n", + szLocation, DeserializeTypeCheckKind(mTypeCheckKind), REINTERPRET_CAST(void *, ulPointer), mType->mTypeName, mLogAlignment); + } else { + Report(isFatal, "UBSan: Undefined Behavior in %s, %s address %p with insufficient space for an object of type %s\n", + szLocation, DeserializeTypeCheckKind(mTypeCheckKind), REINTERPRET_CAST(void *, ulPointer), mType->mTypeName); + } +} + +static void +HandleVlaBoundNotPositive(bool isFatal, struct CVLABoundData *pData, unsigned long ulBound) +{ + char szLocation[LOCATION_MAXLEN]; + char szBound[NUMBER_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + DeserializeNumber(szLocation, szBound, NUMBER_MAXLEN, pData->mType, ulBound); + + Report(isFatal, "UBSan: Undefined Behavior in %s, variable length array bound value %s <= 0\n", + szLocation, szBound); +} + +static void +HandleOutOfBounds(bool isFatal, struct COutOfBoundsData *pData, unsigned long ulIndex) +{ + char szLocation[LOCATION_MAXLEN]; + char szIndex[NUMBER_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + DeserializeNumber(szLocation, szIndex, NUMBER_MAXLEN, pData->mIndexType, ulIndex); + + Report(isFatal, "UBSan: Undefined Behavior in %s, index %s is out of range for type %s\n", + szLocation, szIndex, pData->mArrayType->mTypeName); +} + +static void +HandleShiftOutOfBounds(bool isFatal, struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + char szLocation[LOCATION_MAXLEN]; + char szLHS[NUMBER_MAXLEN]; + char szRHS[NUMBER_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + DeserializeNumber(szLocation, szLHS, NUMBER_MAXLEN, pData->mLHSType, ulLHS); + DeserializeNumber(szLocation, szRHS, NUMBER_MAXLEN, pData->mRHSType, ulRHS); + + if (isNegativeNumber(szLocation, pData->mRHSType, ulRHS)) + Report(isFatal, "UBSan: Undefined Behavior in %s, shift exponent %s is negative\n", + szLocation, szRHS); + else if (isShiftExponentTooLarge(szLocation, pData->mRHSType, ulRHS, zDeserializeTypeWidth(pData->mLHSType))) + Report(isFatal, "UBSan: Undefined Behavior in %s, shift exponent %s is too large for %zu-bit type %s\n", + szLocation, szRHS, zDeserializeTypeWidth(pData->mLHSType), pData->mLHSType->mTypeName); + else if (isNegativeNumber(szLocation, pData->mLHSType, ulLHS)) + Report(isFatal, "UBSan: Undefined Behavior in %s, left shift of negative value %s\n", + szLocation, szLHS); + else + Report(isFatal, "UBSan: Undefined Behavior in %s, left shift of %s by %s places cannot be represented in type %s\n", + szLocation, szLHS, szRHS, pData->mLHSType->mTypeName); +} + +static void +HandleLoadInvalidValue(bool isFatal, struct CInvalidValueData *pData, unsigned long ulValue) +{ + char szLocation[LOCATION_MAXLEN]; + char szValue[NUMBER_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + DeserializeNumber(szLocation, szValue, NUMBER_MAXLEN, pData->mType, ulValue); + + Report(isFatal, "UBSan: Undefined Behavior in %s, load of value %s is not a valid value for type %s\n", + szLocation, szValue, pData->mType->mTypeName); +} + +static void +HandleInvalidBuiltin(bool isFatal, struct CInvalidBuiltinData *pData) +{ + char szLocation[LOCATION_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + + Report(isFatal, "UBSan: Undefined Behavior in %s, passing zero to %s, which is not a valid argument\n", + szLocation, DeserializeBuiltinCheckKind(pData->mKind)); +} + +static void +HandleFunctionTypeMismatch(bool isFatal, struct CFunctionTypeMismatchData *pData, unsigned long ulFunction) +{ + char szLocation[LOCATION_MAXLEN]; + + /* + * There is no a portable C solution to translate an address of a + * function to its name. On the cost of getting this routine simple + * and portable without ifdefs between the userland and the kernel + * just print the address of the function as-is. + * + * For better diagnostic messages in the userland, users shall use + * the full upstream version shipped along with the compiler toolchain. + */ + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + + Report(isFatal, "UBSan: Undefined Behavior in %s, call to function %#lx through pointer to incorrect function type %s\n", + szLocation, ulFunction, pData->mType->mTypeName); +} + +static void +HandleCFIBadType(bool isFatal, struct CCFICheckFailData *pData, unsigned long ulVtable, bool *bValidVtable, bool *FromUnrecoverableHandler, unsigned long *ProgramCounter, unsigned long *FramePointer) +{ + char szLocation[LOCATION_MAXLEN]; + + /* + * This is a minimal implementation without diving into C++ + * specifics and (Itanium) ABI deserialization. + */ + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + + if (pData->mCheckKind == CFI_ICALL || pData->mCheckKind == CFI_VMFCALL) { + Report(isFatal, "UBSan: Undefined Behavior in %s, control flow integrity check for type %s failed during %s (vtable address %#lx)\n", + szLocation, pData->mType->mTypeName, DeserializeCFICheckKind(pData->mCheckKind), ulVtable); + } else { + Report(isFatal || FromUnrecoverableHandler, "UBSan: Undefined Behavior in %s, control flow integrity check for type %s failed during %s (vtable address %#lx; %s vtable; from %s handler; Program Counter %#lx; Frame Pointer %#lx)\n", + szLocation, pData->mType->mTypeName, DeserializeCFICheckKind(pData->mCheckKind), ulVtable, *bValidVtable ? "valid" : "invalid", *FromUnrecoverableHandler ? "unrecoverable" : "recoverable", *ProgramCounter, *FramePointer); + } +} + +static void +HandleDynamicTypeCacheMiss(bool isFatal, struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash) +{ +#if 0 + char szLocation[LOCATION_MAXLEN]; + + /* + * Unimplemented. + * + * This UBSan handler is special as the check has to be impelemented + * in an implementation. In order to handle it there is need to + * introspect into C++ ABI internals (RTTI) and use low-level + * C++ runtime interfaces. + */ + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + + Report(isFatal, "UBSan: Undefined Behavior in %s, %s address %#lx which might not point to an object of type %s\n" + szLocation, DeserializeTypeCheckKind(pData->mTypeCheckKind), ulPointer, pData->mType); +#endif +} + +static void +HandleFloatCastOverflow(bool isFatal, struct CFloatCastOverflowData *pData, unsigned long ulFrom) +{ + char szLocation[LOCATION_MAXLEN]; + char szFrom[NUMBER_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + DeserializeNumber(szLocation, szFrom, NUMBER_MAXLEN, pData->mFromType, ulFrom); + + Report(isFatal, "UBSan: Undefined Behavior in %s, %s (of type %s) is outside the range of representable values of type %s\n", + szLocation, szFrom, pData->mFromType->mTypeName, pData->mToType->mTypeName); +} + +static void +HandleMissingReturn(bool isFatal, struct CUnreachableData *pData) +{ + char szLocation[LOCATION_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + + Report(isFatal, "UBSan: Undefined Behavior in %s, execution reached the end of a value-returning function without returning a value\n", + szLocation); +} + +static void +HandleNonnullArg(bool isFatal, struct CNonNullArgData *pData) +{ + char szLocation[LOCATION_MAXLEN]; + char szAttributeLocation[LOCATION_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + if (pData->mAttributeLocation.mFilename) + DeserializeLocation(szAttributeLocation, LOCATION_MAXLEN, &pData->mAttributeLocation); + else + szAttributeLocation[0] = '\0'; + + Report(isFatal, "UBSan: Undefined Behavior in %s, null pointer passed as argument %d, which is declared to never be null%s%s\n", + szLocation, pData->mArgIndex, pData->mAttributeLocation.mFilename ? ", nonnull/_Nonnull specified in " : "", szAttributeLocation); +} + +static void +HandleNonnullReturn(bool isFatal, struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer) +{ + char szLocation[LOCATION_MAXLEN]; + char szAttributeLocation[LOCATION_MAXLEN]; + + ASSERT(pData); + ASSERT(pLocationPointer); + + if (isAlreadyReported(pLocationPointer)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, pLocationPointer); + if (pData->mAttributeLocation.mFilename) + DeserializeLocation(szAttributeLocation, LOCATION_MAXLEN, &pData->mAttributeLocation); + else + szAttributeLocation[0] = '\0'; + + Report(isFatal, "UBSan: Undefined Behavior in %s, null pointer returned from function declared to never return null%s%s\n", + szLocation, pData->mAttributeLocation.mFilename ? ", nonnull/_Nonnull specified in " : "", szAttributeLocation); +} + +static void +HandlePointerOverflow(bool isFatal, struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult) +{ + char szLocation[LOCATION_MAXLEN]; + + ASSERT(pData); + + if (isAlreadyReported(&pData->mLocation)) + return; + + DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation); + + Report(isFatal, "UBSan: Undefined Behavior in %s, pointer expression with base %#lx overflowed to %#lx\n", + szLocation, ulBase, ulResult); +} + +/* Definions of public symbols emitted by the instrumentation code */ +void +__ubsan_handle_add_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + + ASSERT(pData); + + HandleOverflow(false, pData, ulLHS, ulRHS, PLUS_STRING); +} + +void +__ubsan_handle_add_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + + ASSERT(pData); + + HandleOverflow(true, pData, ulLHS, ulRHS, PLUS_STRING); +} + +void +__ubsan_handle_builtin_unreachable(struct CUnreachableData *pData) +{ + + ASSERT(pData); + + HandleBuiltinUnreachable(true, pData); +} + +void +__ubsan_handle_cfi_bad_type(struct CCFICheckFailData *pData, unsigned long ulVtable, bool bValidVtable, bool FromUnrecoverableHandler, unsigned long ProgramCounter, unsigned long FramePointer) +{ + + ASSERT(pData); + + HandleCFIBadType(false, pData, ulVtable, &bValidVtable, &FromUnrecoverableHandler, &ProgramCounter, &FramePointer); +} + +void +__ubsan_handle_cfi_check_fail(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable) +{ + + ASSERT(pData); + + HandleCFIBadType(false, pData, ulValue, 0, 0, 0, 0); +} + +void +__ubsan_handle_cfi_check_fail_abort(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable) +{ + + ASSERT(pData); + + HandleCFIBadType(true, pData, ulValue, 0, 0, 0, 0); +} + +void +__ubsan_handle_divrem_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + + ASSERT(pData); + + HandleOverflow(false, pData, ulLHS, ulRHS, DIVREM_STRING); +} + +void +__ubsan_handle_divrem_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + + ASSERT(pData); + + HandleOverflow(true, pData, ulLHS, ulRHS, DIVREM_STRING); +} + +void +__ubsan_handle_dynamic_type_cache_miss(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash) +{ + + ASSERT(pData); + + HandleDynamicTypeCacheMiss(false, pData, ulPointer, ulHash); +} + +void +__ubsan_handle_dynamic_type_cache_miss_abort(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash) +{ + + ASSERT(pData); + + HandleDynamicTypeCacheMiss(false, pData, ulPointer, ulHash); +} + +void +__ubsan_handle_float_cast_overflow(struct CFloatCastOverflowData *pData, unsigned long ulFrom) +{ + + ASSERT(pData); + + HandleFloatCastOverflow(false, pData, ulFrom); +} + +void +__ubsan_handle_float_cast_overflow_abort(struct CFloatCastOverflowData *pData, unsigned long ulFrom) +{ + + ASSERT(pData); + + HandleFloatCastOverflow(true, pData, ulFrom); +} + +void +__ubsan_handle_function_type_mismatch(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction) +{ + + ASSERT(pData); + + HandleFunctionTypeMismatch(false, pData, ulFunction); +} + +void +__ubsan_handle_function_type_mismatch_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction) +{ + + ASSERT(pData); + + HandleFunctionTypeMismatch(false, pData, ulFunction); +} + +void +__ubsan_handle_invalid_builtin(struct CInvalidBuiltinData *pData) +{ + + ASSERT(pData); + + HandleInvalidBuiltin(true, pData); +} + +void +__ubsan_handle_invalid_builtin_abort(struct CInvalidBuiltinData *pData) +{ + + ASSERT(pData); + + HandleInvalidBuiltin(true, pData); +} + +void +__ubsan_handle_load_invalid_value(struct CInvalidValueData *pData, unsigned long ulValue) +{ + + ASSERT(pData); + + HandleLoadInvalidValue(false, pData, ulValue); +} + +void +__ubsan_handle_load_invalid_value_abort(struct CInvalidValueData *pData, unsigned long ulValue) +{ + + ASSERT(pData); + + HandleLoadInvalidValue(true, pData, ulValue); +} + +void +__ubsan_handle_missing_return(struct CUnreachableData *pData) +{ + + ASSERT(pData); + + HandleMissingReturn(true, pData); +} + +void +__ubsan_handle_mul_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + + ASSERT(pData); + + HandleOverflow(false, pData, ulLHS, ulRHS, MUL_STRING); +} + +void +__ubsan_handle_mul_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + + ASSERT(pData); + + HandleOverflow(true, pData, ulLHS, ulRHS, MUL_STRING); +} + +void +__ubsan_handle_negate_overflow(struct COverflowData *pData, unsigned long ulOldValue) +{ + + ASSERT(pData); + + HandleNegateOverflow(false, pData, ulOldValue); +} + +void +__ubsan_handle_negate_overflow_abort(struct COverflowData *pData, unsigned long ulOldValue) +{ + + ASSERT(pData); + + HandleNegateOverflow(true, pData, ulOldValue); +} + +void +__ubsan_handle_nonnull_arg(struct CNonNullArgData *pData) +{ + + ASSERT(pData); + + HandleNonnullArg(false, pData); +} + +void +__ubsan_handle_nonnull_arg_abort(struct CNonNullArgData *pData) +{ + + ASSERT(pData); + + HandleNonnullArg(true, pData); +} + +void +__ubsan_handle_nonnull_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer) +{ + + ASSERT(pData); + ASSERT(pLocationPointer); + + HandleNonnullReturn(false, pData, pLocationPointer); +} + +void +__ubsan_handle_nonnull_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer) +{ + + ASSERT(pData); + ASSERT(pLocationPointer); + + HandleNonnullReturn(true, pData, pLocationPointer); +} + +void +__ubsan_handle_nullability_arg(struct CNonNullArgData *pData) +{ + + ASSERT(pData); + + HandleNonnullArg(false, pData); +} + +void +__ubsan_handle_nullability_arg_abort(struct CNonNullArgData *pData) +{ + + ASSERT(pData); + + HandleNonnullArg(true, pData); +} + +void +__ubsan_handle_nullability_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer) +{ + + ASSERT(pData); + ASSERT(pLocationPointer); + + HandleNonnullReturn(false, pData, pLocationPointer); +} + +void +__ubsan_handle_nullability_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer) +{ + + ASSERT(pData); + ASSERT(pLocationPointer); + + HandleNonnullReturn(true, pData, pLocationPointer); +} + +void +__ubsan_handle_out_of_bounds(struct COutOfBoundsData *pData, unsigned long ulIndex) +{ + + ASSERT(pData); + + HandleOutOfBounds(false, pData, ulIndex); +} + +void +__ubsan_handle_out_of_bounds_abort(struct COutOfBoundsData *pData, unsigned long ulIndex) +{ + + ASSERT(pData); + + HandleOutOfBounds(true, pData, ulIndex); +} + +void +__ubsan_handle_pointer_overflow(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult) +{ + + ASSERT(pData); + + HandlePointerOverflow(false, pData, ulBase, ulResult); +} + +void +__ubsan_handle_pointer_overflow_abort(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult) +{ + + ASSERT(pData); + + HandlePointerOverflow(true, pData, ulBase, ulResult); +} + +void +__ubsan_handle_shift_out_of_bounds(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + + ASSERT(pData); + + HandleShiftOutOfBounds(false, pData, ulLHS, ulRHS); +} + +void +__ubsan_handle_shift_out_of_bounds_abort(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + + ASSERT(pData); + + HandleShiftOutOfBounds(true, pData, ulLHS, ulRHS); +} + +void +__ubsan_handle_sub_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + + ASSERT(pData); + + HandleOverflow(false, pData, ulLHS, ulRHS, MINUS_STRING); +} + +void +__ubsan_handle_sub_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + + ASSERT(pData); + + HandleOverflow(true, pData, ulLHS, ulRHS, MINUS_STRING); +} + +void +__ubsan_handle_type_mismatch(struct CTypeMismatchData *pData, unsigned long ulPointer) +{ + + ASSERT(pData); + + HandleTypeMismatch(false, &pData->mLocation, pData->mType, pData->mLogAlignment, pData->mTypeCheckKind, ulPointer); +} + +void +__ubsan_handle_type_mismatch_abort(struct CTypeMismatchData *pData, unsigned long ulPointer) +{ + + ASSERT(pData); + + HandleTypeMismatch(true, &pData->mLocation, pData->mType, pData->mLogAlignment, pData->mTypeCheckKind, ulPointer); +} + +void +__ubsan_handle_type_mismatch_v1(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer) +{ + + ASSERT(pData); + + HandleTypeMismatch(false, &pData->mLocation, pData->mType, __BIT(pData->mLogAlignment), pData->mTypeCheckKind, ulPointer); +} + +void +__ubsan_handle_type_mismatch_v1_abort(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer) +{ + + ASSERT(pData); + + HandleTypeMismatch(true, &pData->mLocation, pData->mType, __BIT(pData->mLogAlignment), pData->mTypeCheckKind, ulPointer); +} + +void +__ubsan_handle_vla_bound_not_positive(struct CVLABoundData *pData, unsigned long ulBound) +{ + + ASSERT(pData); + + HandleVlaBoundNotPositive(false, pData, ulBound); +} + +void +__ubsan_handle_vla_bound_not_positive_abort(struct CVLABoundData *pData, unsigned long ulBound) +{ + + ASSERT(pData); + + HandleVlaBoundNotPositive(true, pData, ulBound); +} + +void +__ubsan_get_current_report_data(const char **ppOutIssueKind, const char **ppOutMessage, const char **ppOutFilename, uint32_t *pOutLine, uint32_t *pOutCol, char **ppOutMemoryAddr) +{ + /* + * Unimplemented. + * + * The __ubsan_on_report() feature is non trivial to implement in a + * shared code between the kernel and userland. It's also opening + * new sets of potential problems as we are not expected to slow down + * execution of certain kernel subsystems (synchronization issues, + * interrupt handling etc). + * + * A proper solution would need probably a lock-free bounded queue built + * with atomic operations with the property of miltiple consumers and + * multiple producers. Maintaining and validating such code is not + * worth the effort. + * + * A legitimate user - besides testing framework - is a debugger plugin + * intercepting reports from the UBSan instrumentation. For such + * scenarios it is better to run the Clang/GCC version. + */ +} + +/* Local utility functions */ + +static void +Report(bool isFatal, const char *pFormat, ...) +{ + va_list ap; + + ASSERT(pFormat); + + va_start(ap, pFormat); +#if defined(_KERNEL) + if (isFatal) + vpanic(pFormat, ap); + else + vprintf(pFormat, ap); +#else + if (ubsan_flags == -1) { + char buf[1024]; + char *p; + + ubsan_flags = UBSAN_STDERR; + + if (getenv_r("LIBC_UBSAN", buf, sizeof(buf)) != -1) { + for (p = buf; *p; p++) { + switch (*p) { + case 'a': + SET(ubsan_flags, UBSAN_ABORT); + break; + case 'A': + CLR(ubsan_flags, UBSAN_ABORT); + break; + case 'e': + SET(ubsan_flags, UBSAN_STDERR); + break; + case 'E': + CLR(ubsan_flags, UBSAN_STDERR); + break; + case 'l': + SET(ubsan_flags, UBSAN_SYSLOG); + break; + case 'L': + CLR(ubsan_flags, UBSAN_SYSLOG); + break; + case 'o': + SET(ubsan_flags, UBSAN_STDOUT); + break; + case 'O': + CLR(ubsan_flags, UBSAN_STDOUT); + break; + default: + break; + } + } + } + } + + // The *v*print* functions can flush the va_list argument. + // Create a local copy for each call to prevent invalid read. + if (ISSET(ubsan_flags, UBSAN_STDOUT)) { + va_list tmp; + va_copy(tmp, ap); + vprintf(pFormat, tmp); + va_end(tmp); + fflush(stdout); + } + if (ISSET(ubsan_flags, UBSAN_STDERR)) { + va_list tmp; + va_copy(tmp, ap); + vfprintf(stderr, pFormat, tmp); + va_end(tmp); + fflush(stderr); + } + if (ISSET(ubsan_flags, UBSAN_SYSLOG)) { + va_list tmp; + va_copy(tmp, ap); + struct syslog_data SyslogData = SYSLOG_DATA_INIT; + ubsan_vsyslog(LOG_DEBUG | LOG_USER, &SyslogData, pFormat, tmp); + va_end(tmp); + } + if (isFatal || ISSET(ubsan_flags, UBSAN_ABORT)) { + abort(); + /* NOTREACHED */ + } +#endif + va_end(ap); +} + +static bool +isAlreadyReported(struct CSourceLocation *pLocation) +{ + /* + * This code is shared between libc, kernel and standalone usage. + * It shall work in early bootstrap phase of both of them. + */ + + uint32_t siOldValue; + volatile uint32_t *pLine; + + ASSERT(pLocation); + + pLine = &pLocation->mLine; + + do { + siOldValue = *pLine; + } while (__sync_val_compare_and_swap(pLine, siOldValue, siOldValue | ACK_REPORTED) != siOldValue); + + return ISSET(siOldValue, ACK_REPORTED); +} + +static size_t +zDeserializeTypeWidth(struct CTypeDescriptor *pType) +{ + size_t zWidth = 0; + + ASSERT(pType); + + switch (pType->mTypeKind) { + case KIND_INTEGER: + zWidth = __BIT(__SHIFTOUT(pType->mTypeInfo, ~NUMBER_SIGNED_BIT)); + break; + case KIND_FLOAT: + zWidth = pType->mTypeInfo; + break; + default: + Report(true, "UBSan: Unknown variable type %#04" PRIx16 "\n", pType->mTypeKind); + /* NOTREACHED */ + } + + /* Invalid width will be transformed to 0 */ + ASSERT(zWidth > 0); + + return zWidth; +} + +static void +DeserializeLocation(char *pBuffer, size_t zBUfferLength, struct CSourceLocation *pLocation) +{ + + ASSERT(pLocation); + ASSERT(pLocation->mFilename); + + snprintf(pBuffer, zBUfferLength, "%s:%" PRIu32 ":%" PRIu32, pLocation->mFilename, pLocation->mLine & (uint32_t)~ACK_REPORTED, pLocation->mColumn); +} + +#ifdef __SIZEOF_INT128__ +static void +DeserializeUINT128(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, __uint128_t U128) +{ + char szBuf[3]; /* 'XX\0' */ + char rgNumber[sizeof(ulongest)]; + ssize_t zI; + + memcpy(rgNumber, &U128, sizeof(U128)); + + strlcpy(pBuffer, "Undecoded-128-bit-Integer-Type (0x", zBUfferLength); +#if BYTE_ORDER == LITTLE_ENDIAN + for (zI = sizeof(ulongest) - 1; zI >= 0; zI--) { +#else + for (zI = 0; zI < (ssize_t)sizeof(ulongest); zI++) { +#endif + snprintf(szBuf, sizeof(szBuf), "%02" PRIx8, rgNumber[zI]); + strlcat(pBuffer, szBuf, zBUfferLength); + } + strlcat(pBuffer, ")", zBUfferLength); +} +#endif + +static void +DeserializeNumberSigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, longest L) +{ + + ASSERT(pBuffer); + ASSERT(zBUfferLength > 0); + ASSERT(pType); + ASSERT(ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT)); + + switch (zDeserializeTypeWidth(pType)) { + default: + ASSERT(0 && "Invalid codepath"); + /* NOTREACHED */ +#ifdef __SIZEOF_INT128__ + case WIDTH_128: + DeserializeUINT128(pBuffer, zBUfferLength, pType, STATIC_CAST(__uint128_t, L)); + break; +#endif + case WIDTH_64: + case WIDTH_32: + case WIDTH_16: + case WIDTH_8: + snprintf(pBuffer, zBUfferLength, "%" PRId64, STATIC_CAST(int64_t, L)); + break; + } +} + +static void +DeserializeNumberUnsigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, ulongest L) +{ + + ASSERT(pBuffer); + ASSERT(zBUfferLength > 0); + ASSERT(pType); + ASSERT(!ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT)); + + switch (zDeserializeTypeWidth(pType)) { + default: + ASSERT(0 && "Invalid codepath"); + /* NOTREACHED */ +#ifdef __SIZEOF_INT128__ + case WIDTH_128: + DeserializeUINT128(pBuffer, zBUfferLength, pType, STATIC_CAST(__uint128_t, L)); + break; +#endif + case WIDTH_64: + case WIDTH_32: + case WIDTH_16: + case WIDTH_8: + snprintf(pBuffer, zBUfferLength, "%" PRIu64, STATIC_CAST(uint64_t, L)); + break; + } +} + +#ifndef _KERNEL +static void +DeserializeFloatOverPointer(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long *pNumber) +{ + double D; +#ifdef __HAVE_LONG_DOUBLE + long double LD; +#endif + + ASSERT(pBuffer); + ASSERT(zBUfferLength > 0); + ASSERT(pType); + ASSERT(pNumber); + /* + * This function handles 64-bit number over a pointer on 32-bit CPUs. + */ + ASSERT((sizeof(*pNumber) * CHAR_BIT < WIDTH_64) || (zDeserializeTypeWidth(pType) >= WIDTH_64)); + ASSERT(sizeof(D) == sizeof(uint64_t)); +#ifdef __HAVE_LONG_DOUBLE + ASSERT(sizeof(LD) > sizeof(uint64_t)); +#endif + + switch (zDeserializeTypeWidth(pType)) { +#ifdef __HAVE_LONG_DOUBLE + case WIDTH_128: + case WIDTH_96: + case WIDTH_80: + memcpy(&LD, pNumber, sizeof(long double)); + snprintf(pBuffer, zBUfferLength, "%Lg", LD); + break; +#endif + case WIDTH_64: + memcpy(&D, pNumber, sizeof(double)); + snprintf(pBuffer, zBUfferLength, "%g", D); + break; + } +} + +static void +DeserializeFloatInlined(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber) +{ + float F; + double D; + uint32_t U32; + + ASSERT(pBuffer); + ASSERT(zBUfferLength > 0); + ASSERT(pType); + ASSERT(sizeof(F) == sizeof(uint32_t)); + ASSERT(sizeof(D) == sizeof(uint64_t)); + + switch (zDeserializeTypeWidth(pType)) { + case WIDTH_64: + memcpy(&D, &ulNumber, sizeof(double)); + snprintf(pBuffer, zBUfferLength, "%g", D); + break; + case WIDTH_32: + /* + * On supported platforms sizeof(float)==sizeof(uint32_t) + * unsigned long is either 32 or 64-bit, cast it to 32-bit + * value in order to call memcpy(3) in an Endian-aware way. + */ + U32 = STATIC_CAST(uint32_t, ulNumber); + memcpy(&F, &U32, sizeof(float)); + snprintf(pBuffer, zBUfferLength, "%g", F); + break; + case WIDTH_16: + snprintf(pBuffer, zBUfferLength, "Undecoded-16-bit-Floating-Type (%#04" PRIx16 ")", STATIC_CAST(uint16_t, ulNumber)); + break; + } +} +#endif + +static longest +llliGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber) +{ + size_t zNumberWidth; + longest L = 0; + + ASSERT(szLocation); + ASSERT(pType); + + zNumberWidth = zDeserializeTypeWidth(pType); + switch (zNumberWidth) { + default: + Report(true, "UBSan: Unexpected %zu-Bit Type in %s\n", zNumberWidth, szLocation); + /* NOTREACHED */ + case WIDTH_128: +#ifdef __SIZEOF_INT128__ + memcpy(&L, REINTERPRET_CAST(longest *, ulNumber), sizeof(longest)); +#else + Report(true, "UBSan: Unexpected 128-Bit Type in %s\n", szLocation); + /* NOTREACHED */ +#endif + break; + case WIDTH_64: + if (sizeof(ulNumber) * CHAR_BIT < WIDTH_64) { + L = *REINTERPRET_CAST(int64_t *, ulNumber); + } else { + L = STATIC_CAST(int64_t, STATIC_CAST(uint64_t, ulNumber)); + } + break; + case WIDTH_32: + L = STATIC_CAST(int32_t, STATIC_CAST(uint32_t, ulNumber)); + break; + case WIDTH_16: + L = STATIC_CAST(int16_t, STATIC_CAST(uint16_t, ulNumber)); + break; + case WIDTH_8: + L = STATIC_CAST(int8_t, STATIC_CAST(uint8_t, ulNumber)); + break; + } + + return L; +} + +static ulongest +llluGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber) +{ + size_t zNumberWidth; + ulongest UL = 0; + + ASSERT(pType); + + zNumberWidth = zDeserializeTypeWidth(pType); + switch (zNumberWidth) { + default: + Report(true, "UBSan: Unexpected %zu-Bit Type in %s\n", zNumberWidth, szLocation); + /* NOTREACHED */ + case WIDTH_128: +#ifdef __SIZEOF_INT128__ + memcpy(&UL, REINTERPRET_CAST(ulongest *, ulNumber), sizeof(ulongest)); + break; +#else + Report(true, "UBSan: Unexpected 128-Bit Type in %s\n", szLocation); + /* NOTREACHED */ +#endif + case WIDTH_64: + if (sizeof(ulNumber) * CHAR_BIT < WIDTH_64) { + UL = *REINTERPRET_CAST(uint64_t *, ulNumber); + break; + } + /* FALLTHROUGH */ + case WIDTH_32: + /* FALLTHROUGH */ + case WIDTH_16: + /* FALLTHROUGH */ + case WIDTH_8: + UL = ulNumber; + break; + } + + return UL; +} + +#ifndef _KERNEL +static void +DeserializeNumberFloat(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber) +{ + size_t zNumberWidth; + + ASSERT(szLocation); + ASSERT(pBuffer); + ASSERT(zBUfferLength > 0); + ASSERT(pType); + ASSERT(pType->mTypeKind == KIND_FLOAT); + + zNumberWidth = zDeserializeTypeWidth(pType); + switch (zNumberWidth) { + default: + Report(true, "UBSan: Unexpected %zu-Bit Type in %s\n", zNumberWidth, szLocation); + /* NOTREACHED */ +#ifdef __HAVE_LONG_DOUBLE + case WIDTH_128: + case WIDTH_96: + case WIDTH_80: + DeserializeFloatOverPointer(pBuffer, zBUfferLength, pType, REINTERPRET_CAST(unsigned long *, ulNumber)); + break; +#endif + case WIDTH_64: + if (sizeof(ulNumber) * CHAR_BIT < WIDTH_64) { + DeserializeFloatOverPointer(pBuffer, zBUfferLength, pType, REINTERPRET_CAST(unsigned long *, ulNumber)); + break; + } + case WIDTH_32: + case WIDTH_16: + DeserializeFloatInlined(pBuffer, zBUfferLength, pType, ulNumber); + break; + } +} +#endif + +static void +DeserializeNumber(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber) +{ + + ASSERT(szLocation); + ASSERT(pBuffer); + ASSERT(zBUfferLength > 0); + ASSERT(pType); + + switch(pType->mTypeKind) { + case KIND_INTEGER: + if (ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT)) { + longest L = llliGetNumber(szLocation, pType, ulNumber); + DeserializeNumberSigned(pBuffer, zBUfferLength, pType, L); + } else { + ulongest UL = llluGetNumber(szLocation, pType, ulNumber); + DeserializeNumberUnsigned(pBuffer, zBUfferLength, pType, UL); + } + break; + case KIND_FLOAT: +#ifdef _KERNEL + Report(true, "UBSan: Unexpected Float Type in %s\n", szLocation); + /* NOTREACHED */ +#else + DeserializeNumberFloat(szLocation, pBuffer, zBUfferLength, pType, ulNumber); +#endif + break; + case KIND_UNKNOWN: + Report(true, "UBSan: Unknown Type in %s\n", szLocation); + /* NOTREACHED */ + break; + } +} + +static const char * +DeserializeTypeCheckKind(uint8_t hhuTypeCheckKind) +{ + const char *rgczTypeCheckKinds[] = { + "load of", + "store to", + "reference binding to", + "member access within", + "member call on", + "constructor call on", + "downcast of", + "downcast of", + "upcast of", + "cast to virtual base of", + "_Nonnull binding to", + "dynamic operation on" + }; + + ASSERT(__arraycount(rgczTypeCheckKinds) > hhuTypeCheckKind); + + return rgczTypeCheckKinds[hhuTypeCheckKind]; +} + +static const char * +DeserializeBuiltinCheckKind(uint8_t hhuBuiltinCheckKind) +{ + const char *rgczBuiltinCheckKinds[] = { + "ctz()", + "clz()" + }; + + ASSERT(__arraycount(rgczBuiltinCheckKinds) > hhuBuiltinCheckKind); + + return rgczBuiltinCheckKinds[hhuBuiltinCheckKind]; +} + +static const char * +DeserializeCFICheckKind(uint8_t hhuCFICheckKind) +{ + const char *rgczCFICheckKinds[] = { + "virtual call", // CFI_VCALL + "non-virtual call", // CFI_NVCALL + "base-to-derived cast", // CFI_DERIVEDCAST + "cast to unrelated type", // CFI_UNRELATEDCAST + "indirect function call", // CFI_ICALL + "non-virtual pointer to member function call", // CFI_NVMFCALL + "virtual pointer to member function call", // CFI_VMFCALL + }; + + ASSERT(__arraycount(rgczCFICheckKinds) > hhuCFICheckKind); + + return rgczCFICheckKinds[hhuCFICheckKind]; +} + +static bool +isNegativeNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber) +{ + + ASSERT(szLocation); + ASSERT(pType); + ASSERT(pType->mTypeKind == KIND_INTEGER); + + if (!ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT)) + return false; + + return llliGetNumber(szLocation, pType, ulNumber) < 0; +} + +static bool +isShiftExponentTooLarge(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber, size_t zWidth) +{ + + ASSERT(szLocation); + ASSERT(pType); + ASSERT(pType->mTypeKind == KIND_INTEGER); + + return llluGetNumber(szLocation, pType, ulNumber) >= zWidth; +} diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 56eba3dd22db..8b0aaa9ab4cf 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -509,9 +509,8 @@ retry: size = round_page(size); buffer = (caddr_t) vm_map_min(pipe_map); - error = vm_map_find(pipe_map, NULL, 0, - (vm_offset_t *) &buffer, size, 0, VMFS_ANY_SPACE, - VM_PROT_ALL, VM_PROT_ALL, 0); + error = vm_map_find(pipe_map, NULL, 0, (vm_offset_t *)&buffer, size, 0, + VMFS_ANY_SPACE, VM_PROT_RW, VM_PROT_RW, 0); if (error != KERN_SUCCESS) { if ((cpipe->pipe_buffer.buffer == NULL) && (size > SMALL_PIPE_SIZE)) { diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index dfe6677de120..55d81c059d5e 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -117,8 +117,7 @@ ); } ; XXX should be { int open(const char *path, int flags, ...); } -; but we're not ready for `const' or varargs. -; XXX man page says `mode_t mode'. +; but we're not ready for varargs. 6 AUE_CLOSE STD { int close( int fd @@ -207,10 +206,9 @@ _In_z_ const char *type, _In_z_ const char *path, int flags, - _In_opt_ caddr_t data + _In_opt_ void *data ); } -; XXX `path' should have type `const char *' but we're not ready for that. 22 AUE_UMOUNT STD { int unmount( _In_z_ const char *path, @@ -253,7 +251,7 @@ 29 AUE_RECVFROM STD { int recvfrom( int s, - _Out_writes_bytes_(len) caddr_t buf, + _Out_writes_bytes_(len) void *buf, size_t len, int flags, _Out_writes_bytes_opt_(*fromlenaddr) struct sockaddr *from, @@ -336,7 +334,7 @@ } 44 AUE_PROFILE STD { int profil( - _Out_writes_bytes_(size) caddr_t samples, + _Out_writes_bytes_(size) char *samples, size_t size, size_t offset, u_int scale @@ -398,7 +396,7 @@ int ioctl( int fd, u_long com, - _Inout_opt_ caddr_t data + _Inout_opt_ char *data ); } 55 AUE_REBOOT STD { @@ -630,14 +628,14 @@ 98 AUE_CONNECT STD { int connect( int s, - _In_reads_bytes_(namelen) caddr_t name, + _In_reads_bytes_(namelen) const struct sockaddr *name, int namelen ); } 99 AUE_ACCEPT COMPAT|NOARGS { int accept( int s, - _Out_writes_bytes_opt_(*anamelen) caddr_t name, + _Out_writes_bytes_opt_(*anamelen) struct sockaddr *name, int *anamelen ); } accept accept_args int @@ -650,7 +648,7 @@ 101 AUE_SEND COMPAT { int send( int s, - _In_reads_bytes_(len) caddr_t buf, + _In_reads_bytes_(len) const void *buf, int len, int flags ); @@ -658,7 +656,7 @@ 102 AUE_RECV COMPAT { int recv( int s, - _Out_writes_bytes_(len) caddr_t buf, + _Out_writes_bytes_(len) void *buf, int len, int flags ); @@ -671,7 +669,7 @@ 104 AUE_BIND STD { int bind( int s, - _In_reads_bytes_(namelen) caddr_t name, + _In_reads_bytes_(namelen) const struct sockaddr *name, int namelen ); } @@ -680,7 +678,7 @@ int s, int level, int name, - _In_reads_bytes_opt_(valsize) caddr_t val, + _In_reads_bytes_opt_(valsize) const void *val, int valsize ); } @@ -731,7 +729,7 @@ 114 AUE_SENDMSG COMPAT { int sendmsg( int s, - _In_ caddr_t msg, + _In_ const void *msg, int flags ); } @@ -753,7 +751,7 @@ int s, int level, int name, - _Out_writes_bytes_opt_(*avalsize) caddr_t val, + _Out_writes_bytes_opt_(*avalsize) void *val, _Inout_ int *avalsize ); } @@ -761,8 +759,8 @@ 120 AUE_READV STD { int readv( int fd, - _Inout_updates_(iovcnt) struct iovec *iovp, - u_int iovcnt + _Inout_updates_(iovcnt) struct iovec *iovp, + u_int iovcnt ); } 121 AUE_WRITEV STD { @@ -794,10 +792,10 @@ 125 AUE_RECVFROM COMPAT|NOARGS { int recvfrom( int s, - _Out_writes_(len) caddr_t buf, + _Out_writes_(len) void *buf, size_t len, int flags, - _Out_writes_bytes_(*fromlenaddr) caddr_t from, + _Out_writes_bytes_(*fromlenaddr) struct sockaddr *from, _Inout_ int *fromlenaddr ); } recvfrom recvfrom_args int @@ -846,10 +844,10 @@ 133 AUE_SENDTO STD { int sendto( int s, - _In_reads_bytes_(len) caddr_t buf, + _In_reads_bytes_(len) const void *buf, size_t len, - int flags, - _In_reads_bytes_opt_(tolen) caddr_t to, + int flags, + _In_reads_bytes_opt_(tolen) const struct sockaddr *to, int tolen ); } @@ -894,7 +892,7 @@ 141 AUE_GETPEERNAME COMPAT { int getpeername( int fdes, - _Out_writes_bytes_(*alen) caddr_t asa, + _Out_writes_bytes_(*alen) struct sockaddr *asa, _Inout_opt_ int *alen ); } @@ -932,7 +930,7 @@ _In_z_ const char *path, int cmd, int uid, - _In_ caddr_t arg + _In_ void *arg ); } 149 AUE_O_QUOTA COMPAT { @@ -941,7 +939,7 @@ 150 AUE_GETSOCKNAME COMPAT|NOARGS { int getsockname( int fdec, - _Out_writes_bytes_(*alen) caddr_t asa, + _Out_writes_bytes_(*alen) struct sockaddr *asa, _Inout_ int *alen ); } getsockname getsockname_args int @@ -966,7 +964,7 @@ 155 AUE_NFS_SVC NOSTD { int nfssvc( int flag, - _In_ caddr_t argp + _In_ void *argp ); } 156 AUE_GETDIRENTRIES COMPAT { @@ -1171,7 +1169,7 @@ } 197 AUE_MMAP COMPAT6 { caddr_t mmap( - _In_ caddr_t addr, + _In_ void *addr, size_t len, int prot, int flags, @@ -2498,9 +2496,9 @@ 472 AUE_SCTP_GENERIC_SENDMSG NOSTD { int sctp_generic_sendmsg( int sd, - _In_reads_bytes_(mlen) caddr_t msg, + _In_reads_bytes_(mlen) void *msg, int mlen, - _In_reads_bytes_(tolen) caddr_t to, + _In_reads_bytes_(tolen) struct sockaddr *to, __socklen_t tolen, _In_opt_ struct sctp_sndrcvinfo *sinfo, int flags @@ -2511,7 +2509,7 @@ int sd, _In_reads_(iovlen) struct iovec *iov, int iovlen, - _In_reads_bytes_(tolen) caddr_t to, + _In_reads_bytes_(tolen) struct sockaddr *to, __socklen_t tolen, _In_opt_ struct sctp_sndrcvinfo *sinfo, int flags @@ -2546,7 +2544,7 @@ } 477 AUE_MMAP STD { caddr_t mmap( - _In_ caddr_t addr, + _In_ void *addr, size_t len, int prot, int flags, @@ -2967,7 +2965,7 @@ int bindat( int fd, int s, - _In_reads_bytes_(namelen) caddr_t name, + _In_reads_bytes_(namelen) const struct sockaddr *name, int namelen ); } @@ -2975,7 +2973,7 @@ int connectat( int fd, int s, - _In_reads_bytes_(namelen) caddr_t name, + _In_reads_bytes_(namelen) const struct sockaddr *name, int namelen ); } diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c index 31283b9df1f0..9061b6eb6a89 100644 --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -136,7 +136,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) uarg[0] = (intptr_t) p->type; /* const char * */ uarg[1] = (intptr_t) p->path; /* const char * */ iarg[2] = p->flags; /* int */ - uarg[3] = (intptr_t) p->data; /* caddr_t */ + uarg[3] = (intptr_t) p->data; /* void * */ *n_args = 4; break; } @@ -197,7 +197,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 29: { struct recvfrom_args *p = params; iarg[0] = p->s; /* int */ - uarg[1] = (intptr_t) p->buf; /* caddr_t */ + uarg[1] = (intptr_t) p->buf; /* void * */ uarg[2] = p->len; /* size_t */ iarg[3] = p->flags; /* int */ uarg[4] = (intptr_t) p->from; /* struct sockaddr * */ @@ -289,7 +289,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* profil */ case 44: { struct profil_args *p = params; - uarg[0] = (intptr_t) p->samples; /* caddr_t */ + uarg[0] = (intptr_t) p->samples; /* char * */ uarg[1] = p->size; /* size_t */ uarg[2] = p->offset; /* size_t */ uarg[3] = p->scale; /* u_int */ @@ -346,7 +346,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct ioctl_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = p->com; /* u_long */ - uarg[2] = (intptr_t) p->data; /* caddr_t */ + uarg[2] = (intptr_t) p->data; /* char * */ *n_args = 3; break; } @@ -582,7 +582,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 98: { struct connect_args *p = params; iarg[0] = p->s; /* int */ - uarg[1] = (intptr_t) p->name; /* caddr_t */ + uarg[1] = (intptr_t) p->name; /* const struct sockaddr * */ iarg[2] = p->namelen; /* int */ *n_args = 3; break; @@ -599,7 +599,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 104: { struct bind_args *p = params; iarg[0] = p->s; /* int */ - uarg[1] = (intptr_t) p->name; /* caddr_t */ + uarg[1] = (intptr_t) p->name; /* const struct sockaddr * */ iarg[2] = p->namelen; /* int */ *n_args = 3; break; @@ -610,7 +610,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[0] = p->s; /* int */ iarg[1] = p->level; /* int */ iarg[2] = p->name; /* int */ - uarg[3] = (intptr_t) p->val; /* caddr_t */ + uarg[3] = (intptr_t) p->val; /* const void * */ iarg[4] = p->valsize; /* int */ *n_args = 5; break; @@ -645,7 +645,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[0] = p->s; /* int */ iarg[1] = p->level; /* int */ iarg[2] = p->name; /* int */ - uarg[3] = (intptr_t) p->val; /* caddr_t */ + uarg[3] = (intptr_t) p->val; /* void * */ uarg[4] = (intptr_t) p->avalsize; /* int * */ *n_args = 5; break; @@ -737,10 +737,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 133: { struct sendto_args *p = params; iarg[0] = p->s; /* int */ - uarg[1] = (intptr_t) p->buf; /* caddr_t */ + uarg[1] = (intptr_t) p->buf; /* const void * */ uarg[2] = p->len; /* size_t */ iarg[3] = p->flags; /* int */ - uarg[4] = (intptr_t) p->to; /* caddr_t */ + uarg[4] = (intptr_t) p->to; /* const struct sockaddr * */ iarg[5] = p->tolen; /* int */ *n_args = 6; break; @@ -805,7 +805,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) uarg[0] = (intptr_t) p->path; /* const char * */ iarg[1] = p->cmd; /* int */ iarg[2] = p->uid; /* int */ - uarg[3] = (intptr_t) p->arg; /* caddr_t */ + uarg[3] = (intptr_t) p->arg; /* void * */ *n_args = 4; break; } @@ -823,7 +823,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 155: { struct nfssvc_args *p = params; iarg[0] = p->flag; /* int */ - uarg[1] = (intptr_t) p->argp; /* caddr_t */ + uarg[1] = (intptr_t) p->argp; /* void * */ *n_args = 2; break; } @@ -2474,9 +2474,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 472: { struct sctp_generic_sendmsg_args *p = params; iarg[0] = p->sd; /* int */ - uarg[1] = (intptr_t) p->msg; /* caddr_t */ + uarg[1] = (intptr_t) p->msg; /* void * */ iarg[2] = p->mlen; /* int */ - uarg[3] = (intptr_t) p->to; /* caddr_t */ + uarg[3] = (intptr_t) p->to; /* struct sockaddr * */ iarg[4] = p->tolen; /* __socklen_t */ uarg[5] = (intptr_t) p->sinfo; /* struct sctp_sndrcvinfo * */ iarg[6] = p->flags; /* int */ @@ -2489,7 +2489,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[0] = p->sd; /* int */ uarg[1] = (intptr_t) p->iov; /* struct iovec * */ iarg[2] = p->iovlen; /* int */ - uarg[3] = (intptr_t) p->to; /* caddr_t */ + uarg[3] = (intptr_t) p->to; /* struct sockaddr * */ iarg[4] = p->tolen; /* __socklen_t */ uarg[5] = (intptr_t) p->sinfo; /* struct sctp_sndrcvinfo * */ iarg[6] = p->flags; /* int */ @@ -2532,7 +2532,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* mmap */ case 477: { struct mmap_args *p = params; - uarg[0] = (intptr_t) p->addr; /* caddr_t */ + uarg[0] = (intptr_t) p->addr; /* void * */ uarg[1] = p->len; /* size_t */ iarg[2] = p->prot; /* int */ iarg[3] = p->flags; /* int */ @@ -3047,7 +3047,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct bindat_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->s; /* int */ - uarg[2] = (intptr_t) p->name; /* caddr_t */ + uarg[2] = (intptr_t) p->name; /* const struct sockaddr * */ iarg[3] = p->namelen; /* int */ *n_args = 4; break; @@ -3057,7 +3057,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct connectat_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->s; /* int */ - uarg[2] = (intptr_t) p->name; /* caddr_t */ + uarg[2] = (intptr_t) p->name; /* const struct sockaddr * */ iarg[3] = p->namelen; /* int */ *n_args = 4; break; @@ -3467,7 +3467,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 3: - p = "caddr_t"; + p = "userland void *"; break; default: break; @@ -3560,7 +3560,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland void *"; break; case 2: p = "size_t"; @@ -3701,7 +3701,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 44: switch(ndx) { case 0: - p = "caddr_t"; + p = "userland char *"; break; case 1: p = "size_t"; @@ -3794,7 +3794,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "u_long"; break; case 2: - p = "caddr_t"; + p = "userland char *"; break; default: break; @@ -4169,7 +4169,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland const struct sockaddr *"; break; case 2: p = "int"; @@ -4198,7 +4198,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland const struct sockaddr *"; break; case 2: p = "int"; @@ -4220,7 +4220,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 3: - p = "caddr_t"; + p = "userland const void *"; break; case 4: p = "int"; @@ -4281,7 +4281,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 3: - p = "caddr_t"; + p = "userland void *"; break; case 4: p = "userland int *"; @@ -4436,7 +4436,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland const void *"; break; case 2: p = "size_t"; @@ -4445,7 +4445,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 4: - p = "caddr_t"; + p = "userland const struct sockaddr *"; break; case 5: p = "int"; @@ -4551,7 +4551,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 3: - p = "caddr_t"; + p = "userland void *"; break; default: break; @@ -4583,7 +4583,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland void *"; break; default: break; @@ -7276,13 +7276,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "caddr_t"; + p = "userland void *"; break; case 2: p = "int"; break; case 3: - p = "caddr_t"; + p = "userland struct sockaddr *"; break; case 4: p = "__socklen_t"; @@ -7310,7 +7310,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 3: - p = "caddr_t"; + p = "userland struct sockaddr *"; break; case 4: p = "__socklen_t"; @@ -7395,7 +7395,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 477: switch(ndx) { case 0: - p = "caddr_t"; + p = "userland void *"; break; case 1: p = "size_t"; @@ -8312,7 +8312,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 2: - p = "caddr_t"; + p = "userland const struct sockaddr *"; break; case 3: p = "int"; @@ -8331,7 +8331,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 2: - p = "caddr_t"; + p = "userland const struct sockaddr *"; break; case 3: p = "int"; diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 26ce6124bf86..022c392d5c17 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include "opt_capsicum.h" +#include "opt_printf.h" #include <sys/param.h> #include <sys/capsicum.h> @@ -106,6 +107,12 @@ SYSCTL_INT(_kern, OID_AUTO, tty_drainwait, CTLFLAG_RWTUN, #define TTYBUF_MAX 65536 +#ifdef PRINTF_BUFR_SIZE +#define TTY_PRBUF_SIZE PRINTF_BUFR_SIZE +#else +#define TTY_PRBUF_SIZE 256 +#endif + /* * Allocate buffer space if necessary, and set low watermarks, based on speed. * Note that the ttyxxxq_setsize() functions may drop and then reacquire the tty @@ -1051,7 +1058,9 @@ tty_alloc_mutex(struct ttydevsw *tsw, void *sc, struct mtx *mutex) PATCH_FUNC(busy); #undef PATCH_FUNC - tp = malloc(sizeof(struct tty), M_TTY, M_WAITOK|M_ZERO); + tp = malloc(sizeof(struct tty) + TTY_PRBUF_SIZE, M_TTY, + M_WAITOK | M_ZERO); + tp->t_prbufsz = TTY_PRBUF_SIZE; tp->t_devsw = tsw; tp->t_devswsoftc = sc; tp->t_flags = tsw->tsw_flags; diff --git a/sys/kern/tty_info.c b/sys/kern/tty_info.c index 378e1bc64284..47e65565848d 100644 --- a/sys/kern/tty_info.c +++ b/sys/kern/tty_info.c @@ -45,6 +45,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_stack.h" + #include <sys/param.h> #include <sys/cons.h> #include <sys/kdb.h> @@ -269,7 +271,7 @@ tty_info(struct tty *tp) if (tty_checkoutq(tp) == 0) return; - (void)sbuf_new(&sb, tp->t_prbuf, sizeof(tp->t_prbuf), SBUF_FIXEDLEN); + (void)sbuf_new(&sb, tp->t_prbuf, tp->t_prbufsz, SBUF_FIXEDLEN); sbuf_set_drain(&sb, sbuf_tty_drain, tp); /* Print load average. */ diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index 4751635e2aee..2f5cad6466d8 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -393,7 +393,7 @@ mqnode_free(struct mqfs_node *node) static __inline void mqnode_addref(struct mqfs_node *node) { - atomic_fetchadd_int(&node->mn_refcount, 1); + atomic_add_int(&node->mn_refcount, 1); } static __inline void diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 57cddd153972..202d5c868de4 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -825,7 +825,7 @@ sys_sendto(struct thread *td, struct sendto_args *uap) struct msghdr msg; struct iovec aiov; - msg.msg_name = uap->to; + msg.msg_name = __DECONST(void *, uap->to); msg.msg_namelen = uap->tolen; msg.msg_iov = &aiov; msg.msg_iovlen = 1; @@ -833,7 +833,7 @@ sys_sendto(struct thread *td, struct sendto_args *uap) #ifdef COMPAT_OLDSOCK msg.msg_flags = 0; #endif - aiov.iov_base = uap->buf; + aiov.iov_base = __DECONST(void *, uap->buf); aiov.iov_len = uap->len; return (sendit(td, uap->s, &msg, uap->flags)); } @@ -849,7 +849,7 @@ osend(struct thread *td, struct osend_args *uap) msg.msg_namelen = 0; msg.msg_iov = &aiov; msg.msg_iovlen = 1; - aiov.iov_base = uap->buf; + aiov.iov_base = __DECONST(void *, uap->buf); aiov.iov_len = uap->len; msg.msg_control = 0; msg.msg_flags = 0; @@ -1225,7 +1225,7 @@ sys_setsockopt(struct thread *td, struct setsockopt_args *uap) } int -kern_setsockopt(struct thread *td, int s, int level, int name, void *val, +kern_setsockopt(struct thread *td, int s, int level, int name, const void *val, enum uio_seg valseg, socklen_t valsize) { struct socket *so; @@ -1241,7 +1241,7 @@ kern_setsockopt(struct thread *td, int s, int level, int name, void *val, sopt.sopt_dir = SOPT_SET; sopt.sopt_level = level; sopt.sopt_name = name; - sopt.sopt_val = val; + sopt.sopt_val = __DECONST(void *, val); sopt.sopt_valsize = valsize; switch (valseg) { case UIO_USERSPACE: @@ -1546,7 +1546,7 @@ sockargs(struct mbuf **mp, char *buf, socklen_t buflen, int type) } int -getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len) +getsockaddr(struct sockaddr **namp, const struct sockaddr *uaddr, size_t len) { struct sockaddr *sa; int error; diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 83e67207dc9f..ea322343d89a 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -1656,7 +1656,7 @@ buf_alloc(struct bufdomain *bd) if (freebufs > 0) bp = uma_zalloc(buf_zone, M_NOWAIT); if (bp == NULL) { - atomic_fetchadd_int(&bd->bd_freebuffers, 1); + atomic_add_int(&bd->bd_freebuffers, 1); bufspace_daemon_wakeup(bd); counter_u64_add(numbufallocfails, 1); return (NULL); diff --git a/sys/mips/include/cpu.h b/sys/mips/include/cpu.h index a54ea2a2d6bf..b4f5c59f72f5 100644 --- a/sys/mips/include/cpu.h +++ b/sys/mips/include/cpu.h @@ -71,6 +71,7 @@ #define cpu_getstack(td) ((td)->td_frame->sp) #define cpu_setstack(td, nsp) ((td)->td_frame->sp = (nsp)) #define cpu_spinwait() /* nothing */ +#define cpu_lock_delay() DELAY(1) /* * A machine-independent interface to the CPU's counter. diff --git a/sys/netgraph/ng_pptpgre.c b/sys/netgraph/ng_pptpgre.c index 0941d8eb7d18..6ad7516a5dbc 100644 --- a/sys/netgraph/ng_pptpgre.c +++ b/sys/netgraph/ng_pptpgre.c @@ -64,6 +64,7 @@ #include <sys/mutex.h> #include <sys/endian.h> #include <sys/errno.h> +#include <sys/sysctl.h> #include <netinet/in.h> #include <netinet/in_systm.h> @@ -124,6 +125,8 @@ typedef u_int64_t pptptime_t; #define PPTP_MIN_TIMEOUT (PPTP_TIME_SCALE / 83) /* 12 milliseconds */ #define PPTP_MAX_TIMEOUT (3 * PPTP_TIME_SCALE) /* 3 seconds */ +#define PPTP_REORDER_TIMEOUT 1 + /* When we receive a packet, we wait to see if there's an outgoing packet we can piggy-back the ACK off of. These parameters determine the mimimum and maxmimum length of time we're willing to wait in order to do that. @@ -142,6 +145,34 @@ typedef u_int64_t pptptime_t; #define SESSHASHSIZE 0x0020 #define SESSHASH(x) (((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1)) +SYSCTL_NODE(_net_graph, OID_AUTO, pptpgre, CTLFLAG_RW, 0, "PPTPGRE"); + +/* + * Reorder queue maximum length. Zero disables reorder. + * + * The node may keep reorder_max queue entries per session + * if reorder is enabled, plus allocate one more for short time. + * + * Be conservative in memory consumption by default. + * Lots of sessions with large queues can overflow M_NETGRAPH zone. + */ +static int reorder_max = 1; /* reorder up to two swapped packets in a row */ +SYSCTL_UINT(_net_graph_pptpgre, OID_AUTO, reorder_max, CTLFLAG_RWTUN, + &reorder_max, 0, "Reorder queue maximum length"); + +static int reorder_timeout = PPTP_REORDER_TIMEOUT; +SYSCTL_UINT(_net_graph_pptpgre, OID_AUTO, reorder_timeout, CTLFLAG_RWTUN, + &reorder_timeout, 0, "Reorder timeout is milliseconds"); + +/* Packet reorder FIFO queue */ +struct ng_pptpgre_roq { + SLIST_ENTRY(ng_pptpgre_roq) next; /* next entry of the queue */ + item_p item; /* netgraph item */ + u_int32_t seq; /* packet sequence number */ +}; +SLIST_HEAD(ng_pptpgre_roq_head, ng_pptpgre_roq); +typedef struct ng_pptpgre_roq_head roqh; + /* We keep packet retransmit and acknowlegement state in this struct */ struct ng_pptpgre_sess { node_p node; /* this node pointer */ @@ -161,6 +192,9 @@ struct ng_pptpgre_sess { u_int32_t winAck; /* seq when xmitWin will grow */ pptptime_t timeSent[PPTP_XMIT_WIN]; LIST_ENTRY(ng_pptpgre_sess) sessions; + roqh roq; /* reorder queue head */ + u_int8_t roq_len; /* reorder queue length */ + struct callout reorderTimer; /* reorder timeout handler */ }; typedef struct ng_pptpgre_sess *hpriv_p; @@ -187,13 +221,19 @@ static ng_disconnect_t ng_pptpgre_disconnect; static int ng_pptpgre_xmit(hpriv_p hpriv, item_p item); static void ng_pptpgre_start_send_ack_timer(hpriv_p hpriv); static void ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv); +static void ng_pptpgre_start_reorder_timer(hpriv_p hpriv); static void ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2); static void ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2); +static void ng_pptpgre_reorder_timeout(node_p node, hook_p hook, + void *arg1, int arg2); static hpriv_p ng_pptpgre_find_session(priv_p privp, u_int16_t cid); static void ng_pptpgre_reset(hpriv_p hpriv); static pptptime_t ng_pptpgre_time(void); +static void ng_pptpgre_ack(const hpriv_p hpriv); +static int ng_pptpgre_sendq(const hpriv_p hpriv, roqh *q, + const struct ng_pptpgre_roq *st); /* Parse type for struct ng_pptpgre_conf */ static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[] @@ -291,6 +331,10 @@ ng_pptpgre_constructor(node_p node) ng_callout_init(&priv->uppersess.rackTimer); priv->uppersess.node = node; + SLIST_INIT(&priv->uppersess.roq); + priv->uppersess.roq_len = 0; + ng_callout_init(&priv->uppersess.reorderTimer); + for (i = 0; i < SESSHASHSIZE; i++) LIST_INIT(&priv->sesshash[i]); @@ -348,6 +392,11 @@ ng_pptpgre_newhook(node_p node, hook_p hook, const char *name) hpriv->conf.cid = cid; hpriv->node = node; hpriv->hook = hook; + + SLIST_INIT(&hpriv->roq); + hpriv->roq_len = 0; + ng_callout_init(&hpriv->reorderTimer); + NG_HOOK_SET_PRIVATE(hook, hpriv); hash = SESSHASH(cid); @@ -646,6 +695,49 @@ done: return (error); } +static void +ng_pptpgre_ack(const hpriv_p hpriv) +{ + mtx_assert(&hpriv->mtx, MA_OWNED); + if (!(callout_pending(&hpriv->sackTimer))) { + /* If delayed ACK is disabled, send it now */ + if (!hpriv->conf.enableDelayedAck) { /* ack now */ + ng_pptpgre_xmit(hpriv, NULL); + /* ng_pptpgre_xmit() drops the mutex */ + return; + } + /* ack later */ + ng_pptpgre_start_send_ack_timer(hpriv); + mtx_unlock(&hpriv->mtx); + return; + } + mtx_unlock(&hpriv->mtx); +} + +/* + * Delivers packets from the queue "q" to upper layers. Frees delivered + * entries with the exception of one equal to "st" that is allocated + * on caller's stack and not on the heap. + */ +static int +ng_pptpgre_sendq(const hpriv_p hpriv, roqh *q, const struct ng_pptpgre_roq *st) +{ + struct ng_pptpgre_roq *np; + struct mbuf *m; + int error = 0; + + mtx_assert(&hpriv->mtx, MA_NOTOWNED); + while (!SLIST_EMPTY(q)) { + np = SLIST_FIRST(q); + SLIST_REMOVE_HEAD(q, next); + NGI_GET_M(np->item, m); + NG_FWD_NEW_DATA(error, np->item, hpriv->hook, m); + if (np != st) + free(np, M_NETGRAPH); + } + return (error); +} + /* * Handle an incoming packet. The packet includes the IP header. */ @@ -661,7 +753,14 @@ ng_pptpgre_rcvdata_lower(hook_p hook, item_p item) int error = 0; struct mbuf *m; - NGI_GET_M(item, m); + roqh sendq = SLIST_HEAD_INITIALIZER(sendq); /* send queue on stack */ + struct ng_pptpgre_roq *last = NULL; /* last packet in the sendq */ + struct ng_pptpgre_roq *np, *prev; + struct ng_pptpgre_roq temp = { { NULL }, NULL, 0 }; + long diff; + u_int32_t seq; + + m = NGI_M(item); /* Update stats */ priv->stats.recvPackets++; priv->stats.recvOctets += m->m_pkthdr.len; @@ -673,18 +772,23 @@ ng_pptpgre_rcvdata_lower(hook_p hook, item_p item) } /* Safely pull up the complete IP+GRE headers */ - if (m->m_len < sizeof(*ip) + sizeof(*gre) - && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { - priv->stats.memoryFailures++; - ERROUT(ENOBUFS); + if (m->m_len < sizeof(*ip) + sizeof(*gre)) { + if ((m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { + priv->stats.memoryFailures++; + _NGI_M(item) = NULL; + ERROUT(ENOBUFS); + } + _NGI_M(item) = m; } ip = mtod(m, const struct ip *); iphlen = ip->ip_hl << 2; if (m->m_len < iphlen + sizeof(*gre)) { if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) { priv->stats.memoryFailures++; + _NGI_M(item) = NULL; ERROUT(ENOBUFS); } + _NGI_M(item) = m; ip = mtod(m, const struct ip *); } gre = (const struct greheader *)((const u_char *)ip + iphlen); @@ -696,8 +800,10 @@ ng_pptpgre_rcvdata_lower(hook_p hook, item_p item) if (m->m_len < iphlen + grelen) { if ((m = m_pullup(m, iphlen + grelen)) == NULL) { priv->stats.memoryFailures++; + _NGI_M(item) = NULL; ERROUT(ENOBUFS); } + _NGI_M(item) = m; ip = mtod(m, const struct ip *); gre = (const struct greheader *)((const u_char *)ip + iphlen); } @@ -726,7 +832,6 @@ ng_pptpgre_rcvdata_lower(hook_p hook, item_p item) const u_int32_t ack = be32dec(&gre->data[gre->hasSeq]); const int index = ack - hpriv->recvAck - 1; long sample; - long diff; /* Sanity check ack value */ if (PPTP_SEQ_DIFF(ack, hpriv->xmitSeq) > 0) { @@ -773,54 +878,178 @@ ng_pptpgre_rcvdata_lower(hook_p hook, item_p item) badAck: /* See if frame contains any data */ - if (gre->hasSeq) { - const u_int32_t seq = be32dec(&gre->data[0]); + if (!gre->hasSeq) { /* no data to deliver */ + priv->stats.recvLoneAcks++; + mtx_unlock(&hpriv->mtx); + ERROUT(0); + } - /* Sanity check sequence number */ - if (PPTP_SEQ_DIFF(seq, hpriv->recvSeq) <= 0) { - if (seq == hpriv->recvSeq) - priv->stats.recvDuplicates++; - else - priv->stats.recvOutOfOrder++; + seq = be32dec(&gre->data[0]); + + diff = PPTP_SEQ_DIFF(seq, hpriv->recvSeq); + if (diff <= 0) { /* late or duplicate packet */ + if (diff < 0 && reorder_max == 0) /* reorder disabled */ + priv->stats.recvOutOfOrder++; /* late */ + else + priv->stats.recvDuplicates++; /* duplicate */ + mtx_unlock(&hpriv->mtx); + ERROUT(EINVAL); + } + + /* Trim mbuf down to internal payload */ + m_adj(m, iphlen + grelen); + if (extralen > 0) + m_adj(m, -extralen); + +#define INIT_SENDQ(t) do { \ + t.item = item; \ + t.seq = seq; \ + SLIST_INSERT_HEAD(&sendq, &t, next); \ + last = &t; \ + hpriv->recvSeq = seq; \ + goto deliver; \ + } while(0) + + if (diff == 1) + /* the packet came in order, place it at the start of sendq */ + INIT_SENDQ(temp); + + /* The packet came too early, try to enqueue it. + * + * Check for duplicate in the queue. After this loop, "prev" will be + * NULL if the packet should become new head of the queue, + * or else it should be inserted after the "prev". + */ + prev = SLIST_FIRST(&hpriv->roq); + SLIST_FOREACH(np, &hpriv->roq, next) { + diff = PPTP_SEQ_DIFF(np->seq, seq); + if (diff == 0) { /* do not add duplicate, drop it */ + priv->stats.recvDuplicates++; mtx_unlock(&hpriv->mtx); ERROUT(EINVAL); } - hpriv->recvSeq = seq; + if (diff > 0) { /* we found newer packet */ + if (np == prev) /* that is the head of the queue */ + prev = NULL; /* put current packet to the head */ + break; + } + prev = np; + } - /* We need to acknowledge this packet; do it soon... */ - if (!(callout_pending(&hpriv->sackTimer))) { - /* If delayed ACK is disabled, send it now */ - if (!hpriv->conf.enableDelayedAck) { /* ack now */ - ng_pptpgre_xmit(hpriv, NULL); - /* ng_pptpgre_xmit() drops the mutex */ - } else { /* ack later */ - ng_pptpgre_start_send_ack_timer(hpriv); - mtx_unlock(&hpriv->mtx); - } - } else - mtx_unlock(&hpriv->mtx); + priv->stats.recvOutOfOrder++; /* duplicate not found */ + if (hpriv->roq_len < reorder_max) + goto enqueue; /* reorder enabled and there is a room */ + + /* + * There is no room in the queue or reorder disabled. + * + * It the latter case, we may still have non-empty reorder queue + * if reorder was disabled in process of reordering. + * Then we correctly deliver the queue without growing it. + * + * In both cases, no malloc()'s until the queue is shortened. + */ + priv->stats.recvReorderOverflow++; + if (prev == NULL) { /* new packet goes before the head */ + INIT_SENDQ(temp); /* of reorder queue, so put it to sendq */ + } +#undef INIT_SENDQ - /* Trim mbuf down to internal payload */ - m_adj(m, iphlen + grelen); - if (extralen > 0) - m_adj(m, -extralen); + /* + * Current packet goes after the head of reorder queue. + * Move the head to sendq to make room for current packet. + */ + np = SLIST_FIRST(&hpriv->roq); + if (prev == np) + prev = NULL; + SLIST_REMOVE_HEAD(&hpriv->roq, next); + hpriv->roq_len--; /* we are allowed to use malloc() now */ + SLIST_INSERT_HEAD(&sendq, np, next); + last = np; + hpriv->recvSeq = np->seq; - mtx_assert(&hpriv->mtx, MA_NOTOWNED); +enqueue: + np = malloc(sizeof(*np), M_NETGRAPH, M_NOWAIT | M_ZERO); + if (np == NULL) { + priv->stats.memoryFailures++; + /* + * Emergency: we cannot save new data. + * Flush the queue delivering all queued packets preceeding + * current one despite of gaps. + */ + while (!SLIST_EMPTY(&hpriv->roq)) { + np = SLIST_FIRST(&hpriv->roq); + if (np->seq > seq) + break; + SLIST_REMOVE_HEAD(&hpriv->roq, next); + hpriv->roq_len--; + if (last == NULL) + SLIST_INSERT_HEAD(&sendq, np, next); + else + SLIST_INSERT_AFTER(last, np, next); + last = np; + } - /* Deliver frame to upper layers */ + /* + * Pretend we got all packets till the current one + * and acknowledge it. + */ + hpriv->recvSeq = seq; + ng_pptpgre_ack(hpriv); /* drops lock */ + ng_pptpgre_sendq(hpriv, &sendq, &temp); NG_FWD_NEW_DATA(error, item, hpriv->hook, m); + ERROUT(ENOMEM); + } + + /* Add current (early) packet to the reorder queue. */ + np->item = item; + np->seq = seq; + if (prev == NULL) + SLIST_INSERT_HEAD(&hpriv->roq, np, next); + else + SLIST_INSERT_AFTER(prev, np, next); + hpriv->roq_len++; + +deliver: + /* Look if we have some packets in sequence after sendq. */ + while (!SLIST_EMPTY(&hpriv->roq)) { + np = SLIST_FIRST(&hpriv->roq); + if (PPTP_SEQ_DIFF(np->seq, hpriv->recvSeq) > 1) + break; /* the gap in the sequence */ + + /* "np" is in sequence, move it to the sendq. */ + SLIST_REMOVE_HEAD(&hpriv->roq, next); + hpriv->roq_len--; + hpriv->recvSeq = np->seq; + + if (last == NULL) + SLIST_INSERT_HEAD(&sendq, np, next); + else + SLIST_INSERT_AFTER(last, np, next); + last = np; + } + + if (SLIST_EMPTY(&hpriv->roq)) { + if (callout_pending(&hpriv->reorderTimer)) + ng_uncallout(&hpriv->reorderTimer, hpriv->node); } else { - priv->stats.recvLoneAcks++; + if (!callout_pending(&hpriv->reorderTimer)) + ng_pptpgre_start_reorder_timer(hpriv); + } + + if (SLIST_EMPTY(&sendq)) { + /* Current packet has been queued, nothing to free/deliver. */ mtx_unlock(&hpriv->mtx); - NG_FREE_ITEM(item); - NG_FREE_M(m); /* no data to deliver */ + return (error); } + /* We need to acknowledge last packet; do it soon... */ + ng_pptpgre_ack(hpriv); /* drops lock */ + ng_pptpgre_sendq(hpriv, &sendq, &temp); return (error); done: NG_FREE_ITEM(item); - NG_FREE_M(m); return (error); } @@ -916,6 +1145,68 @@ ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2) mtx_assert(&hpriv->mtx, MA_NOTOWNED); } +/* + * Start a timer for the reorder queue. This assumes the timer is not + * already running. + */ +static void +ng_pptpgre_start_reorder_timer(hpriv_p hpriv) +{ + int ticks; + + /* Be conservative: timeout can happen up to 1 tick early */ + ticks = (((reorder_timeout * hz) + 1000 - 1) / 1000) + 1; + ng_callout(&hpriv->reorderTimer, hpriv->node, hpriv->hook, + ticks, ng_pptpgre_reorder_timeout, hpriv, 0); +} + +/* + * The oldest packet spent too much time in the reorder queue. + * Deliver it and next packets in sequence, if any. + */ +static void +ng_pptpgre_reorder_timeout(node_p node, hook_p hook, void *arg1, int arg2) +{ + const priv_p priv = NG_NODE_PRIVATE(node); + const hpriv_p hpriv = arg1; + roqh sendq = SLIST_HEAD_INITIALIZER(sendq); + struct ng_pptpgre_roq *np, *last = NULL; + + priv->stats.recvReorderTimeouts++; + mtx_lock(&hpriv->mtx); + if (SLIST_EMPTY(&hpriv->roq)) { /* should not happen */ + mtx_unlock(&hpriv->mtx); + return; + } + + last = np = SLIST_FIRST(&hpriv->roq); + hpriv->roq_len--; + SLIST_REMOVE_HEAD(&hpriv->roq, next); + SLIST_INSERT_HEAD(&sendq, np, next); + + /* Look if we have more packets in sequence */ + while (!SLIST_EMPTY(&hpriv->roq)) { + np = SLIST_FIRST(&hpriv->roq); + if (PPTP_SEQ_DIFF(np->seq, last->seq) > 1) + break; /* the gap in the sequence */ + + /* Next packet is in sequence, move it to the sendq. */ + hpriv->roq_len--; + SLIST_REMOVE_HEAD(&hpriv->roq, next); + SLIST_INSERT_AFTER(last, np, next); + last = np; + } + + hpriv->recvSeq = last->seq; + if (!SLIST_EMPTY(&hpriv->roq)) + ng_pptpgre_start_reorder_timer(hpriv); + + /* We need to acknowledge last packet; do it soon... */ + ng_pptpgre_ack(hpriv); /* drops lock */ + ng_pptpgre_sendq(hpriv, &sendq, NULL); + mtx_assert(&hpriv->mtx, MA_NOTOWNED); +} + /************************************************************************* MISC FUNCTIONS *************************************************************************/ @@ -943,6 +1234,8 @@ ng_pptpgre_find_session(priv_p privp, u_int16_t cid) static void ng_pptpgre_reset(hpriv_p hpriv) { + struct ng_pptpgre_roq *np; + /* Reset adaptive timeout state */ hpriv->ato = PPTP_MAX_TIMEOUT; hpriv->rtt = PPTP_TIME_SCALE / 10; @@ -965,6 +1258,16 @@ ng_pptpgre_reset(hpriv_p hpriv) /* Stop timers */ ng_uncallout(&hpriv->sackTimer, hpriv->node); ng_uncallout(&hpriv->rackTimer, hpriv->node); + ng_uncallout(&hpriv->reorderTimer, hpriv->node); + + /* Clear reorder queue */ + while (!SLIST_EMPTY(&hpriv->roq)) { + np = SLIST_FIRST(&hpriv->roq); + SLIST_REMOVE_HEAD(&hpriv->roq, next); + NG_FREE_ITEM(np->item); + free(np, M_NETGRAPH); + } + hpriv->roq_len = 0; } /* diff --git a/sys/netgraph/ng_pptpgre.h b/sys/netgraph/ng_pptpgre.h index ecba3ce1f37d..08084917dcca 100644 --- a/sys/netgraph/ng_pptpgre.h +++ b/sys/netgraph/ng_pptpgre.h @@ -100,6 +100,10 @@ struct ng_pptpgre_stats { u_int32_t recvLoneAcks; /* ack-only packets rec'd */ u_int32_t recvAckTimeouts; /* times peer failed to ack in time */ u_int32_t memoryFailures; /* times we couldn't allocate memory */ + u_int32_t recvReorderOverflow; /* times we dropped GRE packet + due to overflow of reorder queue */ + u_int32_t recvReorderTimeouts; /* times we flushed reorder queue + due to timeout */ }; /* Keep this in sync with the above structure definition */ @@ -120,6 +124,8 @@ struct ng_pptpgre_stats { { "recvLoneAcks", &ng_parse_uint32_type }, \ { "recvAckTimeouts", &ng_parse_uint32_type }, \ { "memoryFailures", &ng_parse_uint32_type }, \ + { "recvReorderOverflow", &ng_parse_uint32_type}, \ + { "recvReorderTimeouts", &ng_parse_uint32_type}, \ { NULL } \ } diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index ddf5a4ddfd27..08f40974b07a 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3733,6 +3733,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er return (0); } +#if defined(INET) || defined(INET6) static struct sctp_tcb * sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p, uint16_t port, @@ -3822,6 +3823,7 @@ sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p, } return (NULL); } +#endif static struct mbuf * sctp_add_cookie(struct mbuf *init, int init_offset, @@ -12699,9 +12701,11 @@ sctp_lower_sosend(struct socket *so, SCTP_INP_WUNLOCK(inp); /* With the lock applied look again */ stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, NULL); +#if defined(INET) || defined(INET6) if ((stcb == NULL) && (control != NULL) && (port > 0)) { stcb = sctp_findassociation_cmsgs(&t_inp, port, control, &net, &error); } +#endif if (stcb == NULL) { SCTP_INP_WLOCK(inp); SCTP_INP_DECR_REF(inp); diff --git a/sys/powerpc/include/atomic.h b/sys/powerpc/include/atomic.h index 1b3c084db196..c8e1e8447cc7 100644 --- a/sys/powerpc/include/atomic.h +++ b/sys/powerpc/include/atomic.h @@ -510,7 +510,7 @@ atomic_load_acq_##TYPE(volatile u_##TYPE *p) \ u_##TYPE v; \ \ v = *p; \ - mb(); \ + powerpc_lwsync(); \ return (v); \ } \ \ diff --git a/sys/powerpc/include/cpu.h b/sys/powerpc/include/cpu.h index 3573a0a85d20..00f8437c8c49 100644 --- a/sys/powerpc/include/cpu.h +++ b/sys/powerpc/include/cpu.h @@ -128,6 +128,7 @@ get_cyclecount(void) #define cpu_getstack(td) ((td)->td_frame->fixreg[1]) #define cpu_spinwait() __asm __volatile("or 27,27,27") /* yield */ +#define cpu_lock_delay() DELAY(1) extern char btext[]; extern char etext[]; diff --git a/sys/powerpc/powerpc/mp_machdep.c b/sys/powerpc/powerpc/mp_machdep.c index a0a97d4af3f2..49e259ad50b9 100644 --- a/sys/powerpc/powerpc/mp_machdep.c +++ b/sys/powerpc/powerpc/mp_machdep.c @@ -100,7 +100,11 @@ machdep_ap_bootstrap(void) /* Serialize console output and AP count increment */ mtx_lock_spin(&ap_boot_mtx); ap_awake++; - printf("SMP: AP CPU #%d launched\n", PCPU_GET(cpuid)); + if (bootverbose) + printf("SMP: AP CPU #%d launched\n", PCPU_GET(cpuid)); + else + printf("%s%d%s", ap_awake == 2 ? "Launching APs: " : "", + PCPU_GET(cpuid), ap_awake == mp_ncpus ? "\n" : " "); mtx_unlock_spin(&ap_boot_mtx); while(smp_started == 0) diff --git a/sys/riscv/include/cpu.h b/sys/riscv/include/cpu.h index 92c5c67ef597..989f8946333d 100644 --- a/sys/riscv/include/cpu.h +++ b/sys/riscv/include/cpu.h @@ -46,6 +46,7 @@ #define cpu_getstack(td) ((td)->td_frame->tf_sp) #define cpu_setstack(td, sp) ((td)->td_frame->tf_sp = (sp)) #define cpu_spinwait() /* nothing */ +#define cpu_lock_delay() DELAY(1) #ifdef _KERNEL diff --git a/sys/riscv/riscv/pmap.c b/sys/riscv/riscv/pmap.c index 22bec6355684..0e1299d6509b 100644 --- a/sys/riscv/riscv/pmap.c +++ b/sys/riscv/riscv/pmap.c @@ -2098,13 +2098,20 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, new_l3 |= PTE_W; if ((va >> 63) == 0) new_l3 |= PTE_U; - else if (prot & VM_PROT_WRITE) - new_l3 |= PTE_D; new_l3 |= (pn << PTE_PPN0_S); if ((flags & PMAP_ENTER_WIRED) != 0) new_l3 |= PTE_SW_WIRED; - if ((m->oflags & VPO_UNMANAGED) == 0) + + /* + * Set modified bit gratuitously for writeable mappings if + * the page is unmanaged. We do not want to take a fault + * to do the dirty bit accounting for these mappings. + */ + if ((m->oflags & VPO_UNMANAGED) != 0) { + if (prot & VM_PROT_WRITE) + new_l3 |= PTE_D; + } else new_l3 |= PTE_SW_MANAGED; CTR2(KTR_PMAP, "pmap_enter: %.16lx -> %.16lx", va, pa); diff --git a/sys/sparc64/include/cpu.h b/sys/sparc64/include/cpu.h index 54deaf415167..a91159f6a7a2 100644 --- a/sys/sparc64/include/cpu.h +++ b/sys/sparc64/include/cpu.h @@ -48,6 +48,7 @@ #define cpu_getstack(td) ((td)->td_frame->tf_sp) #define cpu_setstack(td, sp) ((td)->td_frame->tf_sp = (sp)) #define cpu_spinwait() /* nothing */ +#define cpu_lock_delay() DELAY(1) #ifdef _KERNEL diff --git a/sys/sys/capability.h b/sys/sys/capability.h index 4b07c090e405..39195e034c56 100644 --- a/sys/sys/capability.h +++ b/sys/sys/capability.h @@ -35,7 +35,8 @@ * Historically, the key userspace and kernel Capsicum definitions were found * in this file. However, it conflicted with POSIX.1e's capability.h, so has * been renamed capsicum.h. The file remains for backwards compatibility - * reasons as a nested include. + * reasons as a nested include. It is expected to be removed before + * FreeBSD 13. */ #ifndef _SYS_CAPABILITY_H_ #define _SYS_CAPABILITY_H_ diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index 93dc23641c7b..94bb6b490b67 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -379,7 +379,8 @@ struct uio; /* * From uipc_socket and friends */ -int getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len); +int getsockaddr(struct sockaddr **namp, const struct sockaddr *uaddr, + size_t len); int getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp, u_int *fflagp, struct filecaps *havecaps); void soabort(struct socket *so); diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index 2c5652c7b552..3545745f5a7f 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -243,7 +243,7 @@ int kern_setitimer(struct thread *, u_int, struct itimerval *, struct itimerval *); int kern_setrlimit(struct thread *, u_int, struct rlimit *); int kern_setsockopt(struct thread *td, int s, int level, int name, - void *optval, enum uio_seg valseg, socklen_t valsize); + const void *optval, enum uio_seg valseg, socklen_t valsize); int kern_settimeofday(struct thread *td, struct timeval *tv, struct timezone *tzp); int kern_shm_open(struct thread *td, const char *userpath, int flags, diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index fa54d1234201..a4e12429ebe3 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -99,7 +99,7 @@ struct mount_args { char type_l_[PADL_(const char *)]; const char * type; char type_r_[PADR_(const char *)]; char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; - char data_l_[PADL_(caddr_t)]; caddr_t data; char data_r_[PADR_(caddr_t)]; + char data_l_[PADL_(void *)]; void * data; char data_r_[PADR_(void *)]; }; struct unmount_args { char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; @@ -132,7 +132,7 @@ struct sendmsg_args { }; struct recvfrom_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char buf_l_[PADL_(caddr_t)]; caddr_t buf; char buf_r_[PADR_(caddr_t)]; + char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)]; char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; char from_l_[PADL_(struct sockaddr *)]; struct sockaddr * from; char from_r_[PADR_(struct sockaddr *)]; @@ -185,7 +185,7 @@ struct getegid_args { register_t dummy; }; struct profil_args { - char samples_l_[PADL_(caddr_t)]; caddr_t samples; char samples_r_[PADR_(caddr_t)]; + char samples_l_[PADL_(char *)]; char * samples; char samples_r_[PADR_(char *)]; char size_l_[PADL_(size_t)]; size_t size; char size_r_[PADR_(size_t)]; char offset_l_[PADL_(size_t)]; size_t offset; char offset_r_[PADR_(size_t)]; char scale_l_[PADL_(u_int)]; u_int scale; char scale_r_[PADR_(u_int)]; @@ -219,7 +219,7 @@ struct sigaltstack_args { struct ioctl_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char com_l_[PADL_(u_long)]; u_long com; char com_r_[PADR_(u_long)]; - char data_l_[PADL_(caddr_t)]; caddr_t data; char data_r_[PADR_(caddr_t)]; + char data_l_[PADL_(char *)]; char * data; char data_r_[PADR_(char *)]; }; struct reboot_args { char opt_l_[PADL_(int)]; int opt; char opt_r_[PADR_(int)]; @@ -347,7 +347,7 @@ struct socket_args { }; struct connect_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char name_l_[PADL_(caddr_t)]; caddr_t name; char name_r_[PADR_(caddr_t)]; + char name_l_[PADL_(const struct sockaddr *)]; const struct sockaddr * name; char name_r_[PADR_(const struct sockaddr *)]; char namelen_l_[PADL_(int)]; int namelen; char namelen_r_[PADR_(int)]; }; struct getpriority_args { @@ -356,14 +356,14 @@ struct getpriority_args { }; struct bind_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char name_l_[PADL_(caddr_t)]; caddr_t name; char name_r_[PADR_(caddr_t)]; + char name_l_[PADL_(const struct sockaddr *)]; const struct sockaddr * name; char name_r_[PADR_(const struct sockaddr *)]; char namelen_l_[PADL_(int)]; int namelen; char namelen_r_[PADR_(int)]; }; struct setsockopt_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; char level_l_[PADL_(int)]; int level; char level_r_[PADR_(int)]; char name_l_[PADL_(int)]; int name; char name_r_[PADR_(int)]; - char val_l_[PADL_(caddr_t)]; caddr_t val; char val_r_[PADR_(caddr_t)]; + char val_l_[PADL_(const void *)]; const void * val; char val_r_[PADR_(const void *)]; char valsize_l_[PADL_(int)]; int valsize; char valsize_r_[PADR_(int)]; }; struct listen_args { @@ -382,7 +382,7 @@ struct getsockopt_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; char level_l_[PADL_(int)]; int level; char level_r_[PADR_(int)]; char name_l_[PADL_(int)]; int name; char name_r_[PADR_(int)]; - char val_l_[PADL_(caddr_t)]; caddr_t val; char val_r_[PADR_(caddr_t)]; + char val_l_[PADL_(void *)]; void * val; char val_r_[PADR_(void *)]; char avalsize_l_[PADL_(int *)]; int * avalsize; char avalsize_r_[PADR_(int *)]; }; struct readv_args { @@ -430,10 +430,10 @@ struct mkfifo_args { }; struct sendto_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char buf_l_[PADL_(caddr_t)]; caddr_t buf; char buf_r_[PADR_(caddr_t)]; + char buf_l_[PADL_(const void *)]; const void * buf; char buf_r_[PADR_(const void *)]; char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; - char to_l_[PADL_(caddr_t)]; caddr_t to; char to_r_[PADR_(caddr_t)]; + char to_l_[PADL_(const struct sockaddr *)]; const struct sockaddr * to; char to_r_[PADR_(const struct sockaddr *)]; char tolen_l_[PADL_(int)]; int tolen; char tolen_r_[PADR_(int)]; }; struct shutdown_args { @@ -471,7 +471,7 @@ struct quotactl_args { char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)]; char uid_l_[PADL_(int)]; int uid; char uid_r_[PADR_(int)]; - char arg_l_[PADL_(caddr_t)]; caddr_t arg; char arg_r_[PADR_(caddr_t)]; + char arg_l_[PADL_(void *)]; void * arg; char arg_r_[PADR_(void *)]; }; struct oquota_args { register_t dummy; @@ -484,7 +484,7 @@ struct nlm_syscall_args { }; struct nfssvc_args { char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)]; - char argp_l_[PADL_(caddr_t)]; caddr_t argp; char argp_r_[PADR_(caddr_t)]; + char argp_l_[PADL_(void *)]; void * argp; char argp_r_[PADR_(void *)]; }; struct lgetfh_args { char fname_l_[PADL_(const char *)]; const char * fname; char fname_r_[PADR_(const char *)]; @@ -1318,9 +1318,9 @@ struct sctp_peeloff_args { }; struct sctp_generic_sendmsg_args { char sd_l_[PADL_(int)]; int sd; char sd_r_[PADR_(int)]; - char msg_l_[PADL_(caddr_t)]; caddr_t msg; char msg_r_[PADR_(caddr_t)]; + char msg_l_[PADL_(void *)]; void * msg; char msg_r_[PADR_(void *)]; char mlen_l_[PADL_(int)]; int mlen; char mlen_r_[PADR_(int)]; - char to_l_[PADL_(caddr_t)]; caddr_t to; char to_r_[PADR_(caddr_t)]; + char to_l_[PADL_(struct sockaddr *)]; struct sockaddr * to; char to_r_[PADR_(struct sockaddr *)]; char tolen_l_[PADL_(__socklen_t)]; __socklen_t tolen; char tolen_r_[PADR_(__socklen_t)]; char sinfo_l_[PADL_(struct sctp_sndrcvinfo *)]; struct sctp_sndrcvinfo * sinfo; char sinfo_r_[PADR_(struct sctp_sndrcvinfo *)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; @@ -1329,7 +1329,7 @@ struct sctp_generic_sendmsg_iov_args { char sd_l_[PADL_(int)]; int sd; char sd_r_[PADR_(int)]; char iov_l_[PADL_(struct iovec *)]; struct iovec * iov; char iov_r_[PADR_(struct iovec *)]; char iovlen_l_[PADL_(int)]; int iovlen; char iovlen_r_[PADR_(int)]; - char to_l_[PADL_(caddr_t)]; caddr_t to; char to_r_[PADR_(caddr_t)]; + char to_l_[PADL_(struct sockaddr *)]; struct sockaddr * to; char to_r_[PADR_(struct sockaddr *)]; char tolen_l_[PADL_(__socklen_t)]; __socklen_t tolen; char tolen_r_[PADR_(__socklen_t)]; char sinfo_l_[PADL_(struct sctp_sndrcvinfo *)]; struct sctp_sndrcvinfo * sinfo; char sinfo_r_[PADR_(struct sctp_sndrcvinfo *)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; @@ -1356,7 +1356,7 @@ struct pwrite_args { char offset_l_[PADL_(off_t)]; off_t offset; char offset_r_[PADR_(off_t)]; }; struct mmap_args { - char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; + char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)]; char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; @@ -1645,13 +1645,13 @@ struct cap_fcntls_get_args { struct bindat_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char name_l_[PADL_(caddr_t)]; caddr_t name; char name_r_[PADR_(caddr_t)]; + char name_l_[PADL_(const struct sockaddr *)]; const struct sockaddr * name; char name_r_[PADR_(const struct sockaddr *)]; char namelen_l_[PADL_(int)]; int namelen; char namelen_r_[PADR_(int)]; }; struct connectat_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char name_l_[PADL_(caddr_t)]; caddr_t name; char name_r_[PADR_(caddr_t)]; + char name_l_[PADL_(const struct sockaddr *)]; const struct sockaddr * name; char name_r_[PADR_(const struct sockaddr *)]; char namelen_l_[PADL_(int)]; int namelen; char namelen_r_[PADR_(int)]; }; struct chflagsat_args { @@ -2207,13 +2207,13 @@ struct sethostname_args { }; struct osend_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char buf_l_[PADL_(caddr_t)]; caddr_t buf; char buf_r_[PADR_(caddr_t)]; + char buf_l_[PADL_(const void *)]; const void * buf; char buf_r_[PADR_(const void *)]; char len_l_[PADL_(int)]; int len; char len_r_[PADR_(int)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; }; struct orecv_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char buf_l_[PADL_(caddr_t)]; caddr_t buf; char buf_r_[PADR_(caddr_t)]; + char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)]; char len_l_[PADL_(int)]; int len; char len_r_[PADR_(int)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; }; @@ -2245,7 +2245,7 @@ struct orecvmsg_args { }; struct osendmsg_args { char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char msg_l_[PADL_(caddr_t)]; caddr_t msg; char msg_r_[PADR_(caddr_t)]; + char msg_l_[PADL_(const void *)]; const void * msg; char msg_r_[PADR_(const void *)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; }; struct otruncate_args { @@ -2258,7 +2258,7 @@ struct oftruncate_args { }; struct ogetpeername_args { char fdes_l_[PADL_(int)]; int fdes; char fdes_r_[PADR_(int)]; - char asa_l_[PADL_(caddr_t)]; caddr_t asa; char asa_r_[PADR_(caddr_t)]; + char asa_l_[PADL_(struct sockaddr *)]; struct sockaddr * asa; char asa_r_[PADR_(struct sockaddr *)]; char alen_l_[PADL_(int *)]; int * alen; char alen_r_[PADR_(int *)]; }; struct osethostid_args { @@ -2401,7 +2401,7 @@ struct freebsd6_pwrite_args { char offset_l_[PADL_(off_t)]; off_t offset; char offset_r_[PADR_(off_t)]; }; struct freebsd6_mmap_args { - char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; + char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)]; char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; diff --git a/sys/sys/tty.h b/sys/sys/tty.h index c85ca559361a..8b458cf115dc 100644 --- a/sys/sys/tty.h +++ b/sys/sys/tty.h @@ -133,12 +133,8 @@ struct tty { void *t_hooksoftc; /* (t) Soft config, for hooks. */ struct cdev *t_dev; /* (c) Primary character device. */ -#ifndef PRINTF_BUFR_SIZE -#define TTY_PRINTF_SIZE 256 -#else -#define TTY_PRINTF_SIZE PRINTF_BUFR_SIZE -#endif - char t_prbuf[TTY_PRINTF_SIZE]; /* (t) */ + size_t t_prbufsz; /* (t) SIGINFO buffer size. */ + char t_prbuf[]; /* (t) SIGINFO buffer. */ }; /* diff --git a/sys/vm/vm_kern.c b/sys/vm/vm_kern.c index 79108ce1ef64..3720ffbee161 100644 --- a/sys/vm/vm_kern.c +++ b/sys/vm/vm_kern.c @@ -650,8 +650,8 @@ kmap_alloc_wait(vm_map_t map, vm_size_t size) map->needs_wakeup = TRUE; vm_map_unlock_and_wait(map, 0); } - vm_map_insert(map, NULL, 0, addr, addr + size, VM_PROT_ALL, - VM_PROT_ALL, MAP_ACC_CHARGED); + vm_map_insert(map, NULL, 0, addr, addr + size, VM_PROT_RW, VM_PROT_RW, + MAP_ACC_CHARGED); vm_map_unlock(map); return (addr); } diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index 9f592c38410a..c69e5e8bd9d7 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -973,7 +973,7 @@ vm_pageout_laundry_worker(void *arg) shortfall = 0; in_shortfall = false; shortfall_cycle = 0; - target = 0; + last_target = target = 0; nfreed = 0; /* diff --git a/sys/x86/x86/delay.c b/sys/x86/x86/delay.c index d0900c4330b8..c767250954da 100644 --- a/sys/x86/x86/delay.c +++ b/sys/x86/x86/delay.c @@ -51,11 +51,23 @@ __FBSDID("$FreeBSD$"); #include <machine/cpu.h> #include <x86/init.h> -static u_int -get_tsc(__unused struct timecounter *tc) +static void +delay_tsc(int n) { + uint64_t end, now; - return (rdtsc32()); + /* + * Pin the current thread ensure correct behavior if the TSCs + * on different CPUs are not in sync. + */ + sched_pin(); + now = rdtsc(); + end = now + tsc_freq * n / 1000000; + do { + cpu_spinwait(); + now = rdtsc(); + } while (now < end); + sched_unpin(); } static int @@ -66,22 +78,24 @@ delay_tc(int n) uint64_t end, freq, now; u_int last, mask, u; - tc = timecounter; - freq = atomic_load_acq_64(&tsc_freq); - if (tsc_is_invariant && freq != 0) { - func = get_tsc; - mask = ~0u; - } else { - if (tc->tc_quality <= 0) - return (0); - func = tc->tc_get_timecount; - mask = tc->tc_counter_mask; - freq = tc->tc_frequency; + /* + * Only use the TSC if it is P-state invariant. If the TSC is + * not P-state invariant and the CPU is not running at the + * "full" P-state, then the TSC will increment at some rate + * less than tsc_freq and delay_tsc() will wait too long. + */ + if (tsc_is_invariant && tsc_freq != 0) { + delay_tsc(n); + return (1); } + tc = timecounter; + if (tc->tc_quality <= 0) + return (0); + func = tc->tc_get_timecount; + mask = tc->tc_counter_mask; + freq = tc->tc_frequency; now = 0; end = freq * n / 1000000; - if (func == get_tsc) - sched_pin(); last = func(tc) & mask; do { cpu_spinwait(); @@ -92,8 +106,6 @@ delay_tc(int n) now += u - last; last = u; } while (now < end); - if (func == get_tsc) - sched_unpin(); return (1); } @@ -110,3 +122,22 @@ DELAY(int n) init_ops.early_delay(n); TSEXIT(); } + +void +cpu_lock_delay(void) +{ + + /* + * Use TSC to wait for a usec if present, otherwise fall back + * to reading from port 0x84. We can't call into timecounters + * for this delay since timecounters might use spin locks. + * + * Note that unlike delay_tc(), this uses the TSC even if it + * is not P-state invariant. For this function it is ok to + * wait even a few usecs. + */ + if (tsc_freq != 0) + delay_tsc(1); + else + inb(0x84); +} |
