Sysctlinfo: a New Interface to Visit the Freebsd Sysctl MIB and to Pass the Objects Info to Userland
Total Page:16
File Type:pdf, Size:1020Kb
sysctlinfo: a new interface to visit the FreeBSD sysctl MIB and to pass the objects info to userland Alfonso Sabato Siciliano [email protected] BSDCan 2020, Ottawa, Canada Abstract known as sysctl MIB-Tree or sysctl tree. The 4.4BSD operating system introduced the sysctl Listing 1: sysctl tree node system call to get or set the state of the system, the struct sysctl o i d f kernel exposes the available parameters for sysctl as struct sysctl o i d l i s t o i d c h i l d r e n ; objects of a Management Information Base. Nowa- struct sysctl o i d l i s t ∗ o i d p a r e n t ; days FreeBSD has thousands of sysctl parameters, SLIST ENTRY( s y s c t l o i d ) o i d l i n k ; moreover, they can also be added or deleted dynam- i n t oid number ; u i n t o i d k i n d ; ically, so the kernel has to provide additional fea- void ∗ o i d a r g 1 ; tures for exploring the MIB, converting the name intmax t o i d a r g 2 ; of a parameter in its corresponding MIB identifier const char ∗ oid name ; and getting the info of an object (e.g., name, de- i n t (∗ o i d h a n d l e r ) (SYSCTL HANDLER ARGS) ; scription, type, etc.). Currently the kernel provides const char ∗ oid fmt ; an undocumented interface to fulfill these tasks, it i n t o i d r e f c n t ; was introduced over twenty years ago, this paper u i n t o i d r u nn i n g ; presents a new interface providing new features and const char ∗ o i d d e s c r ; improving the efficiency to access to the MIB. const char ∗ o i d l a b e l ; g ; The sysctl syscall [Listing 2] represents an OID 1 Introduction by an array of integers and an unsigned integer, when the node with the specified OID is found its The FreeBSD [1] kernel maintains a Management handler is called: it can pass the values between Information Base ("MIB") where a component the kernel and userspace via two buffers. ("object") represents a parameter of the system. The MIB provides a convenient hierarchical nota- Listing 2: sysctl() system call tion to describe the kernel namespace [2], each ob- i n t ject has a number so an Object Identifier ("OID") sysctl(const int ∗ id , u int idlevel , is a series of integers separated by periods. The void ∗ oldp , s i z e t ∗ oldlenp , sysctl system call [3] explores the MIB to find an const void ∗newp , s i z e t newlen ) ; object by its OID then it can retrieve or set the It is often necessary finding an object not for its value of the corresponding parameter. value (calling the handler) but to retrieve its infor- The MIB is implemented by a collection of trees, mation (e.g., name, description, type, next node, the root nodes are the top level objects and are etc.), so the kernel provides an undocumented in- stored as entries of a SLIST [4], each node repre- terface, sysctlinfo is a new interface to visit the sents an object and is defined by a struct sysctl oid sysctl tree and to pass the info of a node to user- [Listing 1]; the complete MIB data structure is land. 1 The rest of the paper is organized as follows: Sec- is implemented in kern sysctl.c by a set of inter- tion 2 gives a description of the current interface nal nodes: sysctl.name, sysctl.next, sysctl.oidfmt, and its limitations, Section 3 introduces sysctlinfo sysctl.oiddescr, sysctl.oidlabel and sysctlname2oid. and explains its design and implementation, real The internal nodes, except sysctl.name2oid, are world use cases are shown in the successive section. CTLTYPE NODEs with a not-NULL handler, so The work is concluded with some consideration and the desired node is specified exending the OID of future directions. the internal node, [Linsting 5] shows how getting the description of a node via sysctl.oiddesc. 2 The current interface Listing 5: current interface API -1- ioid[0] = CTL SYSCTL ; Currently the sysctl MIB consists of thousands of ioid[1] = CTL SYSCTL DESC ; objects, they have various info: types, formats, memcpy(ioid+2, oid , oidlen ∗ sizeof(int)); flags, etc., furthermore the sysctl(9) interface [6] sysctl(ioid , oidlen+2, buf, &bufsize , 0, 0); allows to add or delete an object dinamically. The The sysctl.name2oid internal node uses the newp sysctl syscall finds an object by its OID then can and oldp buffers [Listing 6]. get or set its value, only this functionality is not suf- ficient, for example the sysctl(8) utility [5] needs to Listing 6: current interface API -2- explore the MIB, convert the name of an object in its corresponding OID and finally to get the info of ioid[0] = CTL SYSCTL ; ioid[1] = CTL SYSCTL NAME2OID; an object to display properly its value [Listing 3]. sysctl(ioid, 2, oid, oidlen, name, strlen(name) +1); Listing 3: sysctl(8) % sysctl kern.ostype kern.ostype: FreeBSD Limitations of the current interface % s y s c t l −t kern.ostype kern.ostype: string The CTL MAXNAME constant, in sys/sysctl.h, defines % s y s c t l −aN the max level of an OID, actually it is 24, so kern.ostype sysctl(9) can add a node of 24 levels: ... compat. ia32 .maxdsiz x1.x2.x3.x4.x5.x6.x7.x8.x9.x10.x11. x12.x13.x14.x15.x16.x17.x18.x19.x20. During the years new members were added to x21.x22.x23.x24 struct sysctl oid [Listing 1]: oid descr and oid label, they allow to know the description of an object and and the sysctl() syscall can get or set its value. to address the modern cloud computing require- Unfortunately, the current interface can manage ments [11], [Lising 4]. an object up to CTL MAXNAME-2 levels because the internal nodes, except sysctl.name2oid, use 2 Listing 4: object description and label levels for their OID (see sysctl() of [Listing 5]), % s y s c t l −d kern.ostype consequently an utility like sysctl(8) fails with an kern.ostype: Operating system type object of 23 or 24 levels [Listing 7]. % prometheus s y s c t l exporter kern. features .compat freebsd7 Listing 7: sysctl(8) false negative s y s c t l k e r n f e a t u r e s f feature="compat % /sbin/sysctl x1 f r e e b s d 7 "g 1 sysctl: sysctl(getnext) −1 8 8 : Cannot allocate memory The FreeBSD kernel provides an undocumented % /sbin/sysctl x1.x2.x3.x4.x5.x6.x7.x8. interface, introduced over twenty years ago [8], to x9.x10.x11.x12.x13.x14.x15.x16.x17.x18. retrieve the info of an object: name, type, for- x19.x20.x21.x22.x23.x24 mat, description, next leaf and OID by name, sysctl: sysctl fmt −1 1024 22: Invalid later: description [9] and label [10]. The interface argument 2 The current interface provides sysctl.next to ex- value of an object like "kern.proc.pid.1". plore the MIB, it finds the specified object and gets Furthermore sysctl.name2oid finishes to build the next leaf. However a MIB explorer [Figure 1] the OID if a level-name is just the "NULL string", needs to retrieve also the next internal node. The so sysctlbyname() could get or set the value of an early versions of sysctlview [18], a graphical sysctl unwanted object. Consider [Listing 8], the sysctl(8) MIB explorer, wasted computation in userspace utility uses sysctl.name2oid to retrieve the OID of comparing the OIDs of two consecutive leaves to "security.jail.param.allow.mount.", so it receives an retrieve the internal nodes. incomplete OID, in fact it shows the requested node and its brothers. Figure 1: sysctlview Listing 8: sysctl(8) shows unwanted objects % sysctl security. jail .param.allow.mount. security. jail .param.allow.mount.tmpfs: 0 security. jail .param.allow.mount.debugfs: 0 security . jail .param.allow.mount.anon i n o d e f s : 0 security. jail .param.allow.mount.procfs: 0 security. jail .param.allow.mount.devfs: 0 security. jail .param.allow.mount.: 0 Finally, the current interface does not take care of security: in capability mode [13] it exposes the info of a nodes without the CTLFLAG CAPRD or CTLFLAG CAPWR flag. 3 A new interface This paper presents a new interface: sysctlinfo [16], its purpose is to address the limitations of the cur- rent interface, to improve the efficiency and to im- plement new features; moreover the project pro- The sysctl.name node finds an object by vides: a README, a manual, helper macros, ex- its OID and gets its name, example: [1.1] ! amples, and converted tools. Obviously the inter- "kern.ostype". However if no object has the faces can coexist, the utilities and libraries can con- specified OID the internal node builds a "fake" tinue to use the current kernel interface while the name depending on the input OID and returns converted tools can take the advantages by using always '0' false positive [Listing 5], example: sysctlinfo. [1.1.100.500.1000] ! "kern.ostype.100.500.1000" or a totally non-existent OID [3000.4000.5000] ! Features "3000.4000.5000".