Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/sys Fix anonymous memory object leak for sigcode.



details:   https://anonhg.NetBSD.org/src/rev/67945dc6222f
branches:  trunk
changeset: 1026478:67945dc6222f
user:      ryo <ryo%NetBSD.org@localhost>
date:      Fri Nov 26 08:06:11 2021 +0000

description:
Fix anonymous memory object leak for sigcode.

- Repeating "modload compat_linux && /emul/linux/bin/ls && modunload compat_linux"
  will reproduce this problem.
- It cause in exec_sigcode_map(), anon-object for sigcode was created at
  first exec, but it remained even after exec_remove.
- Fixed that the anon-object for sigcode is created at exec_add(), and the
  anon-object reference is removed at exec_remove().
- sigobject_lock is no longer needed since it is locked by exec_lock.
- The compat_16 module rewrites the e_sigcode entry in emul_netbsd directly and
  does not use exec_add()/exec_remove(), so it needs to call
  sigcode_alloc()/sigcode_free() on its own.

diffstat:

 sys/compat/common/kern_sig_16.c          |   19 ++--
 sys/compat/netbsd32/netbsd32_compat_16.c |   19 ++++-
 sys/kern/kern_exec.c                     |  124 ++++++++++++++++++++++---------
 sys/sys/exec.h                           |    4 +-
 4 files changed, 119 insertions(+), 47 deletions(-)

diffs (truncated from 341 to 300 lines):

diff -r 6571954efb77 -r 67945dc6222f sys/compat/common/kern_sig_16.c
--- a/sys/compat/common/kern_sig_16.c   Thu Nov 25 21:59:40 2021 +0000
+++ b/sys/compat/common/kern_sig_16.c   Fri Nov 26 08:06:11 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_sig_16.c,v 1.6 2020/05/23 23:42:41 ad Exp $       */
+/*     $NetBSD: kern_sig_16.c,v 1.7 2021/11/26 08:06:11 ryo Exp $      */
 
 /*-
  * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -66,13 +66,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sig_16.c,v 1.6 2020/05/23 23:42:41 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sig_16.c,v 1.7 2021/11/26 08:06:11 ryo Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
 #endif
 
 #include <sys/param.h>
+#include <sys/exec.h>
 #include <sys/kernel.h>
 #include <sys/rwlock.h>
 #include <sys/signalvar.h>
@@ -92,8 +93,6 @@
 
 #include <compat/common/compat_mod.h>
 
-extern krwlock_t exec_lock;
-
 #if !defined(__amd64__) || defined(COMPAT_NETBSD32)
 #define COMPAT_SIGCONTEXT
 extern char sigcode[], esigcode[];
@@ -155,11 +154,17 @@
        emul_netbsd.e_sigcode = sigcode;
        emul_netbsd.e_esigcode = esigcode;
        emul_netbsd.e_sigobject = &emul_netbsd_object;
+       error = exec_sigcode_alloc(&emul_netbsd);
+       if (error) {
+               emul_netbsd.e_sigcode = NULL;
+               emul_netbsd.e_esigcode = NULL;
+               emul_netbsd.e_sigobject = NULL;
+       }
        rw_exit(&exec_lock);
        MODULE_HOOK_SET(sendsig_sigcontext_16_hook, sendsig_sigcontext);
 #endif
 
-       return 0;
+       return error;
 }
 
 int
@@ -195,9 +200,7 @@
         * is reference counted so will die eventually.
         */
        rw_enter(&exec_lock, RW_WRITER);
-       if (emul_netbsd_object != NULL) {
-               (*emul_netbsd_object->pgops->pgo_detach)(emul_netbsd_object);
-       }
+       exec_sigcode_free(&emul_netbsd);
        emul_netbsd_object = NULL;
        emul_netbsd.e_sigcode = NULL;
        emul_netbsd.e_esigcode = NULL;
diff -r 6571954efb77 -r 67945dc6222f sys/compat/netbsd32/netbsd32_compat_16.c
--- a/sys/compat/netbsd32/netbsd32_compat_16.c  Thu Nov 25 21:59:40 2021 +0000
+++ b/sys/compat/netbsd32/netbsd32_compat_16.c  Fri Nov 26 08:06:11 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: netbsd32_compat_16.c,v 1.3 2019/12/15 16:48:26 tsutsui Exp $   */
+/*     $NetBSD: netbsd32_compat_16.c,v 1.4 2021/11/26 08:06:11 ryo Exp $       */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -29,12 +29,13 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_compat_16.c,v 1.3 2019/12/15 16:48:26 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_compat_16.c,v 1.4 2021/11/26 08:06:11 ryo Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/module.h>
 #include <sys/dirent.h>
+#include <sys/exec.h>
 #include <sys/lwp.h>
 #include <sys/syscallargs.h>
 #include <sys/syscallvar.h>
@@ -51,19 +52,33 @@
 static int
 compat_netbsd32_16_modcmd(modcmd_t cmd, void *arg)
 {
+       int error;
 
        switch (cmd) {
        case MODULE_CMD_INIT:
+               rw_enter(&exec_lock, RW_WRITER);
                emul_netbsd32.e_sigcode = netbsd32_sigcode;
                emul_netbsd32.e_esigcode = netbsd32_esigcode;
                emul_netbsd32.e_sigobject = &emul_netbsd32_object;
+               error = exec_sigcode_alloc(&emul_netbsd);
+               if (error) {
+                       emul_netbsd32.e_sigcode = NULL;
+                       emul_netbsd32.e_esigcode = NULL;
+                       emul_netbsd32.e_sigobject = NULL;
+               }
+               rw_exit(&exec_lock);
+               if (error)
+                       return error;
                netbsd32_machdep_md_16_init();
                return 0;
 
        case MODULE_CMD_FINI:
+               rw_enter(&exec_lock, RW_WRITER);
+               exec_sigcode_free(&emul_netbsd);
                emul_netbsd32.e_sigcode = NULL;
                emul_netbsd32.e_esigcode = NULL;
                emul_netbsd32.e_sigobject = NULL;
+               rw_exit(&exec_lock);
                netbsd32_machdep_md_16_fini();
                return 0;
 
diff -r 6571954efb77 -r 67945dc6222f sys/kern/kern_exec.c
--- a/sys/kern/kern_exec.c      Thu Nov 25 21:59:40 2021 +0000
+++ b/sys/kern/kern_exec.c      Fri Nov 26 08:06:11 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_exec.c,v 1.513 2021/11/25 10:31:50 ryo Exp $      */
+/*     $NetBSD: kern_exec.c,v 1.514 2021/11/26 08:06:12 ryo Exp $      */
 
 /*-
  * Copyright (c) 2008, 2019, 2020 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.513 2021/11/25 10:31:50 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.514 2021/11/26 08:06:12 ryo Exp $");
 
 #include "opt_exec.h"
 #include "opt_execfmt.h"
@@ -250,8 +250,6 @@
  */
 krwlock_t exec_lock __cacheline_aligned;
 
-static kmutex_t sigobject_lock __cacheline_aligned;
-
 /*
  * Data used between a loadvm and execve part of an "exec" operation
  */
@@ -1815,7 +1813,7 @@
 exec_add(struct execsw *esp, int count)
 {
        struct exec_entry       *it;
-       int                     i;
+       int                     i, error = 0;
 
        if (count == 0) {
                return 0;
@@ -1840,8 +1838,23 @@
        for (i = 0; i < count; i++) {
                it = kmem_alloc(sizeof(*it), KM_SLEEP);
                it->ex_sw = &esp[i];
+               error = exec_sigcode_alloc(it->ex_sw->es_emul);
+               if (error != 0) {
+                       kmem_free(it, sizeof(*it));
+                       break;
+               }
                LIST_INSERT_HEAD(&ex_head, it, ex_list);
        }
+       /* If even one fails, remove them all back. */
+       if (error != 0) {
+               for (i--; i >= 0; i--) {
+                       it = LIST_FIRST(&ex_head);
+                       LIST_REMOVE(it, ex_list);
+                       exec_sigcode_free(it->ex_sw->es_emul);
+                       kmem_free(it, sizeof(*it));
+               }
+               return error;
+       }
 
        /* update execsw[] */
        exec_init(0);
@@ -1886,6 +1899,7 @@
                        next = LIST_NEXT(it, ex_list);
                        if (it->ex_sw == &esp[i]) {
                                LIST_REMOVE(it, ex_list);
+                               exec_sigcode_free(it->ex_sw->es_emul);
                                kmem_free(it, sizeof(*it));
                                break;
                        }
@@ -1919,7 +1933,6 @@
                vaddr_t vmin = 0, vmax;
 
                rw_init(&exec_lock);
-               mutex_init(&sigobject_lock, MUTEX_DEFAULT, IPL_NONE);
                exec_map = uvm_km_suballoc(kernel_map, &vmin, &vmax,
                    maxexec*NCARGS, VM_MAP_PAGEABLE, false, NULL);
                pool_init(&exec_pool, NCARGS, 0, 0, PR_NOALIGN|PR_NOTOUCH,
@@ -1986,22 +1999,25 @@
        return 0;
 }
 
-static int
-exec_sigcode_map(struct proc *p, const struct emul *e)
+int
+exec_sigcode_alloc(const struct emul *e)
 {
        vaddr_t va;
        vsize_t sz;
        int error;
        struct uvm_object *uobj;
 
+       KASSERT(rw_lock_held(&exec_lock));
+
+       if (e == NULL || e->e_sigobject == NULL)
+               return 0;
+
        sz = (vaddr_t)e->e_esigcode - (vaddr_t)e->e_sigcode;
-
-       if (e->e_sigobject == NULL || sz == 0) {
+       if (sz == 0)
                return 0;
-       }
 
        /*
-        * If we don't have a sigobject for this emulation, create one.
+        * Create a sigobject for this emulation.
         *
         * sigobject is an anonymous memory object (just like SYSV shared
         * memory) that we keep a permanent reference to and that we map
@@ -2011,32 +2027,68 @@
         * We map it with PROT_READ|PROT_EXEC into the process just
         * the way sys_mmap() would map it.
         */
+       if (*e->e_sigobject == NULL) {
+               uobj = uao_create(sz, 0);
+               (*uobj->pgops->pgo_reference)(uobj);
+               va = vm_map_min(kernel_map);
+               if ((error = uvm_map(kernel_map, &va, round_page(sz),
+                   uobj, 0, 0,
+                   UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
+                   UVM_INH_SHARE, UVM_ADV_RANDOM, 0)))) {
+                       printf("sigcode kernel mapping failed %d\n", error);
+                       (*uobj->pgops->pgo_detach)(uobj);
+                       return error;
+               }
+               memcpy((void *)va, e->e_sigcode, sz);
+#ifdef PMAP_NEED_PROCWR
+               pmap_procwr(&proc0, va, sz);
+#endif
+               uvm_unmap(kernel_map, va, va + round_page(sz));
+               *e->e_sigobject = uobj;
+               KASSERT(uobj->uo_refs == 1);
+       } else {
+               /* if already created, reference++ */
+               uobj = *e->e_sigobject;
+               (*uobj->pgops->pgo_reference)(uobj);
+       }
+
+       return 0;
+}
+
+void
+exec_sigcode_free(const struct emul *e)
+{
+       struct uvm_object *uobj;
+
+       KASSERT(rw_lock_held(&exec_lock));
+
+       if (e == NULL || e->e_sigobject == NULL)
+               return;
 
        uobj = *e->e_sigobject;
-       if (uobj == NULL) {
-               mutex_enter(&sigobject_lock);
-               if ((uobj = *e->e_sigobject) == NULL) {
-                       uobj = uao_create(sz, 0);
-                       (*uobj->pgops->pgo_reference)(uobj);
-                       va = vm_map_min(kernel_map);
-                       if ((error = uvm_map(kernel_map, &va, round_page(sz),
-                           uobj, 0, 0,
-                           UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
-                           UVM_INH_SHARE, UVM_ADV_RANDOM, 0)))) {
-                               printf("kernel mapping failed %d\n", error);
-                               (*uobj->pgops->pgo_detach)(uobj);
-                               mutex_exit(&sigobject_lock);
-                               return error;
-                       }
-                       memcpy((void *)va, e->e_sigcode, sz);
-#ifdef PMAP_NEED_PROCWR
-                       pmap_procwr(&proc0, va, sz);
-#endif
-                       uvm_unmap(kernel_map, va, va + round_page(sz));
-                       *e->e_sigobject = uobj;
-               }
-               mutex_exit(&sigobject_lock);
-       }
+       if (uobj == NULL)
+               return;
+



Home | Main Index | Thread Index | Old Index