]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: Support Linux-specific handling of envp / argv in psinfo
authorKris Van Hees <kris.van.hees@oracle.com>
Wed, 14 Oct 2015 12:09:29 +0000 (08:09 -0400)
committerKris Van Hees <kris.van.hees@oracle.com>
Wed, 18 Nov 2015 00:54:10 +0000 (19:54 -0500)
The implementation of retrievable envp and argv psinfo in Linux
requires those arrays to be located in kernel memory whereas in
traditional systems with DTrace implementations this was found in
userspace memory.  Therefore, scripts expect to be able to access
this memory using copyin().  We look at the address passed in for
a copyin operation (or copyinstr) and if it is one of these special
cases, we simply pretend to retrieve data from userspace while in
reality we're simply retrieving the data from kernel space.

Orabug: 21984854
Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
Acked-by: Nick Alcock <nick.alcock@oracle.com>
dtrace/dtrace_asm_sparc64.S
dtrace/dtrace_isa.c
dtrace/dtrace_isa_x86_64.c
dtrace/include/dtrace/dtrace_impl.h

index dcea85cb07bb3dac50e9f7ca3679cc54b096f94a..f9daf136fe4baad90b53b33d3050f2427f993fd6 100644 (file)
        mov     -1, %o0
        ENDPROC(dtrace_caller)
 
-       ENTRY(dtrace_copyin)
+       ENTRY(dtrace_copyin_arch)
        tst     %o2
        bz      2f
        clr     %g1
 2:
        retl
        nop
-       ENDPROC(dtrace_copyin)
+       ENDPROC(dtrace_copyin_arch)
 
-       ENTRY(dtrace_copyinstr)
+       ENTRY(dtrace_copyinstr_arch)
        tst     %o2
        bz      2f
        clr     %g1
 2:
        retl
        nop
-       ENDPROC(dtrace_copyinstr)
+       ENDPROC(dtrace_copyinstr_arch)
 
        ENTRY(dtrace_copyout)
        tst     %o2
index 29b74e067eaab7e7bdff2db3b08daf1f3f3ea091..1a75be2fbae413e1b4559672b7a0da66280895ce 100644 (file)
@@ -67,6 +67,59 @@ void dtrace_toxic_ranges(void (*func)(uintptr_t, uintptr_t))
        /* FIXME */
 }
 
+/*
+ * Handle a few special cases where we store information in kernel memory that
+ * in other systems is typically found in userspace.
+ */
+static int dtrace_fake_copyin(intptr_t addr, size_t size)
+{
+       dtrace_psinfo_t *psinfo = current->dtrace_psinfo;
+       uintptr_t       argv = (uintptr_t)psinfo->argv;
+       unsigned long   argc = psinfo->argc;
+       uintptr_t       envp = (uintptr_t)psinfo->envp;
+       unsigned long   envc = psinfo->envc;
+
+       /*
+        * Ensure addr is within the argv array (or the envp array):
+        *      addr in [argv..argv + argc * sizeof(psinfo->argv[0])[
+        * Ensure that addr + size is within the same array
+        *      addr + size in [argv..argv * sizeof(psinfo->argv[0])]
+        *
+        * To guard against overflows on (addr + size) we rewrite this basic
+        * equation:
+        *      addr + size <= argv + argc * sizeof(psinfo->argv[0])
+        * into:
+        *      addr - argv <= argc * sizeof(psinfo->argv[0]) - size
+        */
+       return (addr >= argv && addr - argv < argc * sizeof(psinfo->argv[0])
+                   && addr - argv <= argc * sizeof(psinfo->argv[0]) - size) ||
+              (addr >= envp && addr - envp < envc * sizeof(psinfo->envp[0])
+                   && addr - envp <= envc * sizeof(psinfo->envp[0]) - size);
+}
+
+void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
+                  volatile uint16_t *flags)
+{
+       if (dtrace_fake_copyin(uaddr, size)) {
+               memcpy((char *)kaddr, (char *)uaddr, size);
+               return;
+       }
+
+       dtrace_copyin_arch(uaddr, kaddr, size, flags);
+}
+
+void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
+                     volatile uint16_t *flags)
+{
+       if (dtrace_fake_copyin(uaddr, size)) {
+               strncpy((char *)kaddr, (char *)uaddr,
+                        min(size, (size_t)PR_PSARGS_SZ));
+               return;
+       }
+
+       dtrace_copyinstr_arch(uaddr, kaddr, size, flags);
+}
+
 ktime_t dtrace_gethrestime(void)
 {
        return dtrace_gethrtime();
index 43b90a5b39361b1331257ca2cf70413ad86d5e3c..1e99b0653759029d66f338db66348f8add1bf228 100644 (file)
@@ -85,8 +85,8 @@ static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
        return 1;
 }
 
-void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
-                  volatile uint16_t *flags)
+void dtrace_copyin_arch(uintptr_t uaddr, uintptr_t kaddr, size_t size,
+                       volatile uint16_t *flags)
 {
        if (dtrace_copycheck(uaddr, kaddr, size))
                dtrace_copy(uaddr, kaddr, size);
@@ -99,8 +99,8 @@ void dtrace_copyout(uintptr_t uaddr, uintptr_t kaddr, size_t size,
                dtrace_copy(kaddr, uaddr, size);
 }
 
-void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
-                     volatile uint16_t *flags)
+void dtrace_copyinstr_arch(uintptr_t uaddr, uintptr_t kaddr, size_t size,
+                          volatile uint16_t *flags)
 {
        if (dtrace_copycheck(uaddr, kaddr, size))
                dtrace_copystr(uaddr, kaddr, size, flags);
index cd2c420681ad6d87a12503077f7447c48eca2cee..2b237e973bd53b3ceba9f53245e27e652f536d29 100644 (file)
@@ -897,14 +897,21 @@ extern uint64_t dtrace_getarg(int, int);
 extern int dtrace_getstackdepth(dtrace_mstate_t *, int);
 extern int dtrace_getustackdepth(void);
 extern ulong_t dtrace_getreg(struct task_struct *, uint_t);
-extern void dtrace_copyin(uintptr_t, uintptr_t, size_t, volatile uint16_t *);
-extern void dtrace_copyout(uintptr_t, uintptr_t, size_t, volatile uint16_t *);
+extern void dtrace_copyin(uintptr_t, uintptr_t, size_t,
+                         volatile uint16_t *);
+extern void dtrace_copyout(uintptr_t, uintptr_t, size_t,
+                          volatile uint16_t *);
 extern void dtrace_copyinstr(uintptr_t, uintptr_t, size_t,
                             volatile uint16_t *);
 extern void dtrace_copyoutstr(uintptr_t, uintptr_t, size_t,
                              volatile uint16_t *);
 extern uintptr_t dtrace_caller(int);
 
+extern void dtrace_copyin_arch(uintptr_t, uintptr_t, size_t,
+                              volatile uint16_t *);
+extern void dtrace_copyinstr_arch(uintptr_t, uintptr_t, size_t,
+                                 volatile uint16_t *);
+
 extern void pdata_init(dtrace_module_t *, struct module *);
 extern void pdata_cleanup(dtrace_module_t *, struct module *);