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/kern/sys_module.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: sys_module.c,v 1.30 2022/05/24 06:20:05 andvar Exp $   */
    2 
    3 /*-
    4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   26  * POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * System calls relating to loadable modules.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: sys_module.c,v 1.30 2022/05/24 06:20:05 andvar Exp $");
   35 
   36 #ifdef _KERNEL_OPT
   37 #include "opt_modular.h"
   38 #endif
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/proc.h>
   43 #include <sys/namei.h>
   44 #include <sys/kauth.h>
   45 #include <sys/kmem.h>
   46 #include <sys/kobj.h>
   47 #include <sys/module.h>
   48 #include <sys/syscall.h>
   49 #include <sys/syscallargs.h>
   50 #include <sys/compat_stub.h>
   51 
   52 /*
   53  * Arbitrary limit to avoid DoS for excessive memory allocation.
   54  */
   55 #define MAXPROPSLEN     4096
   56 
   57 int
   58 handle_modctl_load(const char *ml_filename, int ml_flags, const char *ml_props,
   59     size_t ml_propslen)
   60 {
   61         char *path;
   62         char *props;
   63         int error;
   64         prop_dictionary_t dict;
   65         size_t propslen = 0;
   66 
   67         if ((ml_props != NULL && ml_propslen == 0) ||
   68             (ml_props == NULL && ml_propslen > 0)) {
   69                 return EINVAL;
   70         }
   71 
   72         path = PNBUF_GET();
   73         error = copyinstr(ml_filename, path, MAXPATHLEN, NULL);
   74         if (error != 0)
   75                 goto out1;
   76 
   77         if (ml_props != NULL) {
   78                 if (ml_propslen > MAXPROPSLEN) {
   79                         error = ENOMEM;
   80                         goto out1;
   81                 }
   82                 propslen = ml_propslen + 1;
   83 
   84                 props = kmem_alloc(propslen, KM_SLEEP);
   85                 error = copyinstr(ml_props, props, propslen, NULL);
   86                 if (error != 0)
   87                         goto out2;
   88 
   89                 dict = prop_dictionary_internalize(props);
   90                 if (dict == NULL) {
   91                         error = EINVAL;
   92                         goto out2;
   93                 }
   94         } else {
   95                 dict = NULL;
   96                 props = NULL;
   97         }
   98 
   99         error = module_load(path, ml_flags, dict, MODULE_CLASS_ANY);
  100 
  101         if (dict != NULL) {
  102                 prop_object_release(dict);
  103         }
  104 
  105 out2:
  106         if (props != NULL) {
  107                 kmem_free(props, propslen);
  108         }
  109 out1:
  110         PNBUF_PUT(path);
  111         return error;
  112 }
  113 
  114 static int
  115 handle_modctl_stat(struct iovec *iov, void *arg)
  116 {
  117         int ms_cnt;
  118         modstat_t *ms, *mso;
  119         size_t ms_len;
  120         char *req, *reqo;
  121         size_t req_len;
  122         char *out_p;
  123         size_t out_s;
  124 
  125         modinfo_t *mi;
  126         module_t *mod;
  127         vaddr_t addr;
  128         size_t size;
  129         size_t used;
  130         int off;
  131         int error;
  132         bool stataddr;
  133 
  134         /* If not privileged, don't expose kernel addresses. */
  135         error = kauth_authorize_process(kauth_cred_get(), KAUTH_PROCESS_CANSEE,
  136             curproc, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_KPTR), NULL, NULL);
  137         stataddr = (error == 0);
  138 
  139         kernconfig_lock();
  140         ms_cnt = 0;
  141         req_len = 1;
  142 
  143         /*
  144          * Count up the number of modstat_t needed, and total size of
  145          * require_module lists on both active and built-in lists
  146          */
  147         TAILQ_FOREACH(mod, &module_list, mod_chain) {
  148                 ms_cnt++;
  149                 mi = mod->mod_info;
  150                 if (mi->mi_required != NULL) {
  151                         req_len += strlen(mi->mi_required) + 1;
  152                 }
  153         }
  154         TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
  155                 ms_cnt++;
  156                 mi = mod->mod_info;
  157                 if (mi->mi_required != NULL) {
  158                         req_len += strlen(mi->mi_required) + 1;
  159                 }
  160         }
  161 
  162         /* Allocate internal buffers to hold all the output data */
  163         ms_len = ms_cnt * sizeof(modstat_t);
  164         ms = kmem_zalloc(ms_len, KM_SLEEP);
  165         req = kmem_zalloc(req_len, KM_SLEEP);
  166 
  167         mso = ms;
  168         reqo = req++;
  169         off = 1;
  170 
  171         /*
  172          * Load data into our internal buffers for both active and
  173          * built-in module lists
  174          */
  175         TAILQ_FOREACH(mod, &module_list, mod_chain) {
  176                 mi = mod->mod_info;
  177                 strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name));
  178                 if (mi->mi_required != NULL) {
  179                         ms->ms_reqoffset = off;
  180                         used = strlcpy(req,  mi->mi_required, req_len - off);
  181                         KASSERTMSG(used < req_len - off, "reqlist grew!");
  182                         off += used + 1;
  183                         req += used + 1;
  184                 } else
  185                         ms->ms_reqoffset = 0;
  186                 if (mod->mod_kobj != NULL && stataddr) {
  187                         kobj_stat(mod->mod_kobj, &addr, &size);
  188                         ms->ms_addr = addr;
  189                         ms->ms_size = size;
  190                 }
  191                 ms->ms_class = mi->mi_class;
  192                 ms->ms_refcnt = mod->mod_refcnt;
  193                 ms->ms_source = mod->mod_source;
  194                 ms->ms_flags = mod->mod_flags;
  195                 ms++;
  196         }
  197         TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
  198                 mi = mod->mod_info;
  199                 strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name));
  200                 if (mi->mi_required != NULL) {
  201                         ms->ms_reqoffset = off;
  202                         used = strlcpy(req,  mi->mi_required, req_len - off);
  203                         KASSERTMSG(used < req_len - off, "reqlist grew!");
  204                         off += used + 1;
  205                         req += used + 1;
  206                 } else
  207                         ms->ms_reqoffset = 0;
  208                 if (mod->mod_kobj != NULL && stataddr) {
  209                         kobj_stat(mod->mod_kobj, &addr, &size);
  210                         ms->ms_addr = addr;
  211                         ms->ms_size = size;
  212                 }
  213                 ms->ms_class = mi->mi_class;
  214                 ms->ms_refcnt = -1;
  215                 KASSERT(mod->mod_source == MODULE_SOURCE_KERNEL);
  216                 ms->ms_source = mod->mod_source;
  217                 ms++;
  218         }
  219         kernconfig_unlock();
  220 
  221         /*
  222          * Now copyout our internal buffers back to userland
  223          */
  224         out_p = iov->iov_base;
  225         out_s = iov->iov_len;
  226         size = sizeof(ms_cnt);
  227 
  228         /* Copy out the count of modstat_t */
  229         if (out_s) {
  230                 size = uimin(sizeof(ms_cnt), out_s);
  231                 error = copyout(&ms_cnt, out_p, size);
  232                 out_p += size;
  233                 out_s -= size;
  234         }
  235         /* Copy out the modstat_t array */
  236         if (out_s && error == 0) {
  237                 size = uimin(ms_len, out_s);
  238                 error = copyout(mso, out_p, size);
  239                 out_p += size;
  240                 out_s -= size;
  241         }
  242         /* Copy out the "required" strings */
  243         if (out_s && error == 0) {
  244                 size = uimin(req_len, out_s);
  245                 error = copyout(reqo, out_p, size);
  246                 out_p += size;
  247                 out_s -= size;
  248         }
  249         kmem_free(mso, ms_len);
  250         kmem_free(reqo, req_len);
  251 
  252         /* Finally, update the userland copy of the iovec's length */
  253         if (error == 0) {
  254                 iov->iov_len = ms_len + req_len + sizeof(ms_cnt);
  255                 error = copyout(iov, arg, sizeof(*iov));
  256         }
  257 
  258         return error;
  259 }
  260 
  261 int
  262 sys_modctl(struct lwp *l, const struct sys_modctl_args *uap,
  263            register_t *retval)
  264 {
  265         /* {
  266                 syscallarg(int)         cmd;
  267                 syscallarg(void *)      arg;
  268         } */
  269         char buf[MAXMODNAME];
  270         struct iovec iov;
  271         modctl_load_t ml;
  272         int error;
  273         void *arg;
  274 #ifdef MODULAR
  275         uintptr_t loadtype;
  276 #endif
  277 
  278         arg = SCARG(uap, arg);
  279 
  280         switch (SCARG(uap, cmd)) {
  281         case MODCTL_LOAD:
  282                 error = copyin(arg, &ml, sizeof(ml));
  283                 if (error != 0)
  284                         break;
  285                 error = handle_modctl_load(ml.ml_filename, ml.ml_flags,
  286                     ml.ml_props, ml.ml_propslen);
  287                 break;
  288 
  289         case MODCTL_UNLOAD:
  290                 error = copyinstr(arg, buf, sizeof(buf), NULL);
  291                 if (error == 0) {
  292                         error = module_unload(buf);
  293                 }
  294                 break;
  295 
  296         case MODCTL_STAT:
  297                 error = copyin(arg, &iov, sizeof(iov));
  298                 if (error != 0) {
  299                         break;
  300                 }
  301                 error = handle_modctl_stat(&iov, arg);
  302                 break;
  303 
  304         case MODCTL_EXISTS:
  305 #ifndef MODULAR
  306                 error = ENOSYS;
  307 #else
  308                 loadtype = (uintptr_t)arg;
  309                 switch (loadtype) {     /* 0 = modload, 1 = autoload */
  310                 case 0:                 /* FALLTHROUGH */
  311                 case 1:
  312                         error = kauth_authorize_system(kauth_cred_get(),
  313                              KAUTH_SYSTEM_MODULE, 0,
  314                              (void *)(uintptr_t)MODCTL_LOAD,
  315                              (void *)loadtype, NULL);
  316                         break;
  317                 default:
  318                         error = EINVAL;
  319                         break;
  320                 }
  321 #endif
  322                 break;
  323 
  324         default:
  325                 (void)module_autoload("compat_80", MODULE_CLASS_EXEC);
  326                 MODULE_HOOK_CALL(compat_modstat_80_hook,
  327                     (SCARG(uap, cmd), &iov, arg), enosys(), error);
  328                 if (error == ENOSYS)
  329                         error = EINVAL;
  330                 break;
  331         }
  332 
  333         return error;
  334 }

Cache object: c2b050d0d29043e0fbdd5a988fd769fa


[ 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.