From: Carlos O'Donell <carlos@systemhalted.org>
To: parisc-linux@lists.parisc-linux.org
Subject: [parisc-linux] [RFC] Fix compat_sys_timer_create kernel security hole.
Date: Mon, 1 Aug 2005 20:15:09 -0400 [thread overview]
Message-ID: <20050802001505.GA9703@systemhalted.org> (raw)
In-Reply-To: <20050801164250.GX9703@systemhalted.org>
On Mon, Aug 01, 2005 at 12:42:54PM -0400, Carlos O'Donell wrote:
> parisc,
>
> Another crash. Remember in the compat case that the source and destination
> addresses may have sr's both set to zero since you are copying into a
> temporary kernel structure.
>
> Backtrace:
> [<0000000010325ef4>] copy_to_user+0x34/0x40
> [<00000000101711dc>] sys_timer_create+0x294/0x8c8
> [<00000000101836f4>] compat_sys_timer_create+0x74/0xa8
> [<0000000010107f8c>] syscall_exit+0x0/0x14
Found my own bug. I tested this code but at the time the kernel address
dereference worked and it didn't crash. Oddly enough the timer tests
passed in glibc.
When you run the full testsuite in nptl it catches this bug. The value
of created_timer_id is a userspace address and requires a copy into the
kernel and a copy back out.
Could someone else review this patch for any thing else I might have
forgotten?
---
When using set_fs(KERNEL_DS) all the variables crossing the boundary
must be kernel addresses. Any user addresses would be treated as
kernel addresses and dereferences would cause an HPMC. This was the
case here. The value of created_timer_id must be read into the kernel
and later copied back out, the same for timer_event_spec.
2005-08-01 Carlos O'Donell <carlos@systemhalted.org>
* kernel/compat_signal.c (compat_copy_sigevent_to_user): New.
* kernel/compat.c (compat_sys_timer_create): Also copy
created_timer_id into kernel and use that.
* include/linux/compat_signal.h: Add prototypes.
Signed-of-by: Carlos O'Donell <carlos@systemhalted.org>
Index: kernel/compat_signal.c
===================================================================
RCS file: /var/cvs/linux-2.6/kernel/compat_signal.c,v
retrieving revision 1.7
diff -u -p -r1.7 compat_signal.c
--- kernel/compat_signal.c 3 Nov 2004 22:07:38 -0000 1.7
+++ kernel/compat_signal.c 2 Aug 2005 00:05:44 -0000
@@ -242,3 +242,39 @@ int compat_copy_sigevent_from_user(sigev
}
#endif
+#ifndef HAVE_ARCH_COPY_SIGEVENT_TO_USER
+int compat_copy_sigevent_to_user(compat_sigevent_t __user *to, sigevent_t *from)
+{
+ int err;
+ u32 scratch;
+
+ /* copy sigval_t sigev_value
+ int_t sival_int (same)
+ uptr_t sival_ptr (32 vs 64)*/
+ err = __put_user(from->sigev_value.sival_int,
+ &to->sigev_value.sival_int);
+ scratch = (u32 __force)from->sigev_value.sival_ptr & 0xffffffffUL;
+ err |= __put_user((compat_uptr_t)scratch, &to->sigev_value.sival_ptr);
+
+ /* copy int_t sigev_signo (same)*/
+ err |= __put_user(from->sigev_signo, &to->sigev_signo);
+
+ /* copy int_t sigev_notify (same)*/
+ err |= __put_user(from->sigev_notify, &to->sigev_notify);
+
+ /* never copy _sigev_un padding */
+
+ /* copy int_t _tid (same),
+ good_sigevent() uses this value of */
+ err |= __put_user(from->sigev_notify_thread_id, &to->sigev_notify_thread_id);
+
+ /* XXX: Do not copy these, they aren't used by
+ anyone. We would need to distinguish the uses of the union.
+ copy _sigev_thread
+ uptr_t _function (32 vs 64)
+ uptr_t _attribute (32 vs 64)*/
+
+ return err;
+}
+#endif
+
Index: kernel/compat.c
===================================================================
RCS file: /var/cvs/linux-2.6/kernel/compat.c,v
retrieving revision 1.27
diff -u -p -r1.27 compat.c
--- kernel/compat.c 22 Apr 2005 00:26:08 -0000 1.27
+++ kernel/compat.c 2 Aug 2005 00:05:46 -0000
@@ -663,17 +663,35 @@ long compat_sys_timer_create(clockid_t w
compat_timer_t __user * created_timer_id)
{
sigevent_t kevent;
+ timer_t ktimer;
mm_segment_t old_fs = get_fs();
long ret;
+ /* sigevent_t needs handling for 32-bit to 64-bit compat */
if (timer_event_spec != NULL)
if (compat_copy_sigevent_from_user(&kevent, timer_event_spec) != 0)
return -EFAULT;
+
+ /* Timer ID is assumed to be a non-struct simple value */
+ if (created_timer_id != NULL)
+ if (__get_user(ktimer, created_timer_id) != 0)
+ return -EFAULT;
set_fs(KERNEL_DS);
- ret = sys_timer_create(which_clock, timer_event_spec ? (sigevent_t __user *)&kevent : NULL, created_timer_id);
+ ret = sys_timer_create(which_clock,
+ timer_event_spec ? (sigevent_t __user *)&kevent : NULL,
+ created_timer_id ? (timer_t __user *)&ktimer : NULL);
set_fs(old_fs);
+
+ /* Copy back the results to userspace */
+ if (timer_event_spec != NULL)
+ if (compat_copy_sigevent_to_user(timer_event_spec, &kevent) != 0)
+ return -EFAULT;
+ if (created_timer_id != NULL)
+ if (__put_user(ktimer, created_timer_id) != 0)
+ return -EFAULT;
+
return ret;
}
Index: include/linux/compat_siginfo.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/linux/compat_siginfo.h,v
retrieving revision 1.7
diff -u -p -r1.7 compat_siginfo.h
--- include/linux/compat_siginfo.h 18 Mar 2005 14:38:12 -0000 1.7
+++ include/linux/compat_siginfo.h 2 Aug 2005 00:05:46 -0000
@@ -175,6 +175,7 @@ extern int compat_copy_siginfo_to_user(c
extern int compat_copy_siginfo_from_user(struct siginfo *to, compat_siginfo_t __user *from);
extern int compat_copy_sigevent_from_user(struct sigevent *to, compat_sigevent_t __user *from);
+extern int compat_copy_sigevent_to_user(compat_sigevent_t __user *to, struct sigevent *from);
#endif /* CONFIG_COMPAT */
#endif /* _ASM_GENERIC_COMPAT_SIGINFO_H */
_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
next prev parent reply other threads:[~2005-08-02 0:15 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-08-01 15:15 [parisc-linux] pa_memcpy kernel crashing testcase == "glibc +nptl +testsuite", and some tests Carlos O'Donell
2005-08-01 16:42 ` Carlos O'Donell
2005-08-02 0:15 ` Carlos O'Donell [this message]
2005-08-02 3:42 ` [parisc-linux] [RFC] Fix compat_sys_timer_create kernel security hole Carlos O'Donell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20050802001505.GA9703@systemhalted.org \
--to=carlos@systemhalted.org \
--cc=parisc-linux@lists.parisc-linux.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.