The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linux/linux_mib.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1999 Marcel Moolenaar
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer 
   10  *    in this position and unchanged.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/10.2/sys/compat/linux/linux_mib.c 275807 2014-12-15 16:14:49Z sbruno $");
   31 
   32 #include "opt_compat.h"
   33 #include "opt_kdtrace.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/kernel.h>
   37 #include <sys/sdt.h>
   38 #include <sys/systm.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/proc.h>
   41 #include <sys/malloc.h>
   42 #include <sys/mount.h>
   43 #include <sys/jail.h>
   44 #include <sys/lock.h>
   45 #include <sys/mutex.h>
   46 #include <sys/sx.h>
   47 
   48 #ifdef COMPAT_LINUX32
   49 #include <machine/../linux32/linux.h>
   50 #else
   51 #include <machine/../linux/linux.h>
   52 #endif
   53 #include <compat/linux/linux_dtrace.h>
   54 #include <compat/linux/linux_mib.h>
   55 #include <compat/linux/linux_misc.h>
   56 
   57 /* DTrace init */
   58 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
   59 
   60 /**
   61  * DTrace probes in this module.
   62  */
   63 LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osname, entry);
   64 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, sysctl_string_error, "int");
   65 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, return, "int");
   66 
   67 LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osrelease, entry);
   68 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, sysctl_string_error, "int");
   69 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, return, "int");
   70 LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_oss_version, entry);
   71 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, sysctl_string_error,
   72     "int");
   73 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, return, "int");
   74 LIN_SDT_PROBE_DEFINE2(mib, linux_map_osrel, entry, "char *", "int *");
   75 LIN_SDT_PROBE_DEFINE1(mib, linux_map_osrel, return, "int");
   76 LIN_SDT_PROBE_DEFINE2(mib, linux_get_prison, entry, "struct prison *",
   77     "struct prison **");
   78 LIN_SDT_PROBE_DEFINE1(mib, linux_get_prison, return, "struct linux_prison *");
   79 LIN_SDT_PROBE_DEFINE2(mib, linux_alloc_prison, entry, "struct prison *",
   80     "struct linux_prison **");
   81 LIN_SDT_PROBE_DEFINE1(mib, linux_alloc_prison, return, "int");
   82 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_create, entry, "void *", "void *");
   83 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, vfs_copyopt_error, "int");
   84 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, return, "int");
   85 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_check, entry, "void *", "void *");
   86 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_copyopt_error, "int");
   87 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_getopt_error, "int");
   88 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, return, "int");
   89 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_set, entry, "void *", "void *");
   90 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_copyopt_error, "int");
   91 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_getopt_error, "int");
   92 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, return, "int");
   93 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_get, entry, "void *", "void *");
   94 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopt_error, "int");
   95 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopts_error, "int");
   96 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, return, "int");
   97 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_destructor, entry, "void *");
   98 LIN_SDT_PROBE_DEFINE0(mib, linux_prison_destructor, return);
   99 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, entry);
  100 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, return);
  101 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, entry);
  102 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, return);
  103 LIN_SDT_PROBE_DEFINE2(mib, linux_get_osname, entry, "struct thread *",
  104     "char *");
  105 LIN_SDT_PROBE_DEFINE0(mib, linux_get_osname, return);
  106 LIN_SDT_PROBE_DEFINE2(mib, linux_set_osname, entry, "struct thread *",
  107     "char *");
  108 LIN_SDT_PROBE_DEFINE1(mib, linux_set_osname, return, "int");
  109 LIN_SDT_PROBE_DEFINE2(mib, linux_get_osrelease, entry, "struct thread *",
  110     "char *");
  111 LIN_SDT_PROBE_DEFINE0(mib, linux_get_osrelease, return);
  112 LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, entry, "struct thread *");
  113 LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, return, "int");
  114 LIN_SDT_PROBE_DEFINE2(mib, linux_set_osrelease, entry, "struct thread *",
  115     "char *");
  116 LIN_SDT_PROBE_DEFINE1(mib, linux_set_osrelease, return, "int");
  117 LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, entry, "struct thread *");
  118 LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, return, "int");
  119 
  120 LIN_SDT_PROBE_DEFINE2(mib, linux_set_oss_version, entry, "struct thread *",
  121     "int");
  122 LIN_SDT_PROBE_DEFINE1(mib, linux_set_oss_version, return, "int");
  123 
  124 struct linux_prison {
  125         char    pr_osname[LINUX_MAX_UTSNAME];
  126         char    pr_osrelease[LINUX_MAX_UTSNAME];
  127         int     pr_oss_version;
  128         int     pr_osrel;
  129 };
  130 
  131 static struct linux_prison lprison0 = {
  132         .pr_osname =            "Linux",
  133         .pr_osrelease =         "2.6.18",
  134         .pr_oss_version =       0x030600,
  135         .pr_osrel =             2006018
  136 };
  137 
  138 static unsigned linux_osd_jail_slot;
  139 
  140 static SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0,
  141             "Linux mode");
  142 
  143 static int      linux_set_osname(struct thread *td, char *osname);
  144 static int      linux_set_osrelease(struct thread *td, char *osrelease);
  145 static int      linux_set_oss_version(struct thread *td, int oss_version);
  146 
  147 static int
  148 linux_sysctl_osname(SYSCTL_HANDLER_ARGS)
  149 {
  150         char osname[LINUX_MAX_UTSNAME];
  151         int error;
  152 
  153         LIN_SDT_PROBE0(mib, linux_sysctl_osname, entry);
  154 
  155         linux_get_osname(req->td, osname);
  156         error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req);
  157         if (error != 0 || req->newptr == NULL) {
  158                 LIN_SDT_PROBE1(mib, linux_sysctl_osname, sysctl_string_error,
  159                     error);
  160                 LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error);
  161                 return (error);
  162         }
  163         error = linux_set_osname(req->td, osname);
  164 
  165         LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error);
  166         return (error);
  167 }
  168 
  169 SYSCTL_PROC(_compat_linux, OID_AUTO, osname,
  170             CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
  171             0, 0, linux_sysctl_osname, "A",
  172             "Linux kernel OS name");
  173 
  174 static int
  175 linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS)
  176 {
  177         char osrelease[LINUX_MAX_UTSNAME];
  178         int error;
  179 
  180         LIN_SDT_PROBE0(mib, linux_sysctl_osrelease, entry);
  181 
  182         linux_get_osrelease(req->td, osrelease);
  183         error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req);
  184         if (error != 0 || req->newptr == NULL) {
  185                 LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, sysctl_string_error,
  186                     error);
  187                 LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error);
  188                 return (error);
  189         }
  190         error = linux_set_osrelease(req->td, osrelease);
  191 
  192         LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error);
  193         return (error);
  194 }
  195 
  196 SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease,
  197             CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
  198             0, 0, linux_sysctl_osrelease, "A",
  199             "Linux kernel OS release");
  200 
  201 static int
  202 linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS)
  203 {
  204         int oss_version;
  205         int error;
  206 
  207         LIN_SDT_PROBE0(mib, linux_sysctl_oss_version, entry);
  208 
  209         oss_version = linux_get_oss_version(req->td);
  210         error = sysctl_handle_int(oidp, &oss_version, 0, req);
  211         if (error != 0 || req->newptr == NULL) {
  212                 LIN_SDT_PROBE1(mib, linux_sysctl_oss_version,
  213                     sysctl_string_error, error);
  214                 LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error);
  215                 return (error);
  216         }
  217         error = linux_set_oss_version(req->td, oss_version);
  218 
  219         LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error);
  220         return (error);
  221 }
  222 
  223 SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version,
  224             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
  225             0, 0, linux_sysctl_oss_version, "I",
  226             "Linux OSS version");
  227 
  228 /*
  229  * Map the osrelease into integer
  230  */
  231 static int
  232 linux_map_osrel(char *osrelease, int *osrel)
  233 {
  234         char *sep, *eosrelease;
  235         int len, v0, v1, v2, v;
  236 
  237         LIN_SDT_PROBE2(mib, linux_map_osrel, entry, osrelease, osrel);
  238 
  239         len = strlen(osrelease);
  240         eosrelease = osrelease + len;
  241         v0 = strtol(osrelease, &sep, 10);
  242         if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') {
  243                 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
  244                 return (EINVAL);
  245         }
  246         osrelease = sep + 1;
  247         v1 = strtol(osrelease, &sep, 10);
  248         if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') {
  249                 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
  250                 return (EINVAL);
  251         }
  252         osrelease = sep + 1;
  253         v2 = strtol(osrelease, &sep, 10);
  254         if (osrelease == sep || sep != eosrelease) {
  255                 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
  256                 return (EINVAL);
  257         }
  258 
  259         v = v0 * 1000000 + v1 * 1000 + v2;
  260         if (v < 1000000) {
  261                 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
  262                 return (EINVAL);
  263         }
  264 
  265         *osrel = v;
  266 
  267         LIN_SDT_PROBE1(mib, linux_map_osrel, return, 0);
  268         return (0);
  269 }
  270 
  271 /*
  272  * Find a prison with Linux info.
  273  * Return the Linux info and the (locked) prison.
  274  */
  275 static struct linux_prison *
  276 linux_find_prison(struct prison *spr, struct prison **prp)
  277 {
  278         struct prison *pr;
  279         struct linux_prison *lpr;
  280 
  281         LIN_SDT_PROBE2(mib, linux_get_prison, entry, spr, prp);
  282 
  283         if (!linux_osd_jail_slot)
  284                 /* In case osd_register failed. */
  285                 spr = &prison0;
  286         for (pr = spr;; pr = pr->pr_parent) {
  287                 mtx_lock(&pr->pr_mtx);
  288                 lpr = (pr == &prison0)
  289                     ? &lprison0
  290                     : osd_jail_get(pr, linux_osd_jail_slot);
  291                 if (lpr != NULL)
  292                         break;
  293                 mtx_unlock(&pr->pr_mtx);
  294         }
  295         *prp = pr;
  296 
  297         LIN_SDT_PROBE1(mib, linux_get_prison, return, lpr);
  298         return (lpr);
  299 }
  300 
  301 /*
  302  * Ensure a prison has its own Linux info.  If lprp is non-null, point it to
  303  * the Linux info and lock the prison.
  304  */
  305 static int
  306 linux_alloc_prison(struct prison *pr, struct linux_prison **lprp)
  307 {
  308         struct prison *ppr;
  309         struct linux_prison *lpr, *nlpr;
  310         int error;
  311 
  312         LIN_SDT_PROBE2(mib, linux_alloc_prison, entry, pr, lprp);
  313 
  314         /* If this prison already has Linux info, return that. */
  315         error = 0;
  316         lpr = linux_find_prison(pr, &ppr);
  317         if (ppr == pr)
  318                 goto done;
  319         /*
  320          * Allocate a new info record.  Then check again, in case something
  321          * changed during the allocation.
  322          */
  323         mtx_unlock(&ppr->pr_mtx);
  324         nlpr = malloc(sizeof(struct linux_prison), M_PRISON, M_WAITOK);
  325         lpr = linux_find_prison(pr, &ppr);
  326         if (ppr == pr) {
  327                 free(nlpr, M_PRISON);
  328                 goto done;
  329         }
  330         /* Inherit the initial values from the ancestor. */
  331         mtx_lock(&pr->pr_mtx);
  332         error = osd_jail_set(pr, linux_osd_jail_slot, nlpr);
  333         if (error == 0) {
  334                 bcopy(lpr, nlpr, sizeof(*lpr));
  335                 lpr = nlpr;
  336         } else {
  337                 free(nlpr, M_PRISON);
  338                 lpr = NULL;
  339         }
  340         mtx_unlock(&ppr->pr_mtx);
  341  done:
  342         if (lprp != NULL)
  343                 *lprp = lpr;
  344         else
  345                 mtx_unlock(&pr->pr_mtx);
  346 
  347         LIN_SDT_PROBE1(mib, linux_alloc_prison, return, error);
  348         return (error);
  349 }
  350 
  351 /*
  352  * Jail OSD methods for Linux prison data.
  353  */
  354 static int
  355 linux_prison_create(void *obj, void *data)
  356 {
  357         struct prison *pr = obj;
  358         struct vfsoptlist *opts = data;
  359         int jsys, error;
  360 
  361         LIN_SDT_PROBE2(mib, linux_prison_create, entry, obj, data);
  362 
  363         error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
  364         if (error != 0) {
  365                 LIN_SDT_PROBE1(mib, linux_prison_create, vfs_copyopt_error,
  366                     error);
  367         } else if (jsys == JAIL_SYS_INHERIT) {
  368                 LIN_SDT_PROBE1(mib, linux_prison_create, return, 0);
  369                 return (0);
  370         }
  371         /*
  372          * Inherit a prison's initial values from its parent
  373          * (different from JAIL_SYS_INHERIT which also inherits changes).
  374          */
  375         error = linux_alloc_prison(pr, NULL);
  376 
  377         LIN_SDT_PROBE1(mib, linux_prison_create, return, error);
  378         return (error);
  379 }
  380 
  381 static int
  382 linux_prison_check(void *obj __unused, void *data)
  383 {
  384         struct vfsoptlist *opts = data;
  385         char *osname, *osrelease;
  386         int error, jsys, len, osrel, oss_version;
  387 
  388         LIN_SDT_PROBE2(mib, linux_prison_check, entry, obj, data);
  389 
  390         /* Check that the parameters are correct. */
  391         error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
  392         if (error != 0) {
  393                 LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error,
  394                     error);
  395         }
  396         if (error != ENOENT) {
  397                 if (error != 0) {
  398                         LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
  399                         return (error);
  400                 }
  401                 if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) {
  402                         LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
  403                         return (EINVAL);
  404                 }
  405         }
  406         error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len);
  407         if (error != 0) {
  408                 LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error,
  409                     error);
  410         }
  411         if (error != ENOENT) {
  412                 if (error != 0) {
  413                         LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
  414                         return (error);
  415                 }
  416                 if (len == 0 || osname[len - 1] != '\0') {
  417                         LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
  418                         return (EINVAL);
  419                 }
  420                 if (len > LINUX_MAX_UTSNAME) {
  421                         vfs_opterror(opts, "linux.osname too long");
  422                         LIN_SDT_PROBE1(mib, linux_prison_check, return,
  423                             ENAMETOOLONG);
  424                         return (ENAMETOOLONG);
  425                 }
  426         }
  427         error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len);
  428         if (error != 0) {
  429                 LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error,
  430                     error);
  431         }
  432         if (error != ENOENT) {
  433                 if (error != 0) {
  434                         LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
  435                         return (error);
  436                 }
  437                 if (len == 0 || osrelease[len - 1] != '\0') {
  438                         LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
  439                         return (EINVAL);
  440                 }
  441                 if (len > LINUX_MAX_UTSNAME) {
  442                         vfs_opterror(opts, "linux.osrelease too long");
  443                         LIN_SDT_PROBE1(mib, linux_prison_check, return,
  444                             ENAMETOOLONG);
  445                         return (ENAMETOOLONG);
  446                 }
  447                 error = linux_map_osrel(osrelease, &osrel);
  448                 if (error != 0) {
  449                         vfs_opterror(opts, "linux.osrelease format error");
  450                         LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
  451                         return (error);
  452                 }
  453         }
  454         error = vfs_copyopt(opts, "linux.oss_version", &oss_version,
  455             sizeof(oss_version));
  456         if (error != 0)
  457             LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error, error);
  458 
  459         if (error == ENOENT)
  460                 error = 0;
  461         LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
  462         return (error);
  463 }
  464 
  465 static int
  466 linux_prison_set(void *obj, void *data)
  467 {
  468         struct linux_prison *lpr;
  469         struct prison *pr = obj;
  470         struct vfsoptlist *opts = data;
  471         char *osname, *osrelease;
  472         int error, gotversion, jsys, len, oss_version;
  473 
  474         LIN_SDT_PROBE2(mib, linux_prison_set, entry, obj, data);
  475 
  476         /* Set the parameters, which should be correct. */
  477         error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
  478         if (error != 0)
  479                 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error);
  480         if (error == ENOENT)
  481                 jsys = -1;
  482         error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len);
  483         if (error != 0)
  484                 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error);
  485         if (error == ENOENT)
  486                 osname = NULL;
  487         else
  488                 jsys = JAIL_SYS_NEW;
  489         error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len);
  490         if (error != 0)
  491                 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error);
  492         if (error == ENOENT)
  493                 osrelease = NULL;
  494         else
  495                 jsys = JAIL_SYS_NEW;
  496         error = vfs_copyopt(opts, "linux.oss_version", &oss_version,
  497             sizeof(oss_version));
  498         if (error != 0)
  499                 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error);
  500         if (error == ENOENT)
  501                 gotversion = 0;
  502         else {
  503                 gotversion = 1;
  504                 jsys = JAIL_SYS_NEW;
  505         }
  506         switch (jsys) {
  507         case JAIL_SYS_INHERIT:
  508                 /* "linux=inherit": inherit the parent's Linux info. */
  509                 mtx_lock(&pr->pr_mtx);
  510                 osd_jail_del(pr, linux_osd_jail_slot);
  511                 mtx_unlock(&pr->pr_mtx);
  512                 break;
  513         case JAIL_SYS_NEW:
  514                 /*
  515                  * "linux=new" or "linux.*":
  516                  * the prison gets its own Linux info.
  517                  */
  518                 error = linux_alloc_prison(pr, &lpr);
  519                 if (error) {
  520                         mtx_unlock(&pr->pr_mtx);
  521                         LIN_SDT_PROBE1(mib, linux_prison_set, return, error);
  522                         return (error);
  523                 }
  524                 if (osrelease) {
  525                         error = linux_map_osrel(osrelease, &lpr->pr_osrel);
  526                         if (error) {
  527                                 mtx_unlock(&pr->pr_mtx);
  528                                 LIN_SDT_PROBE1(mib, linux_prison_set, return,
  529                                     error);
  530                                 return (error);
  531                         }
  532                         strlcpy(lpr->pr_osrelease, osrelease,
  533                             LINUX_MAX_UTSNAME);
  534                 }
  535                 if (osname)
  536                         strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME);
  537                 if (gotversion)
  538                         lpr->pr_oss_version = oss_version;
  539                 mtx_unlock(&pr->pr_mtx);
  540         }
  541 
  542         LIN_SDT_PROBE1(mib, linux_prison_set, return, 0);
  543         return (0);
  544 }
  545 
  546 SYSCTL_JAIL_PARAM_SYS_NODE(linux, CTLFLAG_RW, "Jail Linux parameters");
  547 SYSCTL_JAIL_PARAM_STRING(_linux, osname, CTLFLAG_RW, LINUX_MAX_UTSNAME,
  548     "Jail Linux kernel OS name");
  549 SYSCTL_JAIL_PARAM_STRING(_linux, osrelease, CTLFLAG_RW, LINUX_MAX_UTSNAME,
  550     "Jail Linux kernel OS release");
  551 SYSCTL_JAIL_PARAM(_linux, oss_version, CTLTYPE_INT | CTLFLAG_RW,
  552     "I", "Jail Linux OSS version");
  553 
  554 static int
  555 linux_prison_get(void *obj, void *data)
  556 {
  557         struct linux_prison *lpr;
  558         struct prison *ppr;
  559         struct prison *pr = obj;
  560         struct vfsoptlist *opts = data;
  561         int error, i;
  562 
  563         static int version0;
  564 
  565         LIN_SDT_PROBE2(mib, linux_prison_get, entry, obj, data);
  566 
  567         /* See if this prison is the one with the Linux info. */
  568         lpr = linux_find_prison(pr, &ppr);
  569         i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
  570         error = vfs_setopt(opts, "linux", &i, sizeof(i));
  571         if (error != 0) {
  572                 LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, error);
  573                 if (error != ENOENT)
  574                         goto done;
  575         }
  576         if (i) {
  577                 error = vfs_setopts(opts, "linux.osname", lpr->pr_osname);
  578                 if (error != 0) {
  579                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
  580                             error);
  581                         if (error != ENOENT)
  582                                 goto done;
  583                 }
  584                 error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease);
  585                 if (error != 0) {
  586                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
  587                             error);
  588                         if (error != ENOENT)
  589                                 goto done;
  590                 }
  591                 error = vfs_setopt(opts, "linux.oss_version",
  592                     &lpr->pr_oss_version, sizeof(lpr->pr_oss_version));
  593                 if (error != 0) {
  594                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error,
  595                             error);
  596                         if(error != ENOENT)
  597                                 goto done;
  598                 }
  599         } else {
  600                 /*
  601                  * If this prison is inheriting its Linux info, report
  602                  * empty/zero parameters.
  603                  */
  604                 error = vfs_setopts(opts, "linux.osname", "");
  605                 if (error != 0) {
  606                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
  607                             error);
  608                         if(error != ENOENT)
  609                                 goto done;
  610                 }
  611                 error = vfs_setopts(opts, "linux.osrelease", "");
  612                 if (error != 0) {
  613                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
  614                             error);
  615                         if(error != ENOENT)
  616                                 goto done;
  617                 }
  618                 error = vfs_setopt(opts, "linux.oss_version", &version0,
  619                     sizeof(lpr->pr_oss_version));
  620                 if (error != 0) {
  621                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error,
  622                             error);
  623                         if(error != ENOENT)
  624                                 goto done;
  625                 }
  626         }
  627         error = 0;
  628 
  629  done:
  630         mtx_unlock(&ppr->pr_mtx);
  631 
  632         LIN_SDT_PROBE1(mib, linux_prison_get, return, error);
  633         return (error);
  634 }
  635 
  636 static void
  637 linux_prison_destructor(void *data)
  638 {
  639 
  640         LIN_SDT_PROBE1(mib, linux_prison_destructor, entry, data);
  641         free(data, M_PRISON);
  642         LIN_SDT_PROBE0(mib, linux_prison_destructor, return);
  643 }
  644 
  645 void
  646 linux_osd_jail_register(void)
  647 {
  648         struct prison *pr;
  649         osd_method_t methods[PR_MAXMETHOD] = {
  650             [PR_METHOD_CREATE] =        linux_prison_create,
  651             [PR_METHOD_GET] =           linux_prison_get,
  652             [PR_METHOD_SET] =           linux_prison_set,
  653             [PR_METHOD_CHECK] =         linux_prison_check
  654         };
  655 
  656         LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry);
  657 
  658         linux_osd_jail_slot =
  659             osd_jail_register(linux_prison_destructor, methods);
  660         if (linux_osd_jail_slot > 0) {
  661                 /* Copy the system linux info to any current prisons. */
  662                 sx_xlock(&allprison_lock);
  663                 TAILQ_FOREACH(pr, &allprison, pr_list)
  664                         (void)linux_alloc_prison(pr, NULL);
  665                 sx_xunlock(&allprison_lock);
  666         }
  667 
  668         LIN_SDT_PROBE0(mib, linux_osd_jail_register, return);
  669 }
  670 
  671 void
  672 linux_osd_jail_deregister(void)
  673 {
  674 
  675         LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry);
  676 
  677         if (linux_osd_jail_slot)
  678                 osd_jail_deregister(linux_osd_jail_slot);
  679 
  680         LIN_SDT_PROBE0(mib, linux_osd_jail_register, return);
  681 }
  682 
  683 void
  684 linux_get_osname(struct thread *td, char *dst)
  685 {
  686         struct prison *pr;
  687         struct linux_prison *lpr;
  688 
  689         LIN_SDT_PROBE2(mib, linux_get_osname, entry, td, dst);
  690 
  691         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  692         bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME);
  693         mtx_unlock(&pr->pr_mtx);
  694 
  695         LIN_SDT_PROBE0(mib, linux_get_osname, return);
  696 }
  697 
  698 static int
  699 linux_set_osname(struct thread *td, char *osname)
  700 {
  701         struct prison *pr;
  702         struct linux_prison *lpr;
  703 
  704         LIN_SDT_PROBE2(mib, linux_set_osname, entry, td, osname);
  705 
  706         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  707         strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME);
  708         mtx_unlock(&pr->pr_mtx);
  709 
  710         LIN_SDT_PROBE1(mib, linux_set_osname, return, 0);
  711         return (0);
  712 }
  713 
  714 void
  715 linux_get_osrelease(struct thread *td, char *dst)
  716 {
  717         struct prison *pr;
  718         struct linux_prison *lpr;
  719 
  720         LIN_SDT_PROBE2(mib, linux_get_osrelease, entry, td, dst);
  721 
  722         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  723         bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME);
  724         mtx_unlock(&pr->pr_mtx);
  725 
  726         LIN_SDT_PROBE0(mib, linux_get_osrelease, return);
  727 }
  728 
  729 int
  730 linux_kernver(struct thread *td)
  731 {
  732         struct prison *pr;
  733         struct linux_prison *lpr;
  734         int osrel;
  735 
  736         LIN_SDT_PROBE1(mib, linux_kernver, entry, td);
  737 
  738         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  739         osrel = lpr->pr_osrel;
  740         mtx_unlock(&pr->pr_mtx);
  741 
  742         LIN_SDT_PROBE1(mib, linux_kernver, return, osrel);
  743         return (osrel);
  744 }
  745 
  746 static int
  747 linux_set_osrelease(struct thread *td, char *osrelease)
  748 {
  749         struct prison *pr;
  750         struct linux_prison *lpr;
  751         int error;
  752 
  753         LIN_SDT_PROBE2(mib, linux_set_osrelease, entry, td, osrelease);
  754 
  755         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  756         error = linux_map_osrel(osrelease, &lpr->pr_osrel);
  757         if (error == 0)
  758                 strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME);
  759         mtx_unlock(&pr->pr_mtx);
  760 
  761         LIN_SDT_PROBE1(mib, linux_set_osrelease, return, error);
  762         return (error);
  763 }
  764 
  765 int
  766 linux_get_oss_version(struct thread *td)
  767 {
  768         struct prison *pr;
  769         struct linux_prison *lpr;
  770         int version;
  771 
  772         LIN_SDT_PROBE1(mib, linux_get_oss_version, entry, td);
  773 
  774         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  775         version = lpr->pr_oss_version;
  776         mtx_unlock(&pr->pr_mtx);
  777 
  778         LIN_SDT_PROBE1(mib, linux_get_oss_version, return, version);
  779         return (version);
  780 }
  781 
  782 static int
  783 linux_set_oss_version(struct thread *td, int oss_version)
  784 {
  785         struct prison *pr;
  786         struct linux_prison *lpr;
  787 
  788         LIN_SDT_PROBE2(mib, linux_set_oss_version, entry, td, oss_version);
  789 
  790         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  791         lpr->pr_oss_version = oss_version;
  792         mtx_unlock(&pr->pr_mtx);
  793 
  794         LIN_SDT_PROBE1(mib, linux_set_oss_version, return, 0);
  795         return (0);
  796 }
  797 
  798 #if defined(DEBUG) || defined(KTR)
  799 /* XXX: can be removed when every ldebug(...) and KTR stuff are removed. */
  800 
  801 u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))];
  802 
  803 static int
  804 linux_debug(int syscall, int toggle, int global)
  805 {
  806 
  807         if (global) {
  808                 char c = toggle ? 0 : 0xff;
  809 
  810                 memset(linux_debug_map, c, sizeof(linux_debug_map));
  811                 return (0);
  812         }
  813         if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL)
  814                 return (EINVAL);
  815         if (toggle)
  816                 clrbit(linux_debug_map, syscall);
  817         else
  818                 setbit(linux_debug_map, syscall);
  819         return (0);
  820 }
  821 
  822 /*
  823  * Usage: sysctl linux.debug=<syscall_nr>.<0/1>
  824  *
  825  *    E.g.: sysctl linux.debug=21.0
  826  *
  827  * As a special case, syscall "all" will apply to all syscalls globally.
  828  */
  829 #define LINUX_MAX_DEBUGSTR      16
  830 static int
  831 linux_sysctl_debug(SYSCTL_HANDLER_ARGS)
  832 {
  833         char value[LINUX_MAX_DEBUGSTR], *p;
  834         int error, sysc, toggle;
  835         int global = 0;
  836 
  837         value[0] = '\0';
  838         error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req);
  839         if (error || req->newptr == NULL)
  840                 return (error);
  841         for (p = value; *p != '\0' && *p != '.'; p++);
  842         if (*p == '\0')
  843                 return (EINVAL);
  844         *p++ = '\0';
  845         sysc = strtol(value, NULL, 0);
  846         toggle = strtol(p, NULL, 0);
  847         if (strcmp(value, "all") == 0)
  848                 global = 1;
  849         error = linux_debug(sysc, toggle, global);
  850         return (error);
  851 }
  852 
  853 SYSCTL_PROC(_compat_linux, OID_AUTO, debug,
  854             CTLTYPE_STRING | CTLFLAG_RW,
  855             0, 0, linux_sysctl_debug, "A",
  856             "Linux debugging control");
  857 
  858 #endif /* DEBUG || KTR */

Cache object: b23187583b3533d7d3110ab7cf578471


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.