security

Total 112
Today 0
profile_image
ino
04-02-20 16:24 0개 3,006회
Linux kernel do_mremap VMA limit local privilege escalation
Product: Linux kernel

Version: 2.2 up to 2.2.25, 2.4 up to 2.4.24, 2.6 up to 2.6.2

Vendor: http://www.kernel.org/

URL: http://isec.pl/vulnerabilities/isec-0014-mremap-unmap.txt

CVE: CAN-2004-0077

Author: Paul Starzetz

Date: February 18, 2004





Issue:

======



A critical security vulnerability has been found in the Linux kernel

memory management code inside the mremap(2) system call due to missing

function return value check. This bug is completely unrelated to the

mremap bug disclosed on 05-01-2004 except concerning the same internal

kernel function code.





Details:

========



The Linux kernel manages a list of user addressable valid memory

locations on a per process basis. Every process owns a single linked

list of so called virtual memory area descriptors (called from now on

just VMAs). Every VMA describes the start of a valid memory region, its

length and moreover various memory flags like page protection.



Every VMA in the list corresponds to a part of the process's page table.

The page table contains descriptors (in short page table entries PTEs)

of physical memory pages seen by the process. The VMA descriptor can be

thus understood as a high level description of a particular region of

the process's page table storing PTE properties like page R/W flag and

so on.



The mremap() system call provides resizing (shrinking or growing) as

well as moving of existing virtual memory areas or any of its parts

across process's addressable space.



Moving a part of the virtual memory from inside a VMA area to a new

location requires creation of a new VMA descriptor as well as copying

the underlying page table entries described by the VMA from the old to

the new location in the process's page table.



To accomplish this task the do_mremap code calls the do_munmap()

internal kernel function to remove any potentially existing old memory

mapping in the new location as well as to remove the old virtual memory

mapping. Unfortunately the code doesn't test the return value of the

do_munmap() function which may fail if the maximum number of available

VMA descriptors has been exceeded. This happens if one tries to unmap

middle part of an existing memory mapping and the process's limit on the

number of VMAs has been reached (which is currently 65535).



One of the possible situations can be illustrated with the following

picture. The corresponding page table entries (PTEs) have been marked

with o and x:



Before mremap():



(oooooooooooooooooooooooo) (xxxxxxxxxxxx)

[----------VMA1----------] [----VMA2----]

[REMAPPED-VMA] <---------------|





After mremap() without VMA limit:



(oooo)(xxxxxxxxxxxx)(oooo)

[VMA3][REMAPPED-VMA][VMA4]





After mremap() but VMA limit:



(ooooxxxxxxxxxxxxxxoooo)

[---------VMA1---------]

[REMAPPED-VMA]





After the maximum number of VMAs in the process's VMA list has been

reached do_munmap() will refuse to create the necessary VMA hole because

it would split the original VMA in two disjoint VMA areas exceeding the

VMA descriptor limit.



Due to the missing return value check after trying to unmap the middle

of the VMA1 (this is the first invocation of do_munmap inside do_mremap

code) the corresponding page table entries from VMA2 are still inserted

into the page table location described by VMA1 thus being subject to

VMA1 page protection flags. It must be also mentioned that the original

PTEs in the VMA1 are lost thus leaving the corresponding page frames

unusable for ever.



The kernel also tries to insert the overlapping VMA area into the VMA

descriptor list but this fails due to further checks in the low level

VMA manipulation code. The low level VMA list check in the 2.4 and 2.6

kernel versions just call BUG() therefore terminating the malicious

process.



There are also two other unchecked calls to do_munmap() inside the

do_mremap() code and we believe that the second occurrence of unchecked

do_munmap is also exploitable. The second occurrence takes place if the

VMA to be remapped is beeing truncated in place. Note that do_munmap can

also fail on an exceptional low memory condition while trying to

allocate a VMA descriptor.



We were able to create a robust proof-of-concept exploit code giving

full super-user privileges on all vulnerable kernel versions. The

exploit code will be released next week.





Impact:

=======



Since no special privileges are required to use the mremap(2) system

call any process may use its unexpected behavior to disrupt the kernel

memory management subsystem.



Proper exploitation of this vulnerability leads to local privilege

escalation giving an attacker full super-user privileges. The

vulnerability may also lead to a denial-of-service attack on the

available system memory.



Tested and known to be vulnerable kernel versions are all <= 2.2.25, <=

2.4.24 and <= 2.6.2. The 2.2.25 version of Linux kernel does not

recognize the MREMAP_FIXED flag but this does not prevent the bug from

being successfully exploited. All users are encouraged to patch all

vulnerable systems as soon as appropriate vendor patches are released.

There is no hotfix for this vulnerablity. Limited per user virtual

memory still permits do_munmap() to fail.





Credits:

========



Paul Starzetz has identified the vulnerability and

performed further research. COPYING, DISTRIBUTION, AND MODIFICATION OF

INFORMATION PRESENTED HERE IS ALLOWED ONLY WITH EXPRESS PERMISSION OF

ONE OF THE AUTHORS.





Disclaimer:

===========



This document and all the information it contains are provided "as is",

for educational purposes only, without warranty of any kind, whether

express or implied.



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.





===== 메일링 리스트.. 홍석범님... =====

안녕하십니까? 오늘과내일의 홍석범입니다.



한달여전에 발견된 리눅스 커널의 메모리 관리 코드인 mremap 에서의 취약성에 이어

이번에는 같은 코드에서 return value 를 체크하지 않는 문제로 인하여 일반유저 권한으로

local 에서 root 권한을 획득할 수 있는 심각한 취약성이 발견되었습니다.



이로써 금번까지 3달 연속 약 한 달을 주기로 심각한

리눅스 커널 취약성이 발견되고 있습니다.



12월초순 : do_brk() 함수에서의 취약성 (2.4.22 이하 버전 취약)

1월 중순 : mremap 에서 bound 체킹 취약성 (2.4.23 이하 버전 취약)

2월중순 : mremap 에서 return value 취약성 (2.4.24 이하 버전 취약)



이번 취약성 역시 현존하는 모든 리눅스 커널에 해당하며

취약한 버전과 안전한 버전은 각각 다음과 같습니다.



-------------------------------------------------------------

취약한 버전 | 패치버전

-------------------------------------------------------------

* 커널 2.2.25 를 포함한 2.2.25 이전 버전 --> 패치버전 미제공

* 커널 2.4.24 를 포함한 2.4.24 이전 버전 --> 2.4.25

* 커널 2.6.2 를 포함한 2.6.2 버전 --> 2.6.3

--------------------------------------------------------------



참고로 금번 취약성과 관련된 패치는 아래와 같습니다.



--- linux-2.4.20/mm/mremap.c~ 2004-02-05 00:17:20.000000000 +0000

+++ linux-2.4.20/mm/mremap.c 2004-02-05 00:22:32.000000000 +0000

@@ -305,7 +305,9 @@

if ((addr <= new_addr) && (addr+old_len) > new_addr)

goto out;



- do_munmap(current->mm, new_addr, new_len);

+ ret = do_munmap(current->mm, new_addr, new_len);

+ if (ret && new_len)

+ goto out;

}



/*

@@ -313,9 +315,11 @@

* the unnecessary pages..

* do_munmap does all the needed commit accounting

*/

- ret = addr;

if (old_len >= new_len) {

- do_munmap(current->mm, addr+new_len, old_len - new_len);

+ ret = do_munmap(current->mm, addr+new_len, old_len - new_len);

+ if (ret && old_len != new_len)

+ goto out;

+ ret = addr;

if (!(flags & MREMAP_FIXED) || (new_addr == addr))

goto out;

old_len = new_len;





커널소스 다운로드 : ftp://ftp.kr.kernel.org/pub/linux/kernel/



만약 rpm 으로 커널을 패치하시려면 각각 아래의 URL 을 참고하시기 바랍니다.



* 레드햇 9.0

https://rhn.redhat.com/errata/RHSA-2004-065.html



* 레드햇 7.2 / 7.3/ 8.0 (곧 제공될 예정)

http://download.fedoralegacy.org/



참고로, 아래 URL 에서는 레드햇 7.2/7.3/8.0 에 대해 유료로 rpm 패치를 제공하고 있군요.

http://transition.progeny.com/





패치가 종료된 후 시스템이 취약한 지 여부는 다음과 같이 확인 가능합니다.

(단지, Proof Of Concept 일 뿐 시스템에 영향을 주지는 않습니다.)



소스코드 다운로드 : http://www.security.nnov.ru/files/mremap_poc_2.c



$ gcc -o mremap_poc_2 mremap_poc_2.c //컴파일





## 취약한 커널 버전(2.4.24)의 경우



$ ./mremap_poc_2

mmap: Cannot allocate memory

created ~65530 VMAs

now mremapping 0x3FFE5000 at 0x3FFE1000Segmentation fault



이후 dmesg 또는 /var/log/messages 파일을 확인하면 다음과 같은

로그가 보이게 됩니다.



$ dmesg | tail -n 15 또는 tail -15 /var/log/messages



kernel BUG at mmap.c:1188!

invalid operand: 0000

CPU: 0

EIP: 0010:[] Not tainted

EFLAGS: 00010287

eax: 3ffe2000 ebx: cead2140 ecx: cead3ec0 edx: cead3f60

esi: cead2124 edi: cead20e0 ebp: cead2140 esp: cf6b1f48

ds: 0018 es: 0018 ss: 0018

Process mremap_poc_2 (pid: 24785, stackpage=cf6b1000)

Stack: cead2140 cead2124 cead20e0 00000002 00000002 c0127f84 ce3be780 c0127ff4

ce3be780 cead2140 cf6b0000 00001000 3ffe5000 ce3be79c ce3be780 3ffe2000

cf6b0000 cead20e0 cead3f00 c01280ab 3ffe5000 00001000 00001000 00000003

Call Trace: [] [] [] []



Code: 0f 0b a4 04 01 e7 1e c0 8b 7c 24 10 8b 74 24 14 8b 5c 24 18





## 취약하지 않은 커널 버전(2.4.25)의 경우



$ ./mremap_poc_2

mmap: Cannot allocate memory

created ~65530 VMAs

now mremapping 0x3FFE5000 at 0x3FFE1000

kernel may not be vulnerable



dmesg 에 아무런 로그가 남지 않음.





본 취약성에 대한 자세한 내용은 아래의 URL 을 참고하시기 바랍니다.



http://www.isec.pl/vulnerabilities/isec-0014-mremap-unmap.txt

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0077









감사합니다.

댓글목록

등록된 댓글이 없습니다.