Aug 26

순수 자바를 이용하여 JVM을 죽게 하는 프로그램을 어떻게 짤까?

분류: Lang.Java 태그: ,, , , Heart @ 1:36 오전

Trackback : http://dev.heartsavior.net/archives/182/trackback/

순수 자바를 이용하여 JVM을 죽게 하는 프로그램을 어떻게 짜죠?

‘사랑하지 않으면 떠나라’ 의 한 챕터에서 제시하는, 자바 고급 프로그래머에 대한 면접 내용이다.

처음에 이 문제를 접했을 때 잠깐 착각을 해서 ‘순수 자바를 이용하여’ 라는 부분을 염두에 두지 못했다.

이 전제가 없으면 가장 편하게 생각할 수 있는 방법은 JNI 이다. JNI에서 C/C++ 라이브러리를 호출하고, 라이브러리 내부에서 런타임 에러로 crash 상태를 만들면(잘못된 메모리 참조 같은 쉬운 방법을 이용하자) JVM 도 crash 가 발생하게 된다. 견고한 JVM 을 피해서 돌아가는 답안이라고 할 수 있다. 그만큼 JNI 라이브러리를 작성할 때는 심혈을 기울여야 한다는 뜻이기도 하다.

하지만, ‘순수 자바를 이용하여’ 라는 전제가 붙는 것을 확인하고는 답을 낼 수 없었다. 자바 코드 내에서 발생하는 오류는 모두 Exception 이나 Error 로 잡힌다고 생각했던 것도 있고, JVM 내부는 공부해 본 적이 없기 때문이기도 했다.

그러다 오늘, 프로그래밍 갤러리에서 DriverManager Vulnerability 라는 글이 올라왔고, 약간의 논쟁 후에 immutable 속성인 String 클래스의 private field 를 수정하는 아이디어가 나타났다.
reflection을 몰라서 가능할 것이라고는 전혀 생각하지 못했다.
근데… reflection을 통해서 String 클래스의 private field 를 변경하는 글이 올라왔다. (첫번째 글 / 두번째 글)
이것 자체로도 나에게는 상당히 신기한 일이었다.
C/C++ 언어를 주로 다뤘던지라, 캡슐화는 견고함을 보장한다라고 생각을 하고 있었는데, reflection 으로 private field의 access 권한을 획득해버렸다.

근데, 첫번째 글의 결과를 보니… JVM이 죽었다!?

글에 적힌 crash 로그를 살펴보니 jre 1.5 버전이다.
같은 코드를 eclipse 에서 구현하여 해당 프로젝트의 JDK와 JRE를 1.5로 맞추었다.

String abc = "abc";
String def = "abc";
Field declaredField = String.class.getDeclaredField("value");
declaredField.setAccessible(true);
char[] abcArray = (char[]) declaredField.get(abc);
 
abcArray[0] = 'd';
 
System.out.println(def);

해당 코드를 호출했다. 역시, JVM이 crash되었다.

#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0×00aea4fc, pid=1764, tid=1672
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_16-b02 mixed mode, sharing)
# Problematic frame:
# j  net.heartsavior.dev.JVMDeath.crashJVMUsingStringObject()V+24
#
# An error report file with more information is saved as hs_err_pid1764.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#

뭐… 그래서 결론은 JVM 이 죽는 코드를 ‘구현했다’ 가 아닌 ‘발견했다’ 이고, 그나마 위의 코드는 1.6에서는 통하지 않는다…;;
위의 코드를 1.6에서 돌리면 정상적으로(라고 해야될라나) ‘def’ 가 출력된다.
( 이게 1.5만의 버그인지, 1.5 이하 공통 버그였다가 1.6에서 수정된 것인지는 잘 모르겠다. 귀찮다;; )

ps. 잘 생각해 보면 1.6도 JVM 이 죽지 않는다 뿐이지, String 클래스가 immutable 에서 해방될 수 있다…
즉, ” ‘뻘짓을 하지 않고 정식 루트로 접근할 경우’ String 클래스는 immutable 이다 ” 라고 할 수 있겠다. -_-;;

8 Responses to “순수 자바를 이용하여 JVM을 죽게 하는 프로그램을 어떻게 짤까?”

  1. sloth says:

    음.. JVM 버젼을 가리지않구 순수자바코드만으로 크래쉬시킬수있는 그런 방법을 찾으면 꼭 잊지말구 알려주세요,,,,^^;

  2. Heart says:

    sloth//JVM이 crash되는 경우에 대한 보고를 계속 하지 않을까요? ^^
    1.6에서 crash 되는 코드를 작성해도 1.7에서는 crash 안될 수도 있을꺼구요.
    (VM의 기본 목표는 crash가 발생하지 않는 환경일 테니까요~)
    각설하고;; 저도 1.6에서 crash되는 코드를 발견하면 다시 포스팅할테니까 sloth 님도 혹시 발견하시면 저한테 귀뜸 부탁드릴께요 ^^

  3. 민달이 says:

    순수 자바를 이용하여 JVM을 죽게 하는 프로그램을 어떻게 짜죠? 이라면

    System.exit(0);

    이렇게 하면 되는거 아닌가요? 그런데 문제를 너무 간단히 생각했는지는 모르겠네요.

  4. Heart says:

    민달이// 책에서 언급한 뉘앙스는 JVM의 메모리 구조라던지 이런 걸 모르기 때문에 이런 문제가 나왔을 때 대답을 하지 못한다고 하더라구요. 그걸 되짚어보면 JVM을 죽인다는 뜻을 ‘종료’의 의미가 아니라 ‘crash’ 의 의미로 생각할 수 있을 것 같아요.

  5. 민달이 says:

    메모리 구조라면 아래와 같은 방법이 있을 것 같습니다. 참조되는 객체는 GC수집이 안되는 것을 이용한 방법입니다.

    import java.util.LinkedList;
    import java.util.List;

    public class CrashUsingMemoryArchitecture {
    public static void main(String[] args) {
    List list = new LinkedList();
    StringBuffer buf = new StringBuffer(1024 * 1024);
    for (int i = 0; i < 1024; i++) {
    for (int j = 0; j < 1024; j++) {
    buf.append(”c”);
    }
    }

    while(true) {
    list.add(new String(buf.toString()));
    }
    }
    }

    실행결과

    Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOfRange(Unknown Source)
    at java.lang.String.(Unknown Source)
    at java.lang.StringBuffer.toString(Unknown Source)
    at com.prelude.experiment.crash.CrashUsingMemoryArchitecture.main(CrashUsingMemoryArchitecture.java:17)

  6. Heart says:

    민달이//
    음… ‘죽게 하다’ 가 Error 를 발생시키는 것 까지라면 맞는 답변이신 것 같아요 ^^
    (누가 누굴 판단하는… 퍽)

  7. 민달이 says:

    위 답변 틀린 것 같습니다. 저는 OutOfMemory가 발생하면 JVM이 죽을지 알았는데 그건 아니더라구요 ㅎ 시간날 때 좀더 고민해봐야 할 듯 싶네요.

  8. Heart says:

    민달이//
    민달이님의 의견까지 종합해 보면 이 문제는 JVM 의 취약점을 찾는 문제인 것 같네요 ^^
    (처리 가능한 Exception이나 Error가 되면 안되니까요~)

Leave a Reply