Date: Tue, 18 Dec 2018 12:06:48 -0500 From: Austin Shafer <amshafer64@gmail.com> To: Konstantin Belousov <kostikbel@gmail.com> Cc: freebsd-hackers@freebsd.org Subject: Re: ENOMEM when calling sysctl_handle_int from custom handler Message-ID: <m25zvqix1z.fsf@triplebuff.com> In-Reply-To: <20181218055828.GA60291@kib.kiev.ua> References: <861s6fpyua.fsf@triplebuff.com> <20181218055828.GA60291@kib.kiev.ua>
next in thread | previous in thread | raw e-mail | index | archive | help
Konstantin Belousov <kostikbel@gmail.com> writes: > On Mon, Dec 17, 2018 at 05:34:05PM -0500, Austin Shafer wrote: >> My best guess: >> I've tried to dig around in the debugger (using kgdb) but haven't been >> able to find anything. The only difference I noticed while tracing was >> that the "oldlenp" field in the sysctl_args struct passed in from >> userland was 0 when calling my handler and 8 when calling the default >> handler. I am not very familiar with the sysctl implementation, but this >> affected the valid length in the sysctl_req which ended up returning >> ENOMEM from sysctl_old_user. You can watch/confirm this change in sysctl_req >> using the following dtrace one-liner. Its unclear why changing the >> sysctl handler would affect the arguments passed to it. > Yes, this is most likely cause for your issue. ENOMEM does not have > anything with the memory shortage, but with the fact that the oldlen > is too short for int copyout. > > Note that for the int-typed oid, old and new len should be 4 (not 0 and > not 8). Why your userspace code passed such length is the question to > you. > Thanks for the reply! I'm just using the sysctl(8) utility in the examples above so the valid length passing from userspace is not done by me. Based on what you said it seems to me that sysctl(8) is not passing the correct values then? This would be strange since all other sysctls work using sysctl(8). I'm more than happy to dig deep and debug sysctl(8) to see if it is the culprit. I had assumed it was working fine and that the error was on my end in the kernel module. You are right about the userspace passed values being whats causing my problems though. I wrote a short program to call sysctlbyname (with the correct length as you specified above) and now I can set the value of the sysctl: // read_sysctl.c int main (int argc, char *argv[]) { int error, old, new = 3; size_t size; size = sizeof(int); ... error = sysctlbyname(argv[1], &old, &size, &new, size); ... } // dtrace -n '*::sysctl_handle_int:entry /execname == "read_sysctl" / { print(*args[3]); }' CPU ID FUNCTION:NAME 2 27761 sysctl_handle_int:entry struct sysctl_req { struct thread *td = 0xfffff80003b38580 int lock = 0x1 void *oldptr = 0x7fffffffd71c size_t oldlen = 0x4 size_t oldidx = 0 int (*)() oldfunc = kernel`sysctl_old_user void *newptr = 0 size_t newlen = 0 size_t newidx = 0 int (*)() newfunc = kernel`sysctl_new_user size_t validlen = 0x4 int flags = 0 } 2 27761 sysctl_handle_int:entry struct sysctl_req { struct thread *td = 0xfffff80003b38580 int lock = 0x1 void *oldptr = 0x7fffffffeb28 size_t oldlen = 0x4 size_t oldidx = 0 int (*)() oldfunc = kernel`sysctl_old_user void *newptr = 0x7fffffffeb24 size_t newlen = 0x4 size_t newidx = 0 int (*)() newfunc = kernel`sysctl_new_user size_t validlen = 0x4 int flags = 0 } Also out of curiosity, the dtrace probes show multiple sysctl_handle_int evaluations. Is this for each root and sub-node in the sysctl tree? Thats what it looks like to me but I'd love to know for sure. Thanks for all the help! Austin Shafer
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?m25zvqix1z.fsf>