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>
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
/* 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();
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);
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);
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 *);