diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 1afe586a2b08..4f1fc28337d4 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -386,16 +386,16 @@ ; ; The following are reserved for loadable syscalls ; -210 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -211 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -212 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -213 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -214 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -215 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -216 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -217 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -218 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -219 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int +210 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +211 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +212 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +213 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +214 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +215 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +216 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +217 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +218 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +219 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int ; ; The following were introduced with NetBSD/4.4Lite-2 diff --git a/sys/kern/kern_syscalls.c b/sys/kern/kern_syscalls.c index 9cb7b68bd541..d1a5c0dba5f7 100644 --- a/sys/kern/kern_syscalls.c +++ b/sys/kern/kern_syscalls.c @@ -28,12 +28,15 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include #include #include #include +#include +#include /* * Acts like "nosys" but can be identified in sysent for dynamic call @@ -55,6 +58,51 @@ lkmressys(struct thread *td, struct nosys_args *args) return (nosys(td, args)); } +static void +syscall_thread_drain(struct sysent *se) +{ + u_int32_t cnt, oldcnt; + + do { + oldcnt = se->sy_thrcnt; + KASSERT((oldcnt & SY_THR_STATIC) == 0, + ("drain on static syscall")); + cnt = oldcnt | SY_THR_DRAINING; + } while (atomic_cmpset_acq_32(&se->sy_thrcnt, oldcnt, cnt) == 0); + while (atomic_cmpset_32(&se->sy_thrcnt, SY_THR_DRAINING, + SY_THR_ABSENT) == 0) + pause("scdrn", hz/2); +} + +int +syscall_thread_enter(struct thread *td, struct sysent *se) +{ + u_int32_t cnt, oldcnt; + + do { + oldcnt = se->sy_thrcnt; + if ((oldcnt & SY_THR_STATIC) != 0) + return (0); + if ((oldcnt & (SY_THR_DRAINING | SY_THR_ABSENT)) != 0) + return (ENOSYS); + cnt = oldcnt + SY_THR_INCR; + } while (atomic_cmpset_acq_32(&se->sy_thrcnt, oldcnt, cnt) == 0); + return (0); +} + +void +syscall_thread_exit(struct thread *td, struct sysent *se) +{ + u_int32_t cnt, oldcnt; + + do { + oldcnt = se->sy_thrcnt; + if ((oldcnt & SY_THR_STATIC) != 0) + return; + cnt = oldcnt - SY_THR_INCR; + } while (atomic_cmpset_rel_32(&se->sy_thrcnt, oldcnt, cnt) == 0); +} + int syscall_register(int *offset, struct sysent *new_sysent, struct sysent *old_sysent) @@ -74,8 +122,12 @@ syscall_register(int *offset, struct sysent *new_sysent, sysent[*offset].sy_call != (sy_call_t *)lkmressys) return (EEXIST); + KASSERT(sysent[*offset].sy_thrcnt == SY_THR_ABSENT, + ("dynamic syscall is not protected")); *old_sysent = sysent[*offset]; + new_sysent->sy_thrcnt = SY_THR_ABSENT; sysent[*offset] = *new_sysent; + atomic_store_rel_32(&sysent[*offset].sy_thrcnt, 0); return (0); } @@ -83,8 +135,10 @@ int syscall_deregister(int *offset, struct sysent *old_sysent) { - if (*offset) + if (*offset) { + syscall_thread_drain(&sysent[*offset]); sysent[*offset] = *old_sysent; + } return (0); } diff --git a/sys/kern/makesyscalls.sh b/sys/kern/makesyscalls.sh index 4e55f96857cc..46e04fc53029 100644 --- a/sys/kern/makesyscalls.sh +++ b/sys/kern/makesyscalls.sh @@ -253,6 +253,10 @@ s/\$//g f=4 # toss number, type, audit event argc= 0; argssize = "0" + thr_flag = "SY_THR_STATIC" + if (flag("NOTSTATIC")) { + thr_flag = "SY_THR_ABSENT" + } if ($NF != "}") { funcalias=$(NF-2) argalias=$(NF-1) @@ -401,10 +405,10 @@ s/\$//g printf("\t{ %s, (sy_call_t *)", argssize) > sysent column = 8 + 2 + length(argssize) + 15 if (flag("NOSTD")) { - printf("%s },", "lkmressys, AUE_NULL, NULL, 0, 0, 0") > sysent + printf("%s },", "lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT") > sysent column = column + length("lkmressys") + length("AUE_NULL") + 3 } else { - printf("%s, %s, NULL, 0, 0, %s },", funcname, auditev, flags) > sysent + printf("%s, %s, NULL, 0, 0, %s, %s },", funcname, auditev, flags, thr_flag) > sysent column = column + length(funcname) + length(auditev) + length(flags) + 3 } align_sysent_comment(column) @@ -472,13 +476,13 @@ s/\$//g prefix, funcname, auditev) > sysaue } if (flag("NOSTD")) { - printf("\t{ %s, (sy_call_t *)%s, %s, NULL, 0, 0, 0 },", + printf("\t{ %s, (sy_call_t *)%s, %s, NULL, 0, 0, 0, SY_THR_ABSENT },", "0", "lkmressys", "AUE_NULL") > sysent align_sysent_comment(8 + 2 + length("0") + 15 + \ length("lkmressys") + length("AUE_NULL") + 3) } else { - printf("\t{ %s(%s,%s), %s, NULL, 0, 0, %s },", - wrap, argssize, funcname, auditev, flags) > sysent + printf("\t{ %s(%s,%s), %s, NULL, 0, 0, %s, %s },", + wrap, argssize, funcname, auditev, flags, thr_flag) > sysent align_sysent_comment(8 + 9 + length(argssize) + 1 + \ length(funcname) + length(auditev) + \ length(flags) + 4) @@ -498,7 +502,7 @@ s/\$//g next } type("OBSOL") { - printf("\t{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0 },") > sysent + printf("\t{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },") > sysent align_sysent_comment(34) printf("/* %d = obsolete %s */\n", syscall, comment) > sysent printf("\t\"obs_%s\",\t\t\t/* %d = obsolete %s */\n", @@ -509,7 +513,7 @@ s/\$//g next } type("UNIMPL") { - printf("\t{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0 },\t\t\t/* %d = %s */\n", + printf("\t{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },\t\t\t/* %d = %s */\n", syscall, comment) > sysent printf("\t\"#%d\",\t\t\t/* %d = %s */\n", syscall, syscall, comment) > sysnames diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 19bd5d46684d..4298429223bf 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -298,6 +298,9 @@ syscallenter(struct thread *td, struct syscall_args *sa) if (error != 0) goto retval; } + error = syscall_thread_enter(td, sa->callp); + if (error != 0) + goto retval; #ifdef KDTRACE_HOOKS /* @@ -327,6 +330,7 @@ syscallenter(struct thread *td, struct syscall_args *sa) (*systrace_probe_func)(sa->callp->sy_return, sa->code, sa->callp, sa->args); #endif + syscall_thread_exit(td, sa->callp); CTR4(KTR_SYSC, "syscall: p=%p error=%d return %#lx %#lx", p, error, td->td_retval[0], td->td_retval[1]); } diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 6a0ea65f7d53..8e11134d06e9 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -40,7 +40,7 @@ ; NOPROTO same as STD except do not create structure or ; function prototype in sys/sysproto.h. Does add a ; definition to syscall.h besides adding a sysent. - +; NONSTATIC syscall is loadable ; ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master @@ -403,16 +403,16 @@ ; ; The following are reserved for loadable syscalls ; -210 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -211 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -212 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -213 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -214 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -215 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -216 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -217 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -218 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int -219 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int +210 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +211 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +212 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +213 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +214 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +215 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +216 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +217 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +218 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int +219 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int ; ; The following were introduced with NetBSD/4.4Lite-2 diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h index 99e44a0d44ab..641bdae58d49 100644 --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -61,8 +61,15 @@ struct sysent { /* system call table */ u_int32_t sy_entry; /* DTrace entry ID for systrace. */ u_int32_t sy_return; /* DTrace return ID for systrace. */ u_int32_t sy_flags; /* General flags for system calls. */ + u_int32_t sy_thrcnt; }; +#define SY_THR_FLAGMASK 0x7 +#define SY_THR_STATIC 0x1 +#define SY_THR_DRAINING 0x2 +#define SY_THR_ABSENT 0x4 +#define SY_THR_INCR 0x8 + struct image_params; struct __sigset; struct syscall_args; @@ -211,6 +218,9 @@ struct nosys_args; int lkmnosys(struct thread *, struct nosys_args *); int lkmressys(struct thread *, struct nosys_args *); +int syscall_thread_enter(struct thread *td, struct sysent *se); +void syscall_thread_exit(struct thread *td, struct sysent *se); + #endif /* _KERNEL */ #endif /* !_SYS_SYSENT_H_ */