Index: lib/libc/gen/sysctlbyname.c =================================================================== --- lib/libc/gen/sysctlbyname.c +++ lib/libc/gen/sysctlbyname.c @@ -1,11 +1,29 @@ -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- +/*- + * SPDX-License-Identifier: BSD-2-Clause * + * Copyright 2018 Pawel Biernacki, Mysterious Code Ltd. + * + * 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 AUTHOR 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 AUTHOR 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. */ #include @@ -13,16 +31,16 @@ #include #include +#include + +extern int __sysctlbyname(const char *name, u_int namelen, void *oldp, + size_t *oldlenp, const void *newp, size_t newlen); int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, const void *newp, size_t newlen) { - int real_oid[CTL_MAXNAME+2]; - size_t oidlen; - - oidlen = sizeof(real_oid) / sizeof(int); - if (sysctlnametomib(name, real_oid, &oidlen) < 0) - return (-1); - return (sysctl(real_oid, oidlen, oldp, oldlenp, newp, newlen)); + u_int len = strlen(name); + return (__sysctlbyname(name, len, oldp, oldlenp, newp, newlen)); } + Index: lib/libc/sys/Symbol.map =================================================================== --- lib/libc/sys/Symbol.map +++ lib/libc/sys/Symbol.map @@ -399,6 +399,7 @@ statfs; cpuset_getdomain; cpuset_setdomain; + __sysctlbyname; }; FBSDprivate_1.0 { @@ -456,6 +457,8 @@ __sys___syscall; ___sysctl; __sys___sysctl; + ___sysctlbyname; + __sys___sysctlbyname; __umtx_op; __sys__umtx_op; _abort2; Index: sys/compat/freebsd32/capabilities.conf =================================================================== --- sys/compat/freebsd32/capabilities.conf +++ sys/compat/freebsd32/capabilities.conf @@ -48,6 +48,7 @@ __mac_set_fd __mac_set_proc freebsd32_sysctl +freebsd32_sysctlbyname freebsd32_umtx_op abort2 accept Index: sys/compat/freebsd32/freebsd32_misc.c =================================================================== --- sys/compat/freebsd32/freebsd32_misc.c +++ sys/compat/freebsd32/freebsd32_misc.c @@ -118,6 +118,8 @@ FEATURE(compat_freebsd_32bit, "Compatible with 32-bit FreeBSD"); +MALLOC_DECLARE(M_SYSCTL); + #ifdef __amd64__ CTASSERT(sizeof(struct timeval32) == 8); CTASSERT(sizeof(struct timespec32) == 8); @@ -2289,6 +2291,53 @@ return (0); } +int +freebsd32_sysctlbyname(struct thread *td, struct + freebsd32_sysctlbyname_args *uap) +{ + char *name; + int oid[CTL_MAXNAME]; + size_t namelen, oidlen, oldlen, rv; + int error; + uint32_t tmp; + + namelen = uap->namelen; + if (namelen > MAXPATHLEN || namelen < 1) + return (EINVAL); + + name = malloc(namelen, M_SYSCTL, M_WAITOK); + error = copyin(uap->name, name, namelen); + if (error) + goto out; + + oid[0] = 0; + oid[1] = 3; + oidlen = sizeof(oid); + error = kernel_sysctl(td, oid, 2, oid, &oidlen, (void *)name, namelen, + &rv, 0); + if (error) + goto out; + + if (uap->oldlenp) { + error = fueword32(uap->oldlenp, &tmp); + oldlen = tmp; + } else { + oldlen = 0; + } + if (error) + goto out; + error = userland_sysctl(td, oid, rv / sizeof(int), uap->old, + &oldlen, 1, (void *)uap->new, uap->newlen, &rv, 0); + if (error) + goto out; + if (uap->oldlenp) + suword32(uap->oldlenp, rv); + +out: + free(name, M_SYSCTL); + return (error); +} + int freebsd32_jail(struct thread *td, struct freebsd32_jail_args *uap) { Index: sys/compat/freebsd32/freebsd32_proto.h =================================================================== --- sys/compat/freebsd32/freebsd32_proto.h +++ sys/compat/freebsd32/freebsd32_proto.h @@ -710,6 +710,14 @@ char mask_l_[PADL_(domainset_t *)]; domainset_t * mask; char mask_r_[PADR_(domainset_t *)]; char policy_l_[PADL_(int)]; int policy; char policy_r_[PADR_(int)]; }; +struct freebsd32_sysctlbyname_args { + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char namelen_l_[PADL_(u_int)]; u_int namelen; char namelen_r_[PADR_(u_int)]; + char old_l_[PADL_(void *)]; void * old; char old_r_[PADR_(void *)]; + char oldlenp_l_[PADL_(uint32_t *)]; uint32_t * oldlenp; char oldlenp_r_[PADR_(uint32_t *)]; + char new_l_[PADL_(void *)]; void * new; char new_r_[PADR_(void *)]; + char newlen_l_[PADL_(uint32_t)]; uint32_t newlen; char newlen_r_[PADR_(uint32_t)]; +}; #if !defined(PAD64_REQUIRED) && (defined(__powerpc__) || defined(__mips__)) #define PAD64_REQUIRED #endif @@ -842,6 +850,7 @@ int freebsd32_kevent(struct thread *, struct freebsd32_kevent_args *); int freebsd32_cpuset_getdomain(struct thread *, struct freebsd32_cpuset_getdomain_args *); int freebsd32_cpuset_setdomain(struct thread *, struct freebsd32_cpuset_setdomain_args *); +int freebsd32_sysctlbyname(struct thread *, struct freebsd32_sysctlbyname_args *); #ifdef COMPAT_43 @@ -1391,6 +1400,7 @@ #define FREEBSD32_SYS_AUE_freebsd32_kevent AUE_KEVENT #define FREEBSD32_SYS_AUE_freebsd32_cpuset_getdomain AUE_NULL #define FREEBSD32_SYS_AUE_freebsd32_cpuset_setdomain AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_sysctlbyname AUE_SYSCTL #undef PAD_ #undef PADL_ Index: sys/compat/freebsd32/freebsd32_syscall.h =================================================================== --- sys/compat/freebsd32/freebsd32_syscall.h +++ sys/compat/freebsd32/freebsd32_syscall.h @@ -469,4 +469,5 @@ #define FREEBSD32_SYS_freebsd32_cpuset_getdomain 561 #define FREEBSD32_SYS_freebsd32_cpuset_setdomain 562 #define FREEBSD32_SYS_getrandom 563 -#define FREEBSD32_SYS_MAXSYSCALL 564 +#define FREEBSD32_SYS_freebsd32_sysctlbyname 564 +#define FREEBSD32_SYS_MAXSYSCALL 565 Index: sys/compat/freebsd32/freebsd32_syscalls.c =================================================================== --- sys/compat/freebsd32/freebsd32_syscalls.c +++ sys/compat/freebsd32/freebsd32_syscalls.c @@ -596,4 +596,5 @@ "freebsd32_cpuset_getdomain", /* 561 = freebsd32_cpuset_getdomain */ "freebsd32_cpuset_setdomain", /* 562 = freebsd32_cpuset_setdomain */ "getrandom", /* 563 = getrandom */ + "freebsd32_sysctlbyname", /* 564 = freebsd32_sysctlbyname */ }; Index: sys/compat/freebsd32/freebsd32_sysent.c =================================================================== --- sys/compat/freebsd32/freebsd32_sysent.c +++ sys/compat/freebsd32/freebsd32_sysent.c @@ -643,4 +643,5 @@ { AS(freebsd32_cpuset_getdomain_args), (sy_call_t *)freebsd32_cpuset_getdomain, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 561 = freebsd32_cpuset_getdomain */ { AS(freebsd32_cpuset_setdomain_args), (sy_call_t *)freebsd32_cpuset_setdomain, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 562 = freebsd32_cpuset_setdomain */ { AS(getrandom_args), (sy_call_t *)sys_getrandom, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 563 = getrandom */ + { AS(freebsd32_sysctlbyname_args), (sy_call_t *)freebsd32_sysctlbyname, AUE_SYSCTL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 564 = freebsd32_sysctlbyname */ }; Index: sys/compat/freebsd32/freebsd32_systrace_args.c =================================================================== --- sys/compat/freebsd32/freebsd32_systrace_args.c +++ sys/compat/freebsd32/freebsd32_systrace_args.c @@ -3258,6 +3258,18 @@ *n_args = 3; break; } + /* freebsd32_sysctlbyname */ + case 564: { + struct freebsd32_sysctlbyname_args *p = params; + uarg[0] = (intptr_t) p->name; /* const char * */ + uarg[1] = p->namelen; /* u_int */ + uarg[2] = (intptr_t) p->old; /* void * */ + uarg[3] = (intptr_t) p->oldlenp; /* uint32_t * */ + uarg[4] = (intptr_t) p->new; /* void * */ + uarg[5] = p->newlen; /* uint32_t */ + *n_args = 6; + break; + } default: *n_args = 0; break; @@ -8758,6 +8770,31 @@ break; }; break; + /* freebsd32_sysctlbyname */ + case 564: + switch(ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "u_int"; + break; + case 2: + p = "userland void *"; + break; + case 3: + p = "userland uint32_t *"; + break; + case 4: + p = "userland void *"; + break; + case 5: + p = "uint32_t"; + break; + default: + break; + }; + break; default: break; }; @@ -10599,6 +10636,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* freebsd32_sysctlbyname */ + case 564: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; Index: sys/compat/freebsd32/syscalls.master =================================================================== --- sys/compat/freebsd32/syscalls.master +++ sys/compat/freebsd32/syscalls.master @@ -1113,5 +1113,8 @@ int policy); } 563 AUE_NULL NOPROTO { int getrandom(void *buf, size_t buflen, \ unsigned int flags); } +564 AUE_SYSCTL STD { int freebsd32_sysctlbyname(const char *name, \ + u_int namelen, void *old, uint32_t *oldlenp, \ + void *new, uint32_t newlen); } ; vim: syntax=off Index: sys/kern/capabilities.conf =================================================================== --- sys/kern/capabilities.conf +++ sys/kern/capabilities.conf @@ -58,6 +58,7 @@ ## proxying daemon in userspace. ## __sysctl +__sysctlbyname ## ## Allow umtx operations as these are scoped by address space. Index: sys/kern/init_sysent.c =================================================================== --- sys/kern/init_sysent.c +++ sys/kern/init_sysent.c @@ -613,4 +613,5 @@ { AS(cpuset_getdomain_args), (sy_call_t *)sys_cpuset_getdomain, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 561 = cpuset_getdomain */ { AS(cpuset_setdomain_args), (sy_call_t *)sys_cpuset_setdomain, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 562 = cpuset_setdomain */ { AS(getrandom_args), (sy_call_t *)sys_getrandom, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 563 = getrandom */ + { AS(sysctlbyname_args), (sy_call_t *)sys___sysctlbyname, AUE_SYSCTL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 564 = __sysctlbyname */ }; Index: sys/kern/kern_sysctl.c =================================================================== --- sys/kern/kern_sysctl.c +++ sys/kern/kern_sysctl.c @@ -71,7 +71,8 @@ #include #include -static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic"); +/* Can't be static as it's used by freebsd32 compat */ +MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic"); static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids"); static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer"); @@ -2071,6 +2072,53 @@ return (error); } +#ifndef _SYS_SYSPROTO_H_ +struct sysctlbyname_args { + const char *name; + u_int namelen; + void *old; + size_t *oldlenp; + void *new; + size_t newlen; +}; +#endif +int +sys___sysctlbyname(struct thread *td, struct sysctlbyname_args *uap) +{ + char *name; + int oid[CTL_MAXNAME]; + size_t namelen, oidlen, rv; + int error; + + namelen = uap->namelen; + if (namelen > MAXPATHLEN || namelen < 1) + return (EINVAL); + + name = malloc(namelen, M_SYSCTL, M_WAITOK); + error = copyin(uap->name, name, namelen); + if (error) + goto out; + + oid[0] = 0; + oid[1] = 3; + oidlen = sizeof(oid); + error = kernel_sysctl(td, oid, 2, oid, &oidlen, (void *)name, namelen, + &rv, 0); + if (error) + goto out; + + error = userland_sysctl(td, oid, rv / sizeof(int), uap->old, uap->oldlenp, + 0, (void *)uap->new, uap->newlen, &rv, 0); + if (error) + goto out; + if (uap->oldlenp) + error = copyout(&rv, uap->oldlenp, sizeof(rv)); + +out: + free(name, M_SYSCTL); + return (error); +} + /* * This is used from various compatibility syscalls too. That's why name * must be in kernel space. Index: sys/kern/syscalls.c =================================================================== --- sys/kern/syscalls.c +++ sys/kern/syscalls.c @@ -570,4 +570,5 @@ "cpuset_getdomain", /* 561 = cpuset_getdomain */ "cpuset_setdomain", /* 562 = cpuset_setdomain */ "getrandom", /* 563 = getrandom */ + "__sysctlbyname", /* 564 = __sysctlbyname */ }; Index: sys/kern/syscalls.master =================================================================== --- sys/kern/syscalls.master +++ sys/kern/syscalls.master @@ -1340,6 +1340,16 @@ 563 AUE_NULL STD { int getrandom( \ _Out_writes_bytes_(buflen) void *buf, \ size_t buflen, unsigned int flags); } +564 AUE_SYSCTL STD { int __sysctlbyname( \ + _In_reads_(namelen) const char *name, \ + u_int namelen, \ + _Out_writes_bytes_opt_(*oldlenp) \ + void *old, \ + _Inout_opt_ size_t *oldlenp, \ + _In_reads_bytes_opt_(newlen) \ + void *new, \ + size_t newlen); } \ + __sysctlbyname sysctlbyname_args int ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master Index: sys/kern/systrace_args.c =================================================================== --- sys/kern/systrace_args.c +++ sys/kern/systrace_args.c @@ -3266,6 +3266,18 @@ *n_args = 3; break; } + /* __sysctlbyname */ + case 564: { + struct sysctlbyname_args *p = params; + uarg[0] = (intptr_t) p->name; /* const char * */ + uarg[1] = p->namelen; /* u_int */ + uarg[2] = (intptr_t) p->old; /* void * */ + uarg[3] = (intptr_t) p->oldlenp; /* size_t * */ + uarg[4] = (intptr_t) p->new; /* void * */ + uarg[5] = p->newlen; /* size_t */ + *n_args = 6; + break; + } default: *n_args = 0; break; @@ -8710,6 +8722,31 @@ break; }; break; + /* __sysctlbyname */ + case 564: + switch(ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "u_int"; + break; + case 2: + p = "userland void *"; + break; + case 3: + p = "userland size_t *"; + break; + case 4: + p = "userland void *"; + break; + case 5: + p = "size_t"; + break; + default: + break; + }; + break; default: break; }; @@ -10586,6 +10623,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* __sysctlbyname */ + case 564: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; Index: sys/sys/syscall.h =================================================================== --- sys/sys/syscall.h +++ sys/sys/syscall.h @@ -479,4 +479,5 @@ #define SYS_cpuset_getdomain 561 #define SYS_cpuset_setdomain 562 #define SYS_getrandom 563 -#define SYS_MAXSYSCALL 564 +#define SYS___sysctlbyname 564 +#define SYS_MAXSYSCALL 565 Index: sys/sys/syscall.mk =================================================================== --- sys/sys/syscall.mk +++ sys/sys/syscall.mk @@ -404,4 +404,5 @@ kevent.o \ cpuset_getdomain.o \ cpuset_setdomain.o \ - getrandom.o + getrandom.o \ + __sysctlbyname.o Index: sys/sys/sysproto.h =================================================================== --- sys/sys/sysproto.h +++ sys/sys/sysproto.h @@ -1770,6 +1770,14 @@ char buflen_l_[PADL_(size_t)]; size_t buflen; char buflen_r_[PADR_(size_t)]; char flags_l_[PADL_(unsigned int)]; unsigned int flags; char flags_r_[PADR_(unsigned int)]; }; +struct sysctlbyname_args { + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char namelen_l_[PADL_(u_int)]; u_int namelen; char namelen_r_[PADR_(u_int)]; + char old_l_[PADL_(void *)]; void * old; char old_r_[PADR_(void *)]; + char oldlenp_l_[PADL_(size_t *)]; size_t * oldlenp; char oldlenp_r_[PADR_(size_t *)]; + char new_l_[PADL_(void *)]; void * new; char new_r_[PADR_(void *)]; + char newlen_l_[PADL_(size_t)]; size_t newlen; char newlen_r_[PADR_(size_t)]; +}; int nosys(struct thread *, struct nosys_args *); void sys_sys_exit(struct thread *, struct sys_exit_args *); int sys_fork(struct thread *, struct fork_args *); @@ -2150,6 +2158,7 @@ int sys_cpuset_getdomain(struct thread *, struct cpuset_getdomain_args *); int sys_cpuset_setdomain(struct thread *, struct cpuset_setdomain_args *); int sys_getrandom(struct thread *, struct getrandom_args *); +int sys___sysctlbyname(struct thread *, struct sysctlbyname_args *); #ifdef COMPAT_43 @@ -3047,6 +3056,7 @@ #define SYS_AUE_cpuset_getdomain AUE_NULL #define SYS_AUE_cpuset_setdomain AUE_NULL #define SYS_AUE_getrandom AUE_NULL +#define SYS_AUE___sysctlbyname AUE_SYSCTL #undef PAD_ #undef PADL_