public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
* [Bug runtime/14848] New: Reading user memory fails occasionally when it shouldn't
@ 2012-11-15 16:21 dsmith at redhat dot com
  2012-11-27 19:24 ` [Bug runtime/14848] " dsmith at redhat dot com
  0 siblings, 1 reply; 2+ messages in thread
From: dsmith at redhat dot com @ 2012-11-15 16:21 UTC (permalink / raw)
  To: systemtap

http://sourceware.org/bugzilla/show_bug.cgi?id=14848

             Bug #: 14848
           Summary: Reading user memory fails occasionally when it
                    shouldn't
           Product: systemtap
           Version: unspecified
            Status: NEW
          Severity: normal
          Priority: P2
         Component: runtime
        AssignedTo: systemtap@sourceware.org
        ReportedBy: dsmith@redhat.com
    Classification: Unclassified


I was looking at some failures we're seeing in the syscall/nd_syscall test
cases on RHEL6 (2.6.32-279.14.1.el6.x86_64). Note I'm seeing the exact same
failure on rawhide (3.7.0-0.rc4.git3.1.fc19.x86_64).

The 32-bit clock tests are failing, because we fail to be able to read user
memory for the 2nd parameter of clock_settime(). The 64-bit clock test passes.

Here's the syscall.clock_settime probe from syscalls.stp (the nd_syscall
variant looks very similar):

====
probe syscall.clock_settime = kernel.function("sys_clock_settime").call
{
    name = "clock_settime"
    clk_id = $which_clock
    clk_id_str = _get_wc_str($which_clock)
    tp_uaddr = $tp
    argstr = sprintf("%s, %s", clk_id_str, _struct_timespec_u($tp, 1))
}
====

The problem is that _struct_timespec_u() is failing. The code in it that reads
user memory looks like this (from aux_syscalls.stp):

====
  if(_stp_copy_from_user((char *)&ts, ptr, n*sizeof(struct compat_timespec))) 
{
    strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
  }
====

Here's _stp_copy_from_user() from copy.c:

====
static unsigned long _stp_copy_from_user(char *dst, const char __user *src,
unsigned long count)
{
    if (count) {
                mm_segment_t _oldfs = get_fs();
                set_fs(USER_DS);
                pagefault_disable();
        if (access_ok(VERIFY_READ, src, count))
            count = __copy_from_user_inatomic(dst, src, count);
        else
            memset(dst, 0, count);
                pagefault_enable();
                set_fs(_oldfs);
    }
    return count;
}
====

Strangely enough, if I remove the access_ok() call, __copy_from_user_inatomic()
works fine. If I move the set_fs() call after the access_ok() call (which
effectively neuters the access_ok() call for x86_64 if I'm reading
arch/x86/asm/uaccess.h correctly), __copy_from_user_inatomic() also works fine.

I don't know why access_ok() is failing in this situation on an address that is
valid.

Just for reference, here's the code from sys_clock_settime() which accesses
user memory. Note it doesn't call access_ok():

====
    if (copy_from_user(&new_tp, tp, sizeof (*tp)))
        return -EFAULT;
====

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [Bug runtime/14848] Reading user memory fails occasionally when it shouldn't
  2012-11-15 16:21 [Bug runtime/14848] New: Reading user memory fails occasionally when it shouldn't dsmith at redhat dot com
@ 2012-11-27 19:24 ` dsmith at redhat dot com
  0 siblings, 0 replies; 2+ messages in thread
From: dsmith at redhat dot com @ 2012-11-27 19:24 UTC (permalink / raw)
  To: systemtap

http://sourceware.org/bugzilla/show_bug.cgi?id=14848

--- Comment #1 from David Smith <dsmith at redhat dot com> 2012-11-27 19:23:42 UTC ---
It looks like this is a "compat" issue. When we're doing a 32-bit executable on
a 64-bit kernel, user 'clock_settime()' ends up calling kernel
'compat_sys_clock_settime()', which looks like this:

====
long compat_sys_clock_settime(clockid_t which_clock,
        struct compat_timespec __user *tp)
{
    long err;
    mm_segment_t oldfs;
    struct timespec ts;

    if (get_compat_timespec(&ts, tp))
        return -EFAULT;
    oldfs = get_fs();
    set_fs(KERNEL_DS);
    err = sys_clock_settime(which_clock,
                (struct timespec __user *) &ts);
    set_fs(oldfs);
    return err;
}
====

I believe "access_ok()" is failing because the address that sys_clock_settime()
gets isn't a user address, it is a kernel address.

I don't know how to fix/workaround this yet.

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2012-11-27 19:24 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-15 16:21 [Bug runtime/14848] New: Reading user memory fails occasionally when it shouldn't dsmith at redhat dot com
2012-11-27 19:24 ` [Bug runtime/14848] " dsmith at redhat dot com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).