
Снимок исходного кода ядра Linux 4.1.15 для анализа и изучения CVE-2022-3564, уязвимости в сетевой подсистеме ядра.
Linux kernel release 4.x http://kernel.org/
Это примечания к выпуску Linux версии 4. Прочтите их внимательно, поскольку они объясняют, что это такое, как установить ядро и что делать, если что-то пойдёт не так.
ЧТО ТАКОЕ LINUX?
Linux — это клон операционной системы Unix, написанный с нуля Линусом Торвальдсом при содействии разрозненной команды хакеров из Сети. Он нацелен на соответствие POSIX и Single UNIX Specification.
Он обладает всеми функциями, которые вы ожидаете от современной полноценной Unix, включая настоящую многозадачность, виртуальную память, разделяемые библиотеки, загрузку по требованию, разделяемые исполняемые файлы с копированием при записи, правильное управление памятью и многоуровневую поддержку сети, включая IPv4 и IPv6.
Он распространяется под лицензией GNU General Public License — см. прилагаемый файл COPYING для получения более подробной информации.
НА КАКОМ ОБОРУДОВАНИИ ОН РАБОТАЕТ?
Хотя изначально он был разработан для 32-битных ПК на базе x86 (386 или выше), сегодня Linux также работает (по крайней мере) на архитектурах Compaq Alpha AXP, Sun SPARC и UltraSPARC, Motorola 68000, PowerPC, PowerPC64, ARM, Hitachi SuperH, Cell, IBM S/390, MIPS, HP PA-RISC, Intel IA-64, DEC VAX, AMD x86-64, AXIS CRIS, Xtensa, Tilera TILE, AVR32 и Renesas M32R.
Linux легко переносится на большинство универсальных 32- или 64-битных архитектур при условии, что они имеют страничный блок управления памятью (PMMU) и порт компилятора GNU C (gcc) (часть набора компиляторов GNU, GCC). Linux также был портирован на ряд архитектур без PMMU, хотя функциональность в этом случае, очевидно, несколько ограничена. Linux также был портирован на самого себя. Теперь можно запускать ядро как пользовательское приложение — это называется UserMode Linux (UML).
ДОКУМЕНТАЦИЯ:
Существует множество документации, доступной как в электронном виде в Интернете, так и в книгах, как посвящённых непосредственно Linux, так и касающихся общих вопросов UNIX. Я рекомендую заглянуть в подкаталоги документации на любом FTP-сайте Linux за книгами LDP (Linux Documentation Project). Этот README не предназначен для документации по системе: доступны гораздо лучшие источники.
В подкаталоге Documentation/ есть различные файлы README: они обычно содержат специфические для ядра заметки по установке, например, для некоторых драйверов. См. Documentation/00-INDEX для списка того, что содержится в каждом файле. Пожалуйста, прочитайте файл Changes, так как он содержит информацию о проблемах, которые могут возникнуть при обновлении вашего ядра.
Подкаталог Documentation/DocBook/ содержит несколько руководств для разработчиков и пользователей ядра. Эти руководства могут быть отображены в различных форматах: PostScript (.ps), PDF, HTML и man-страницы, среди прочих. После установки "make psdocs", "make pdfdocs", "make htmldocs" или "make mandocs" отобразят документацию в запрошенном формате.
УСТАНОВКА исходных текстов ядра:
Если вы устанавливаете полные исходные тексты, поместите tar-архив ядра в каталог, где у вас есть права (например, в ваш домашний каталог), и распакуйте его:
xz -cd linux-4.X.tar.xz | tar xvf -
Замените "X" на номер версии последнего ядра.
НЕ используйте область /usr/src/linux! Эта область содержит (обычно неполный) набор заголовочных файлов ядра, которые используются заголовочными файлами библиотек. Они должны соответствовать библиотеке и не должны быть испорчены тем, чем бы ни оказалось ядро-дня (kernel-du-jour).
Вы также можете перейти между выпусками 4.x с помощью патчей. Патчи распространяются в формате xz. Чтобы установить с помощью патчей, получите все новые файлы патчей, войдите в верхний уровень каталога исходных текстов ядра (linux-4.X) и выполните:
xz -cd ../patch-4.x.xz | patch -p1
Замените "x" для всех версий, больших, чем версия "X" вашего текущего дерева исходных текстов, по порядку, и у вас всё должно быть в порядке. Возможно, вы захотите удалить резервные файлы (some-file-name~ или some-file-name.orig) и убедиться, что нет неудачных патчей (some-file-name# или some-file-name.rej). Если они есть, значит, ошиблись либо вы, либо я.
В отличие от патчей для ядер 4.x, патчи для ядер 4.x.y (также известных как -stable ядра) не являются инкрементальными, а применяются напрямую к базовому ядру 4.x. Например, если ваше базовое ядро — 4.0 и вы хотите применить патч 4.0.3, вы не должны сначала применять патчи 4.0.1 и 4.0.2. Аналогично, если вы работаете с ядром версии 4.0.2 и хотите перейти на 4.0.3, вы должны сначала отменить патч 4.0.2 (то есть patch -R) перед применением патча 4.0.3. Подробнее об этом можно прочитать в Documentation/applying-patches.txt
Как вариант, сценарий patch-kernel можно использовать для автоматизации этого процесса. Он определяет текущую версию ядра и применяет все найденные патчи.
linux/scripts/patch-kernel linux
Первый аргумент в приведённой выше команде — это расположение исходных текстов ядра. Патчи применяются из текущего каталога, но альтернативный каталог можно указать вторым аргументом.
Убедитесь, что у вас нет устаревших .o файлов и зависимостей:
cd linux make mrproper
Теперь у вас должны быть правильно установлены исходные тексты.
ТРЕБОВАНИЯ К ПРОГРАММНОМУ ОБЕСПЕЧЕНИЮ
Для компиляции и запуска ядер 4.x требуются актуальные версии различных программных пакетов. Обратитесь к Documentation/Changes для получения минимальных номеров версий и информации о том, как получить обновления для этих пакетов. Имейте в виду, что использование чрезмерно старых версий этих пакетов может вызывать косвенные ошибки, которые очень трудно отследить, поэтому не предполагайте, что можно просто обновить пакеты, когда очевидные проблемы возникают во время сборки или работы.
КАТАЛОГ СБОРКИ для ядра:
При компиляции ядра все выходные файлы по умолчанию будут храниться вместе с исходными текстами ядра. Использование опции "make O=output/dir" позволяет указать альтернативное место для выходных файлов (включая .config). Пример:
исходные тексты ядра: /usr/src/linux-4.X
каталог сборки: /home/name/build/kernel
Чтобы настроить и собрать ядро, используйте:
cd /usr/src/linux-4.X
make O=/home/name/build/kernel menuconfig
make O=/home/name/build/kernel
sudo make O=/home/name/build/kernel modules_install install
Пожалуйста, обратите внимание: если используется опция 'O=output/dir', то она должна использоваться для всех вызовов make.
КОНФИГУРИРОВАНИЕ ядра:
Не пропускайте этот шаг, даже если вы просто обновляете одну минорную версию. Новые параметры конфигурации добавляются в каждом выпуске, и странные проблемы возникнут, если файлы конфигурации не настроены должным образом. Если вы хотите перенести существующую конфигурацию в новую версию с минимальными усилиями, используйте "make oldconfig", который задаст вам вопросы только о новых параметрах.
Альтернативные команды конфигурации:
"make config" Интерфейс простого текста.
"make menuconfig" Текстовые цветные меню, радиосписки и диалоги.
"make nconfig" Улучшенные текстовые цветные меню.
"make xconfig" Инструмент конфигурации на основе X Window (Qt).
"make gconfig" Инструмент конфигурации на основе X Window (Gtk).
"make oldconfig" Отвечает на все вопросы значениями по умолчанию на основе содержимого вашего существующего файла ./.config и спрашивает о новых символах конфигурации.
"make silentoldconfig" Как указано выше, но не загромождает экран вопросами, на которые уже были даны ответы. Кроме того, обновляет зависимости.
"make olddefconfig" Как указано выше, но устанавливает новые символы в их значения по умолчанию без запроса.
"make defconfig" Создаёт файл ./.config, используя значения символов по умолчанию из arch/$ARCH/defconfig или arch/$ARCH/configs/${PLATFORM}_defconfig, в зависимости от архитектуры.
"make ${PLATFORM}_defconfig" Создаёт файл ./.config, используя значения символов по умолчанию из arch/$ARCH/configs/${PLATFORM}_defconfig. Используйте "make help", чтобы получить список всех доступных платформ вашей архитектуры.
"make allyesconfig" Создаёт файл ./.config, устанавливая значения символов в 'y' насколько это возможно.
"make allmodconfig" Создаёт файл ./.config, устанавливая значения символов в 'm' насколько это возможно.
"make allnoconfig" Создаёт файл ./.config, устанавливая значения символов в 'n' насколько это возможно.
"make randconfig" Создаёт файл ./.config, устанавливая значения символов в случайные значения.
"make localmodconfig" Создаёт конфигурацию на основе текущей конфигурации и загруженных модулей (lsmod). Отключает любые параметры модулей, которые не нужны для загруженных модулей.
Чтобы создать localmodconfig для другой машины,
сохраните вывод lsmod этой машины в файл
и передайте его как параметр LSMOD.
target$ lsmod > /tmp/mylsmod
target$ scp /tmp/mylsmod host:/tmp
host$ make LSMOD=/tmp/mylsmod localmodconfig
Вышеуказанное также работает при кросс-компиляции.
"make localyesconfig" Похоже на localmodconfig, за исключением того, что преобразует все параметры модулей во встроенные (=y) параметры.
Дополнительную информацию об использовании инструментов конфигурации ядра Linux можно найти в Documentation/kbuild/kconfig.txt.
ПРИМЕЧАНИЯ о "make config":
Наличие ненужных драйверов сделает ядро больше и может при некоторых обстоятельствах привести к проблемам: опрос несуществующей платы контроллера может сбить с толку ваши другие контроллеры.
Компиляция ядра с "Processor type", установленным выше 386, приведёт к тому, что ядро НЕ будет работать на 386. Ядро обнаружит это при загрузке и прекратит работу.
Ядро со встроенной эмуляцией математики по-прежнему будет использовать сопроцессор, если он присутствует: в этом случае эмуляция математики просто никогда не будет использоваться. Ядро будет немного больше, но будет работать на разных машинах независимо от того, есть ли у них математический сопроцессор или нет.
Детали конфигурации "kernel hacking" обычно приводят к большему или более медленному ядру (или и тому, и другому) и могут даже сделать ядро менее стабильным, настраивая некоторые процедуры на активные попытки сломать плохой код, чтобы найти проблемы ядра (kmalloc()). Таким образом, вам, вероятно, следует отвечать 'n' на вопросы о функциях "development", "experimental" или "debugging".
КОМПИЛЯЦИЯ ядра:
Убедитесь, что у вас есть как минимум gcc 3.2. Для получения дополнительной информации обратитесь к Documentation/Changes.
Обратите внимание, что вы всё ещё можете запускать пользовательские программы a.out с этим ядром.
Выполните "make", чтобы создать сжатый образ ядра. Также можно выполнить "make install", если у вас установлен lilo, подходящий для make-файлов ядра, но вы, возможно, захотите сначала проверить вашу конкретную настройку lilo.
Для выполнения фактической установки вы должны быть root, но ни одна из обычных операций сборки не должна требовать этого. Не поминайте имя root всуе.
Если вы настроили какие-либо части ядра как `modules', вам также придётся выполнить "make modules_install".
Подробный вывод компиляции/сборки ядра:
Обычно система сборки ядра работает в довольно тихом режиме (но не полностью молчаливом). Однако иногда вам или другим разработчикам ядра нужно видеть команды компиляции, компоновки или другие команды точно так, как они выполняются. Для этого используйте режим "verbose" сборки. Это делается путём вставки "V=1" в команду "make". Например:
make V=1 all
Чтобы система сборки также сообщала причину пересборки каждой цели, используйте "V=2". По умолчанию используется "V=0".
Держите резервное ядро под рукой на случай, если что-то пойдёт не так. Это особенно важно для разработочных выпусков, поскольку каждый новый выпуск содержит новый код, который не был отлажен. Убедитесь, что вы также храните резервную копию модулей, соответствующих этому ядру. Если вы устанавливаете новое ядро с тем же номером версии, что и ваше рабочее ядро, сделайте резервную копию вашего каталога модулей перед тем, как выполнить "make modules_install".
Как вариант, перед компиляцией используйте параметр конфигурации ядра "LOCALVERSION", чтобы добавить уникальный суффикс к обычной версии ядра. LOCALVERSION можно установить в меню "General Setup".
Чтобы загрузить ваше новое ядро, вам нужно скопировать образ ядра (например, .../linux/arch/i386/boot/bzImage после компиляции) в место, где находится ваше обычное загружаемое ядро.
Загрузка ядра непосредственно с дискеты без помощи загрузчика, такого как LILO, больше не поддерживается.
Если вы загружаете Linux с жёсткого диска, скорее всего, вы используете LILO, который использует образ ядра, указанный в файле /etc/lilo.conf. Файл образа ядра обычно находится в /vmlinuz, /boot/vmlinuz, /bzImage или /boot/bzImage. Чтобы использовать новое ядро, сохраните копию старого образа и скопируйте новый образ поверх старого. Затем вы ДОЛЖНЫ ПОВТОРНО ЗАПУСТИТЬ LILO, чтобы обновить карту загрузки!! Если вы этого не сделаете, вы не сможете загрузить новый образ ядра.
Переустановка LILO обычно сводится к запуску /sbin/lilo. Возможно, вы захотите отредактировать /etc/lilo.conf, чтобы указать запись для вашего старого образа ядра (скажем, /vmlinux.old) на случай, если новый не заработает. См. документацию LILO для получения дополнительной информации.
После переустановки LILO у вас всё должно быть готово. Выключите систему, перезагрузитесь и наслаждайтесь!
Если вам когда-либо понадобится изменить корневое устройство по умолчанию, видеорежим, размер ramdisk и т.д. в образе ядра, используйте программу 'rdev' (или, как альтернативу, параметры загрузки LILO, когда это уместно). Нет необходимости перекомпилировать ядро для изменения этих параметров.
Перезагрузитесь с новым ядром и наслаждайтесь.
ЕСЛИ ЧТО-ТО ПОШЛО НЕ ТАК:
Если у вас есть проблемы, которые, по-видимому, вызваны ошибками ядра, пожалуйста, проверьте файл MAINTAINERS, чтобы узнать, есть ли конкретный человек, связанный с той частью ядра, с которой у вас возникли проблемы. Если там никто не указан, то второе по полезности действие — отправить их мне ([email protected]) и, возможно, в любой другой соответствующий список рассылки или в группу новостей.
Во всех отчётах об ошибках, пожалуйста, сообщайте, о каком ядре идёт речь, как воспроизвести проблему и какова ваша конфигурация (используйте здравый смысл). Если проблема новая, сообщите мне об этом, а если проблема старая, пожалуйста, постарайтесь сообщить, когда вы впервые её заметили.
Если ошибка приводит к сообщению типа
unable to handle kernel paging request at address C0000010 Oops: 0002 EIP: 0010:XXXXXXXX eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx ds: xxxx es: xxxx fs: xxxx gs: xxxx Pid: xx, process nr: xx xx xx xx xx xx xx xx xx xx xx
или к подобной отладочной информации ядра на вашем экране или в системном журнале, пожалуйста, воспроизведите её точно. Дамп может выглядеть для вас непонятным, но он содержит информацию, которая может помочь в отладке проблемы. Текст над дампом также важен: он сообщает кое-что о том, почему ядро сбросило код (в приведённом выше примере это происходит из-за плохого указателя ядра). Более подробная информация о том, как понять дамп, находится в Documentation/oops-tracing.txt
Если вы скомпилировали ядро с CONFIG_KALLSYMS, вы можете отправить дамп как есть, в противном случае вам придётся использовать программу "ksymoops", чтобы понять дамп (но компиляция с CONFIG_KALLSYMS обычно предпочтительнее). Эту утилиту можно загрузить с ftp://ftp..kernel.org/pub/linux/utils/kernel/ksymoops/ . Как вариант, вы можете выполнить поиск по дампу вручную:
При отладке дампов, подобных приведённому выше, очень помогает, если вы можете выяснить, что означает значение EIP. Само по себе шестнадцатеричное значение мало помогает мне или кому-либо ещё: оно будет зависеть от вашей конкретной конфигурации ядра. Что вам следует сделать, так это взять шестнадцатеричное значение из строки EIP (игнорируя "0010:") и найти его в списке имён ядра, чтобы увидеть, какая функция ядра содержит ошибочный адрес.
Чтобы узнать имя функции ядра, вам нужно найти системный двоичный файл, связанный с ядром, которое проявило симптом. Это файл 'linux/vmlinux'. Чтобы извлечь список имён и сопоставить его с EIP из сбоя ядра, выполните:
nm vmlinux | sort | less
Это даст вам список адресов ядра, отсортированных в порядке возрастания, из которого легко найти функцию, содержащую ошибочный адрес. Обратите внимание, что адрес, указанный отладочными сообщениями ядра, не обязательно будет точно совпадать с адресами функций (на самом деле это очень маловероятно), поэтому вы не можете просто 'grep' этот список: однако список даст вам начальную точку каждой функции ядра, поэтому, найдя функцию, у которой начальный адрес ниже искомого, но за которой следует функция с более высоким адресом, вы найдёте нужную. На самом деле, возможно, будет хорошей идеей включить немного "контекста" в ваш отчёт о проблеме, приведя несколько строк вокруг интересующей.
Если вы по какой-то причине не можете сделать вышеуказанное (у вас есть предварительно скомпилированный образ ядра или что-то подобное), мне поможет как можно более подробное описание вашей конфигурации. Пожалуйста, прочитайте документ REPORTING-BUGS для подробностей.
Как вариант, вы можете использовать gdb на работающем ядре. (только для чтения; т.е. вы не можете изменять значения или устанавливать точки останова.) Чтобы сделать это, сначала скомпилируйте ядро с -g; соответствующим образом отредактируйте arch/i386/Makefile, затем выполните "make clean". Вам также нужно будет включить CONFIG_PROC_FS (через "make config").
После перезагрузки с новым ядром выполните "gdb vmlinux /proc/kcore". Теперь вы можете использовать все обычные команды gdb. Команда для поиска точки, где произошёл сбой вашей системы, — "l *0xXXXXXXXX". (Замените XXX на значение EIP.)
Использование gdb на неработающем ядре в настоящее время не работает, потому что gdb (ошибочно) игнорирует начальное смещение, с которым скомпилировано ядро.