суббота, 5 марта 2011 г.

sun.misc.Unsafe - немного магии вокруг JVM

Когда-то, выбирая декомпилятор, натолкнулся я на несколько изумительных статей на wasm.ru. Статьи они кажется потерли, или по крайней мере изменили адреса, но сохранили их в виде вордовского файла, который можно загрузить отсюда:



Описывают, что такое Unsafe api, предоставляющее программисту возможность работать с классами, методами и т.п. ниже того уровня , который позволяют штатные средства платформы Java - на фактически на уровне тех самых С-структур, которые используются внутри JVM для предоставления сущностей класс, инстанс класса, метод и т.п.

Что дает возможность делать многие вещи, которые в программировании на Java  "традиционно" считаются невыполнимыми - функция sizeOf, (возвращающая точный размер объекта в памяти , взятый напрямую из поля  структуры, которая представляет этот объект внутри JVM), наследования от final-класса (делается двумя шагами по сути -  в список предков класса добавляется нужный нам класс, и из таблицы модификаторов доступа для этого суперкласса во время выполнения программы удаляется final - и

всего делов ;)).



Ну и уже более изощренные и хакерские штучки - самомодицирующиеся во время выполнения методы..и т.п. Очень рекомендую эти статьи к прочтению :).

Да, конечно -- смещения полей в структурах высчитываются на пальцах, класс sun.mics.Unsafe недокументирован (но присутствует в Java с самого ее начала, и очень навряд ли будет из нее удален - я очень сильно подозреваю, что предоставляемые им низкоуровневые возможности используются инструментами типа отладчиков и т.п.), и в продакшне ни один Project Manager такое использоватьне позволит -- да и не требуется в обычных приложения никогда столь низкоуровневый доступ к JVM. Но знать, как ява-машины работает с классами внутри себя -- полезно и интересно, а знать что из обычной программы на чистой яве можно получать доступ такого уровня -- еще интересней.

И напоследок два слова по поводу того, что это gap в ява-машине, который будет закрыт в следующем же релизе и т.п.

Я не думаю, что это дыра в системе безопасности Java. Собственно, суммирую и повторю описанное в первой из статей.
Итак. Есть две точки входа для получения инстанса класса Unsafe, который позволит нам творить черную магию:

1) Получить его можно через Unsage.getUnsafe() - НО! только в том случае, если вызывающий класс был загружен первичным класслоадером (www.tedneward.com/files/Papers/BootClasspath /BootClasspath.pdf - тут можно прочитать подробней про иерархию класслоадеров). Это сделать несложно -- всего-то добавить ключ -Xbootclasspath в список стартовых опций ява-машины. Но для этого надо иметь доступ  к среде выполнения.

2) Можно просто взять private переменную theUnsafe - которая хранит инстанс класса Unsafe внутри него. Но если есть Security Manager и установлена для него соответствующая политика запрещения опасной рефлексии , получить значение этой закрытой переменной не удастся.

Соответственно, мой вывод -- это API не является уязвимостью в JVM, вовсе нет.
Потому что точно так же рефлексией (если она не запрещена в политиках безопасности) можно творить безобразия внутри приложения, но и польза от нее может быть большая-- надо просто разумно выставлять политики безопасности в каждом конкретном случае.

Да - Unsafe API дает беспрецедентный уровень доступа к среде выполнения Java из программы. Но чтобы получить доступ к этому апи -- надо либо иметь соотв. права на той машине, где выполняется приложение (например, возможность задавать параметры запуска ява-машины), либо должен быть соответственно сконфигурирован (без учета этой опасности) Security Manager.

7 комментариев:

  1. как бы нибыло, использование приватных, не public API никогда не приветствуется. в основном, потому что это не public api и они могут измениться без каких-либо репортов в change list (в основном они просто в тихоря используются внутри самой java). ну и применение в продакшене это же просто самоубийство.

    ОтветитьУдалить
  2. Я согласен) посмотри на заголовок блога ;)

    Я пишу о таких вещах, потому что мало кто знает что это вообще есть. А я рассказываю людям о всяких малоизвестных вещах в Java / JVM. Я не призываю нигде это использовать на практике активно.

    ОтветитьУдалить
  3. Битые ссылки, может есть другие?
    wasm.ru/article.php
    wasm.ru/article.php

    ОтветитьУдалить
  4. https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDIQFjAA&url=https%3A%2F%2Fwww.evilfingers.com%2Fpublications%2Fresearch_RU%2Funsafe-java.stuff.doc&ei=CxRNUfPGAsHNiwKgnYDABQ&usg=AFQjCNFKQ8jm_6SHEDTqNVJKRE84_jXsQQ&bvm=bv.44158598,d.cGE&cad=rja

    Скачиваемый файл с обеими статьями.

    ОтветитьУдалить
  5. Анонимный23 июня 2013 г., 22:55

    Как-то копался в исходниках JVM и прям мозолило глаза это Unsafe.

    Спасибо! Благодаря вашей статье упростил поиски информации по тебе этого Ансейфа :)

    ОтветитьУдалить
  6. обходим "защиту" Security Manager'a
    @SuppressWarnings("restriction")
    private static Unsafe getUnsafe()
    {
    try
    {
    Field field_theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
    field_theUnsafe.setAccessible(true);
    return (Unsafe) field_theUnsafe.get(null);
    }
    catch (Throwable e)
    {
    e.printStackTrace();
    }
    return null;
    }

    ОтветитьУдалить