Рекомендации по взаимодействию с сообществом разработчиков ядра
Содержание
- Сообщение об ошибке в виде патча
- Предварительная настройка Git
- Предварительная настройка почтового клиента
- Выбор-репозитория и версии ядра для подготовки исправления
- Обновление репозитория до актуальной версии и создание новой ветки
- Внесение необходимых исправлений в код с соблюдением принятых правил форматирования
- Разбиение вносимых изменений по нескольким коммитам
- Коммит исправлений
- Добавление тегов в тело коммита
- Проверка компилируемости ядра
- Создание самого патча (серии патчей)
- Редактирование файла с патчем
- Обязательная проверка форматирования патча
- Отправка
- Подготовка второй версии патча
- Сообщение об ошибке без патча
- Перенос патчей в стабильную ветку ядра
- Добавление патчей напрямую в стабильную ветку ядра
Сообщение об ошибке в виде патча
Ниже на примере рассматривается подготовка и отправка в международное сообщество разработчиков ядра почтовой версии набора коммитов (патчей) с исправлением ошибки, обнаруженной в коде ядра с помощью статических или динамических средств анализа и тестирования. Более полную информацию о разработке, подготовке и отправке патчей, в том числе для случаев изменений в коде драйверов, связанном с платформами конечных устройств, а также о требованиях к отправляемому коду, можно получить в документации на docs.kernel.org:
- Submitting patches: the essential guide to getting your code into the kernel
- Linux Kernel patch submission checklist
- A guide to the Kernel Development Process
Предварительная настройка Git
Для корректного оформления патчей все коммиты должны быть подписаны при помощи опции --signoff команды git commit. Для этого необходимо добавить в конфигурацию Git ваше имя и электронную почту в параметры user.name и user.email, например:
git config --global user.name "Alexey Khoroshilov"
git config --global user.email "khoroshilov@ispras.ru"
Чтобы патчи, подготовленные для отправки в списки рассылки, не вставлять вручную в почтовый клиент, можно использовать команду git send-email. Для этого в конфигурацию Git в раздел [sendemail]. необходимо добавить параметры, соответствующие настройкам сервера SMTP, через который будет отправляться почта. Часто достаточно задать адрес сервера SMTP, порт, тип шифрования и используемый почтовый адрес:
git config --global sendemail.smtpServer "mail.ispras.ru"
git config --global sendemail.smtpServerPort "587"
git config --global sendemail.smtpEncryption "tls"
git config --global sendemail.smtpUser "ВАША ПОЧТА"
Также для изменения конфигурации Git можно использовать команду git config --global --edit, которая открывает файл конфигурации Git в редакторе.
Конфигурация Git для рассматриваемого примера выглядит следующим образом:
cat ~/.gitconfig
[user]
name = Alexey Khoroshilov
email = khoroshilov@ispras.ru
[sendemail]
smtpServer = mail.ispras.ru
smtpEncryption = tls
smtpServerPort = 587
smtpUser = ВАША ПОЧТА
Предварительная настройка почтового клиента
Разработка ядра Linux ведётся путём обмена патчами и проведением их обсуждений в почтовых списках рассылки. Существует ряд общепринятых норм ведения почтовой переписки.
Вся необходимая информация отражена на ресурсе: https://subspace.kernel.org/etiquette.html. Настоятельно рекомендуется с ней ознакомиться. Основные моменты:
- необходимо использовать только плоский текст (plain text), следует учитывать, что по умолчанию популярные почтовые клиенты используют HTML, а не плоский текст;
- строки текста должны быть длиной не более 75-85 символов;
- избегать top-posting — стиля ведения переписки, когда ответ идёт выше цитируемого текста.
Шаги по настройке различных почтовых клиентов к использованию плоского текста перечислены на ресурсе: https://useplaintext.email.
Выбор репозитория и версии ядра для подготовки исправления
При анализе ошибки рекомендуется определить затрагиваемые ей версии ядра Linux.
Если ошибка присутствует в основном репозитории ядра, то для дальнейшей работы, как правило, выбирается он. Однако стоит учитывать, что в некоторых подсистемах ядра идёт постоянная активная разработка, и их кодовая база может значительно отличаться от текущей в основном репозитории. В таких случаях для работы рекомендуется выбирать репозитории соответствующих подсистем из списка.
Hint. Если известен файл, который подлежит изменению, то информацию об актуальных репозиториях, в которых ведётся разработка затрагиваемой подсистемы, можно получить при помощи скрипта get_maintainer.pl с аргументом --scm. Например, если планируются изменения файла fs/notify/fsnotify.c, то требуемый репозиторий будет выдан командой:
./scripts/get_maintainer.pl --no-email --scm -f fs/notify/fsnotify.c
Если ошибки в основном репозитории нет, но она проявляется в одной из стабильных веток ядра, то для дальнейшей работы следуйте рекомендациям из соответствующего раздела настоящей инструкции.
Обновление репозитория до актуальной версии и создание новой ветки
Перед внесением изменений в код ядра необходимо склонировать или обновить соответствующий репозиторий ядра. Например, клонируется основной репозиторий ядра:
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
или, если репозиторий был уже склонирован ранее:
git pull
Hint. В основном репозитории ядра есть лишь одна ветка - master. Если используется какой-либо другой репозиторий, то предварительно может понадобиться перейти на ветку, на основе которой будет готовиться исправление. Например, для подготовки исправлений в подсистеме fsnotify может потребоваться совершить переход на ветку fsnotify репозитория jack/linux-fs.git:
git clone https://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git
git checkout fsnotify
Далее создаётся отдельная новая ветка для подготовки исправления (в рассматриваемом примере ветка названа по имени драйвера):
git checkout -b usb_gadget master
Внесение необходимых исправлений в код с соблюдением принятых правил форматирования
При внесении изменений в код необходимо соблюдать принятые в сообществе разработчиков ядра Linux правила форматирования кода:
Разбиение вносимых изменений по нескольким коммитам
Каждое логически самодостаточное изменение кода следует выделять в отдельный коммит (патч). Например, если проводимые изменения затрагивают исправление определённой ошибки и рефакторинг кода, имеет смысл разделить их по разным коммитам. Также, один коммит не должен стремиться решить одновременно сразу ряд разных проблем, пусть даже в одном и том же драйвере. Под каждую логически обособленную проблему следует готовить собственный коммит. Это в том числе является хорошим подспорьем для потенциального портирования патчей в стабильные ветки ядра, где хорошей практикой является точечное исправление актуальных для данной ветки ошибок.
Коммит исправлений
При осуществлении коммита рекомендуется использовать опцию --signoff, чтобы добавить строчку "Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>" (обязательно нужна):
git commit --signoff drivers/usb/gadget/inode.c
Некоторые важные правила оформления текста коммитов
- Придумать название патча (и, соответственно, коммита):
- название должно четко отражать суть внесенных изменений или исправленной ошибки;
- в названии нужен определённый префикс, идентифицирующий подсистему ядра, в которую вносится патч, который можно определить в логе изменений конкретного файла;
- префиксов может быть несколько, для большего уточнения;
- некоторые примеры названий:
ipv6: Fix tcp socket connection with DSCP.net: mpls: fix stale pointer if allocation fails during device rename.
- Необходимо описать проблему, которую решает данный патч. Если проблем несколько, то имеет смысл разделить их по разным патчам.
- Обязательно нужно показать, каким образом исправляемый баг может быть спровоцирован, какое поведение ядра приводит к данной ошибке.
- Рекомендуется вставить информацию, которая поможет разработчикам ядра составить представление об ошибке. Это может быть:
- выдержка из баг-репорта или другие данные из журнала ядра с трассой ошибки (backtrace);
- описание возможного поведения ядра, провоцирующего ошибку:
- в случае использования
Syzkallerи динамических детекторов багов (KASan,KMSan,Kmemleakи пр.) баг-репорт с трассой ядра предоставляется системой в удобном виде; - в случае использования статических анализаторов необходимо дополнительно посмотреть, может ли найденная ошибка произойти в реальной системе, и какое поведение ядра может к ней привести.
- в случае использования
- анализ производительности, задержек и т.п.
- После обоснования проблемы описать, что именно делает патч для ее исправления:
- описывать изменения рекомендуется в императивной форме, то есть "
make xyzzy do frotz" вместо "[This patch] makes xyzzy do frotz" или "[I] changed xyzzy to do frotz"; - если изменения тривиальные и текст в описании коммита не добавляет ничего нового к тому, что можно увидеть в самом патче, то это описание рекомендуется опустить.
- описывать изменения рекомендуется в императивной форме, то есть "
Стандартный шаблон патча, исправляющего ошибку в ядре, такой:
usb-gadget: Add module_put on error path in if_open()
If something happens (describe the path), then module_put is not
called (describe the problem).
Make if_open() do module_put on error path (describe the solution in imperative mood).
If the solution is trivial, this section can be omitted.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Если ошибка найдена не при помощи SVACE, то это необходимо отразить в последней строчке, например:
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Рекомендуется познакомиться с общими правилами оформления сообщений коммитов, которые применимы в том числе и для коммитов в ядро Linux.
Добавление тегов в тело коммита
Co-developed-by:
https://docs.kernel.org/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by
При совместной разработке патча в конце коммита желательно указать участвующих коллег (см. Теги и подписи коммитов):
Co-developed-by: Co-Author <coauthor@ispras.ru>
Signed-off-by: Co-Author <coauthor@ispras.ru>
Fixes:
Если известен коммит, в котором была внесена исправляемая ошибка, то в текст коммита (перед строчкой Signed-off-by: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>) рекомендуется вставить строчку с префиксом Fixes:, например:
Fixes: 193ab2a60700 ("usb: gadget: allow multiple gadgets to be built")
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
Hint. Правильный тег можно сгенерировать при помощи команды:
git show -s --pretty="format:Fixes: %h (\"%s\")" HASH-OF-COMMIT-THAT-INTRODUCED-BUG
Рекомедуется в обязательном порядке указывать тег Fixes:, даже если при этом приходится ссылаться на первоначальный коммит, который добавил соответствующий драйвер в ядро, то есть ошибка была в коде изначально. При этом надо учитывать, что тег Fixes: необходим только для коммитов, исправляющих какую-либо ошибку в ядре. При удалении лишнего кода и других видах рефакторинга он не нужен.
При поиске коммита, который внёс ошибку, важно иметь ввиду, что код мог быть затронут рефакторинг-коммитами, не повлиявшими на причину ошибки. Такие коммиты стоит пропускать при поиске. Также важно учитывать перемещения файла между директориями. Для этого бывает удобно воспользоваться опцией --follow, которая позволяет увидеть историю изменений в файле с учётом его перемещений внутри репозитория:
git log -p --follow drivers/usb/gadget/legacy/inode.c
Cc: stable@vger.kernel.org
Вероятно, исправляемая проблема присутствует в стабильных ветках. При подготовке коммита в основной репозиторий ядра необходимо проверить данный факт и, если коммит соответствует критериям переносимых в стабильные ветки патчей, отразить это в зоне подписей патча:
Cc: stable@vger.kernel.org
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
В таком случае коммит будет своевременно перенесён в стабильные ветки. Если коммит не удастся чисто применить к какой-либо поддерживаемой затрагиваемой стабильной ветке ядра, то автор патча будет об этом извещён.
Если точно известно, в какой момент исправляемый баг был привнесен в ядро, то это можно также отметить. Например, известно, что проблема присутствует во всех стабильных ветках, начиная с 5.10.y:
Cc: stable@vger.kernel.org # v5.10+
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
Порядок тегов
Теги Fixes: и Reported-by: (при наличии) рекомендуется ставить выше своей подписи Signed-off-by:. При этом пустых строк между тегами и подписями быть не должно.
Строка "Found by Linux Verification Center (linuxtesting.org)" относится к телу коммита, а не к тегам. Её уже необходимо отделить пустой строкой от тегов и подписей в конце описания коммита. С примерами оформления принятых патчей можно ознакомиться, выполнив команду:
git log --grep="Found by Linux Verification Center (linuxtesting.org)"
Выглядеть должно примерно так:
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Fixes: 193ab2a60700 ("usb: gadget: allow multiple gadgets to be built")
Cc: stable@vger.kernel.org
Signed-off-by: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>
Проверка компилируемости ядра
После внесения изменений в код следует запустить сборку ядра, по завершении которой убедиться, что изменённые файлы были скомпилированы:
make allmodconfig
make prepare
make modules_prepare
make M=drivers/xxx/ #или
make drivers/xxx/filename.o
Важно. Если изменения были разделены по нескольким коммитам, сборка ядра должна проходить успешно на каждом этапе инкрементального применения коммитов из серии.
Создание самого патча (серии патчей)
git format-patch master..usb_gadget
Git сделает заготовку письма из того коммита, который был сделан ранее.
Hint. Имя текущей ветки можно и опустить:
git format-patch master..
Если в ходе работы подготовлено несколько коммитов, объединённых некоторой общей идеей, их можно оформить в виде серии патчей для отправки по почте.
git format-patch --cover-letter master..usb_gadget
На основе имеющихся в тематической ветке коммитов git format-patch автоматически создаст и пронумерует ряд файлов-патчей.
Серии патчей принято снабжать сопроводительным письмом (имеющим номер 0), шаблон которого генерируется при указании опции --cover-letter. В данном письме можно указать общую информацию, позволяющую читателям-ревьюерам составить представление о том, на решение какой задачи направлены патчи серии.
Редактирование файла с патчем
Тема письма
Если всё сделано правильно, то git format-patch сам создаст такую тему письма:
[PATCH] prefix: short description
Идентификация адресатов
./scripts/get_maintainer.pl 0001-xxx.patch
Следует удалить из вывода скрипта то, что в круглых скобках, поставить первому адресату To:, а остальным Cc:. Дописать это в письмо. Также добавить в Cc: адрес списка рассылки: lvc-project@linuxtesting.org.
На этом этапе в текст письма можно внести произвольные изменения.
В результате получается примерно следующее:
From 9bbb34d71038fc7015917646a3365bca20cacb02 Mon Sep 17 00:00:00 2001
From: Alexey Khoroshilov <khoroshilov@ispras.ru>
To: Mauro Carvalho Chehab <mchehab@infradead.org>
Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: lvc-project@linuxtesting.org
Date: Thu, 26 May 2011 00:38:12 +0400
Subject: [PATCH] usb-gadget: unlock data->lock mutex on error path in ep_write()
ep_read() acquires data->lock mutex in get_ready_ep() and releases it on
all paths except for one: when usb_endpoint_xfer_isoc() failed.
Add mutex_unlock(&data->lock) at that path.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Fixes: 193ab2a60700 ("usb: gadget: allow multiple gadgets to be built")
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
---
drivers/usb/gadget/inode.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 3ed73f4..a01383f 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -386,8 +386,10 @@ ep_read (struct file *fd, char __user *buf, size_tlen, loff_t *ptr)
/* halt any endpoint by doing a "wrong direction" i/o call */
if (usb_endpoint_dir_in(&data->desc)) {
- if (usb_endpoint_xfer_isoc(&data->desc))
+ if (usb_endpoint_xfer_isoc(&data->desc)) {
+ mutex_unlock(&data->lock);
return -EINVAL;
+ }
DBG (data->dev, "%s halt\n", data->name);
spin_lock_irq (&data->dev->lock);
if (likely (data->ep != NULL))
-- 1.7.0.4
Указание целевого Git-дерева
Если патч сделан относительно основного репозитория ядра, то явно писать об этом не требуется.
Если же патч сделан относительно другого репозитория, то это как правило просят указать. В разных подсистемах ядра существуют свои устоявшиеся правила. Рекомендуется ознакомиться с тем, как оформляются патчи в затрагиваемую подсистему, посмотрев на историю сообщений в списке рассылки соответствующей подсистемы.
Например, для сетевой подсистемы существует два основных Git-дерева: net и net-next. Информация о них указывается в теме письма: [PATCH net] или [PATCH net-next].
Также информацию о Git-дереве можно написать в комментарии к патчу. Комментарий делается сразу после строки, содержащей ---. Эта строка следует за зоной подписей (Signed-off-by) патча. Текст в этой области будет виден тому, кто проводит ревью патча, но он не попадёт в итоговый коммит в репозитории. Фрагмент патча, содержащий комментарий, может выглядеть так:
Fixes: 193ab2a60700 ("usb: gadget: allow multiple gadgets to be built")
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
---
The patch is against <BRANCH-NAME> branch of <REPO-URL> repo.
drivers/usb/gadget/inode.c | 4 +++-
Проверка орфографии
Например, можно скопировать текст из 0001-xxx.patch в какой-нибудь редактор документов, в котором включены соответствующие проверки. Это позволит не нервировать разработчиков орфографическими ошибками, а также избежать повторной отправки патчей.
Обязательная проверка форматирования патча
./scripts/checkpatch.pl 0001-xxx.patch
Отправка
git send-email 0001-xxx.patch
При отправке серии следует указать несколько файлов-патчей сразу через пробел. Тогда Git скомпонует из них одну цепочку, и патчи будут ответами на первое (сопроводительное) письмо серии. Это делается командой:
git send-email 0001-xxx.patch 0002-yyy.patch 0003-zzz.patch
Перед финальной отправкой команда git send-email спрашивает, кому будут направлены письма и выводит окончательный список адресатов.
Важно. git send-email по умолчанию добавляет в копию адреса, имеющиеся в тексте патча (например, если указан тег Cc: stable@vger.kernel.org). При отправке патча для предварительного внутреннего обсуждения внешние адресаты могут быть нежелательными. В таких случаях их можно убрать, передав команде опцию --suppress-cc=all.
Если происходит отправка в международное сообщество и в теле патчей всё указано верно, то можно отправлять патчи (нажав Enter), ничего не вводя, и Git воспользуется значениями, указанными в теле патчей.
Подготовка второй версии патча
Если в первую версию патча разработчики ядра предложили внести какие-либо изменения, то необходимо подготовить вторую версию. Этот процесс практически не отличается от подготовки первой версии, но есть некоторые нюансы.
Генерация патча
При генерации второй и последующих версий можно использовать аргумент -v:
git format-patch -v 2 master..
тогда Git сгенерирует правильную тему письма, например:
Subject: [PATCH v2] clk: renesas: cpg-mssr: Fix use after free if cpg_mssr_common_init() failed
Редактирование файла с патчем
Как правило, имеет смысл оставить комментарий в письме, отражающий изменения между первой и второй версиями.
Комментарий делается сразу после строки, содержащей ---. Текст в этой области будет виден тому, кто проводит ревью патча, но он не попадёт в итоговый коммит в репозитории.
При этом в тексте рекомендуется указывать тех, кто высказал замечания и предложения.
Для третьей и последующих версий история изменений добавляется в порядке сверху вниз:
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
---
v3: Fix something else per Somebody request.
v2: Move cpg_mssr_priv assignment just before return 0; instead of
clearing it as Geert Uytterhoeven <geert@linux-m68k.org> suggested.
drivers/clk/renesas/renesas-cpg-mssr.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Важно. Чтобы текст был более читаемым, желательно отделить пустой строкой комментарий от последующих строк (в примере начинается с drivers/clk/renesas/renesas-cpg-mssr.c | 3 ++-).
В большинстве подсистем разработчики просят при отправке следующих версий патча атрибут In-Reply-To: не использовать. Таким образом каждая новая версия патча будет иметь собственное дерево обсуждений (mail thread). При необходимости можно указывать ссылки на предыдущие версии патча в комментариях к нему. Чтобы найти идентификатор письма, необходимо посмотреть сырую версию соответствующего письма и скопировать из неё значение атрибута Message-ID:.
From 768ff4d6d9ed69a23f9d37da06d8d4efa99eb585 Mon Sep 17 00:00:00 2001
From: Alexey Khoroshilov <khoroshilov@ispras.ru>
To: Geert Uytterhoeven <geert+renesas@glider.be>, Chris Brandt <chris.brandt@renesas.com>
Cc: Michael Turquette <mturquette@baylibre.com>, Stephen Boyd <sboyd@kernel.org>
Cc: linux-renesas-soc@vger.kernel.org, linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: lvc-project@linuxtesting.org
In-Reply-To: <CAMuHMdXehA_n78nLXCwBdKV=So=6Vzjt5eye7ZE4bS_BvHnzEA@mail.gmail.com>
Date: Fri, 23 Dec 2022 17:33:31 +0300
Subject: [PATCH v2] clk: renesas: cpg-mssr: Fix use after free if cpg_mssr_common_init() failed
If cpg_mssr_common_init() fails after assigning priv to global variable
cpg_mssr_priv, it deallocates priv, but cpg_mssr_priv keeps dangling
pointer that potentially can be used later.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Fixes: 1f7db7bbf031 ("clk: renesas: cpg-mssr: Add early clock support")
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
---
v2: Move cpg_mssr_priv assignment just before return 0; instead of
clearing it as Geert Uytterhoeven <geert@linux-m68k.org> suggested.
drivers/clk/renesas/renesas-cpg-mssr.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index 1a0cdf001b2f..5dce9779324d 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -989,7 +989,6 @@ static int __init cpg_mssr_common_init(struct device *dev,
goto out_err;
}
- cpg_mssr_priv = priv;
priv->num_core_clks = info->num_total_core_clks;
priv->num_mod_clks = info->num_hw_mod_clks;
priv->last_dt_core_clk = info->last_dt_core_clk;
@@ -1019,6 +1018,8 @@ static int __init cpg_mssr_common_init(struct device *dev,
if (error)
goto out_err;
+ cpg_mssr_priv = priv;
+
return 0;
out_err:
--
2.7.4
Сообщение об ошибке без патча
Описание проблемы и её последствий без предложения по исправлению готовится в виде письма и посылается тем же адресатам (см. ./scripts/get_maintainer.pl --bug -f path_to_file). Письмо должно содержать только плоский текст (plain text), не HTML.
В конце письма необходимо вставить строчку:
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Если команда, указанная выше, помимо адресов выдала URL Bugzilla или другой системы управления задачами, то можно продублировать сообщение заведением тикета в этой системе.
Перенос патчей в стабильную ветку ядра
Everything you ever wanted to know about Linux stable releases
Важно. В стабильные ветки осуществляется перенос патчей, удовлетворяющих следующим условиями:
- он исправляет реальный баг, нарушающий корректную работу системы и приводящий к неприятным последствиям. К подобным проблемам, например, относятся:
- kernel panic (падения ядра)
- повреждения памяти
- зависания
- проблемы безопасности
- ошибки сборки ядра
- исправления теоретических ошибок, для которых обоснованы предпосылки, могущие к ним привести
- он не должен быть 'тривиальным':
- исправления орфографии, пробельных символов
- удаление недостижимого кода
- он должен быть протестирован;
- он или эквивалентное исправление должны находиться в upstream-репозитории ядра
1. Подготовка репозитория
Клонируется репозиторий со стабильными версиями ядра:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
cd linux-stable
В первую очередь, необходимо убедиться, что интересующий патч ещё действительно не был портирован в требуемые стабильные ветки. В этом можно удостовериться, осуществив поиск по истории коммитов:
git log --grep="<НАИМЕНОВАНИЕ-КОММИТА>" origin/<НАИМЕНОВАНИЕ-СТАБИЛЬНОЙ-ВЕТКИ-ЯДРА>
либо
git log --grep="<UPSTREAM-ХЭШ-КОММИТА>" origin/<НАИМЕНОВАНИЕ-СТАБИЛЬНОЙ-ВЕТКИ-ЯДРА>
Hint. Также следует посмотреть наличие патча в очереди на включение в предстоящие стабильные релизы ядра, выпускаемые международным сообществом. Например, проверить наличие патча в очереди на включение в ветку linux-5.10.y можно таким образом:
git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git
cd stable-queue
grep -rn <UPSTREAM-ХЭШ-КОММИТА> queue-5.10
Важно. Помимо предыдущих шагов необходимо проверить, содержится ли портируемый патч в более свежих по сравнению с целевой стабильных ветках ядра. Если нет, то необходимо также перенести его в более свежие стабильные ветки (возможно, с некоторыми дополнительными адаптивными изменениями). Такое требование позволяет не допускать регрессий ядра, то есть ситуаций, когда в более старой стабильной версии определённая ошибка исправлена, а в более новой нет.
Например, рассмотрим случай, когда ветка master основного репозитория ядра имеет тег v6.2, а патч, который переносится, был внесён в основной репозиторий в версии v6.0. При этом список поддерживаемых стабильных веток таков: v5.10.y, v5.15.y, v6.1.y. Таким образом, патч уже есть в v6.1.y, но по какой-то причине в другие стабильные ветки его не перенесли. Если цель – перенести патч в ветку v5.10.y, то в таком случае его также необходимо перенести и в v5.15.y.
Для перехода на ветку, в которую переносится патч, следует выполнить команду:
git checkout linux-5.10.y
Далее создаётся отдельная ветка для подготовки исправления (в рассматриваемом примере ветка названа по имени драйвера):
git checkout -b ath9k linux-5.10.y
2. Внесение необходимых изменений в код
Необходимо определить хэш исправляющего коммита в основном репозитории ядра.
Первым шагом необходимо проверить, смогут ли изменения, внесённые коммитом, чисто примениться к стабильной ветке:
git cherry-pick HASH-OF-COMMIT-THAT-NEEDS-TO-BE-BACKPORTED
Далее необходимо действовать в зависимости от результата выполнения этой команды.
Если патч был успешно применен, то это можно увидеть с помощью
git log.Если во время применения изменений произошел конфликт (
CONFLICT), то необходимо вручную попытаться адаптировать изменения, внесённые коммитом, к коду стабильной ветки. Для этого можно открыть файл, в котором произошёл конфликт, найти конфликтное место и его разрешить. Важно оценить, не привнесут ли ручные изменения новых проблем и не нарушат ли логику кода. После этого необходимо закоммитить сделанные исправления:git add FILE_WITH_CONFLICT git cherry-pick --continueЕсли выяснится, что предварительно необходимо перенести ряд других коммитов, необходимо
произвести откат к изначальному состоянию:
git cherry-pick --abortосуществить перенос предварительных коммитов;
вернуться к переносу или адаптации целевого коммита.
Рекомендуется ознакомиться с документацией: man git-cherry-pick, либо web-документация git-cherry-pick.
После того, как все необходимые изменения внесены, необходимо проверить компилируемость ядра и отсутствие ошибок после исправления (см. выше раздел про внесение патчей в основную ветку ядра.
3. Создание патча (серии патчей)
git format-patch linux-5.10.y..ath9k
Эта команда сгенерирует заготовки писем из коммитов, имеющихся в тематической ветке, но отсутствующих в базовой ветке.
Hint. Имя текущей ветки можно опустить:
git format-patch linux-5.10.y..
Hint. При генерации второй и последующих версий используйте аргумент -v:
git format-patch -v 2 linux-5.10.y..
4. Редактирование файла с патчем
Строку From: Автор оригинального коммита следует поместить в само письмо (то есть поместить ниже заголовка письма и отделить одной строкой).
В заголовке следует поправить отправителя и дату:
From: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>
Date: <АКТУАЛЬНАЯ ДАТА>
В теме письма Subject указываются стабильные ветки, в которые необходимо перенести патч. Например, [PATCH 5.10]. Если при переносе патчей используется письмо с номером 0 (сопроводительное письмо для обоснования необходимости переноса), то все письма посылаются серией. Если переносимых патчей два и более, то они также заключаются в серию патчей. Например, если патчей два, то в первом письме указывается [PATCH 5.10 1/2], во втором соответственно [PATCH 5.10 2/2].
Hint. Если производится перенос сразу в несколько стабильных веток, то следует указать это в теге письма, перечислив ветки через /. Например, [PATCH 5.10/5.15/6.1].
Через строку после From: Автор оригинального коммита необходимо написать хэш коммита из основного репозитория в несокращённой форме:
commit HASH-OF-COMMIT-THAT-NEEDS-TO-BE-BACKPORTED upstream.
Необходимо обязательно подписать патч:
Signed-off-by: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>
Текст описания оригинального патча следует оставить как есть.
Если были внесены какие-либо адаптивные изменения, их стоит описать в квадратных скобках в зоне строк с подписями - после подписей изначальных авторов и прямо над своей подписью Signed-off-by. В начале комментария прописывается свой адрес электронной почты (или, для краткости, только своё имя) для идентификации автора адаптивных изменений. Если комментарий достаточно длинный, то его можно перенести по строкам.
Signed-off-by: ИЗНАЧАЛЬНЫЙ АВТОР
...
Signed-off-by: ИЗНАЧАЛЬНЫЙ АВТОР
[ ВАШЕ ИМЯ: Комментарий с описанием адаптивных изменений... ]
Signed-off-by: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>
Основными адресатами являются: stable@vger.kernel.org и Greg Kroah-Hartman <gregkh@linuxfoundation.org>.
Остальные адресаты, которым будут отправлены копии, идентифицируются с помощью скрипта scripts/get_maintainer.pl. В конце следует добавить:
Cc: lvc-project@linuxtesting.org
В результате получится примерно следующее:
From 63845fa0bdcd3ea538c4f1e5d298a3b0e343fe20 Mon Sep 17 00:00:00 2001
From: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>
To: stable@vger.kernel.org, Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jakub Kicinski <kuba@kernel.org>, Pietro Borrello <borrello@diag.uniroma1.it>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: lvc-project@linuxtesting.org
Date: Thu, 28 Nov 2024 10:35:09 -0800
Subject: [PATCH 5.4/5.10/5.15] net/tls: tls_is_tx_ready() checked list_entry
From: Pietro Borrello <borrello@diag.uniroma1.it>
commit ffe2a22562444720b05bdfeb999c03e810d84cbb upstream.
tls_is_tx_ready() checks that list_first_entry() does not return NULL.
This condition can never happen. For empty lists, list_first_entry()
returns the list_entry() of the head, which is a type confusion.
Use list_first_entry_or_null() which returns NULL in case of empty
lists.
Fixes: a42055e8d2c3 ("net/tls: Add support for async encryption of records for performance")
Signed-off-by: Pietro Borrello <borrello@diag.uniroma1.it>
Link: https://lore.kernel.org/r/20230128-list-entry-null-check-tls-v1-1-525bbfe6f0d0@diag.uniroma1.it
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ ВАШЕ ИМЯ: for old kernels tls_is_tx_ready() exists only as
is_tx_ready() in include/net/tls.h, fix the issue there
instead. ]
Signed-off-by: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>
---
include/net/tls.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/net/tls.h b/include/net/tls.h
index 7f220e03ebb2..e6836a5dfb6e 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -427,7 +427,7 @@ static inline bool is_tx_ready(struct tls_sw_context_tx *ctx)
{
struct tls_rec *rec;
- rec = list_first_entry(&ctx->tx_list, struct tls_rec, list);
+ rec = list_first_entry_or_null(&ctx->tx_list, struct tls_rec, list);
if (!rec)
return false;
--
2.25.1
5. Портирование исправлений для известных уязвимостей
Если портируемый в стабильные ветки ядра Linux коммит является исправлением для известной уязвимости с заведённым идентификатором CVE, данную информацию можно кратко отразить в отправляемом в списки рассылки ядра патче. Рекомендуемое место — комментарий к патчу, зона после ---. Добавленная пометка выглядит следующим образом:
Signed-off-by: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>
---
Backport fix for CVE-2024-50121
6. Сопроводительное письмо
Сопровождающим стабильных веток ядра Linux следует сообщить информацию о том, почему интересующие патчи подлежат переносу. В большинстве случаев необходимая информация уже заложена в текст исходного коммита в виде сообщений и трасс ошибок из журнала ядра, вложенных отчётов средств анализа кода, или же когда автор патча снабжает его тегом Fixes: или Cc: stable@vger.kernel.org. Тогда у сопровождающих стабильных веток обычно не возникает дополнительных вопросов по поводу необходимости переноса патчей.
При отсутствии в патчах явной информации об устранении какой-либо ошибки, мотивацию переноса в нужные стабильные ветки обычно описывают в комментарии к отправляемым патчам. Если текста становится достаточно много, а также, если имеется необходимость прикладывать полученные трассы ошибок и другие громоздкие данные, то лучше отражать эту информацию в отдельном сопроводительном письме, которое следует включать в отправляемую серию патчей под номером 0.
Примерный вид письма:
From: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>
To: stable@vger.kernel.org, Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Chris Lu <chris.lu@mediatek.com>, Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Cc: linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: lvc-project@linuxtesting.org
Date: Mon, 30 Dec 2024 13:51:58 +0300
Subject: [PATCH 6.12 0/4] Backport fixes for a crash in hci_unregister_dev()
On 6.12 there is a kernel crash during the release of btusb Mediatek
device.
list_del corruption, ffff8aae1f024000->next is LIST_POISON1 (dead000000000100)
------------[ cut here ]------------
kernel BUG at lib/list_debug.c:56!
Oops: invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
CPU: 3 UID: 0 PID: 3770 Comm: qemu-system-x86 Tainted: G W 6.12.5-200.fc41.x86_64 #1
RIP: 0010:__list_del_entry_valid_or_report.cold+0x5c/0x6f
Call Trace:
<TASK>
hci_unregister_dev+0x46/0x1f0 [bluetooth]
btusb_disconnect+0x67/0x170 [btusb]
usb_unbind_interface+0x95/0x2d0
device_release_driver_internal+0x19c/0x200
proc_ioctl+0x1be/0x230
usbdev_ioctl+0x6bd/0x1430
__x64_sys_ioctl+0x91/0xd0
do_syscall_64+0x82/0x160
entry_SYSCALL_64_after_hwframe+0x76/0x7e
The bug has been fixed "silently" in upstream with the following series
of 4 commits [1]:
ad0c6f603bb0 ("Bluetooth: btusb: mediatek: move Bluetooth power off command position")
cea1805f165c ("Bluetooth: btusb: mediatek: add callback function in btusb_disconnect")
489304e67087 ("Bluetooth: btusb: mediatek: add intf release flow when usb disconnect")
defc33b5541e ("Bluetooth: btusb: mediatek: change the conditions for ISO interface")
The offending commit is ceac1cb0259d ("Bluetooth: btusb: mediatek: add
ISO data transmission functions") and it is present in 6.12.y.
[1]: https://lore.kernel.org/linux-bluetooth/20240923084705.14123-1-chris.lu@mediatek.com/
7. Отправка патчей
Используется стандартная команда git send-email:
git send-email 0000-xxx.patch 0001-yyy.patch 0002-zzz.patch 0003-xyz.patch
Добавление патчей напрямую в стабильную ветку ядра
Иногда случаются ситуации, когда проблема была исправлена в основном репозитории ядра, однако перенос исправляющих коммитов в затрагиваемые стабильные ветки нецелесообразен в силу некоторых из причин:
- патчи не удовлетворяют требованиям переносимых в стабильные ветки патчей ;
- невозможность адаптировать патчи к стабильным веткам ввиду серьёзных изменений в кодовой базе, в смежных подсистемах или во внутреннем API ядра.
Важно. Если переносимый из основного репозитория ядра коммит не удаётся чисто применить к стабильной ветке, то это не означает автоматически, что его невозможно к ней адаптировать. В большинстве случаев достаточно подправить контекст патча, разрешив Git-конфликт, при этом суть исходного переносимого коммита сохраняется. Это считается адаптацией коммита к стабильной ветке и рассматривается в соответствующем разделе про перенос патчей в стабильные ветки.
Для целенаправленного включения изменений в необходимые стабильные ветки процесс их разработки в целом аналогичен стандартной подготовке патчей, но также следует:
- поставить строку "
No upstream commit exists for this patch." на место строки с определением коммита из основного репозитория ядра; - в теме письма указать теги стабильных веток, куда следует перенести патч, например,
[PATCH 5.10/5.15/6.1]; - в качестве адресатов письма указать
stable@vger.kernel.orgиGreg Kroah-Hartman <gregkh@linuxfoundation.org>, а также разработчиков затрагиваемых патчем подсистем ядра; - в описании патча обосновать необходимость его добавления в стабильные ветки ядра в отсутствие прямого аналога в основном репозитории ядра: описать существующую проблему и то, почему перенос исправляющего кода из основного репозитория является проблематичным.
Дальнейшие действия принимаются согласно результатам обсуждения патчей и исправляемой проблемы с международным сообществом разработчиков, сопровождающими стабильных веток ядра, и разработчиками затрагиваемых подсистем.
Пример патча для прямого добавления в стабильные ветки:
From 63845fa0bdcd3ea5385ef1e5d298a3b0e343fe20 Mon Sep 17 00:00:00 2001
From: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, stable@vger.kernel.org, Jens Axboe <axboe@kernel.dk>
Cc: linux-kernel@vger.kernel.org, lvc-project@linuxtesting.org
Subject: [PATCH 5.10/5.15] io_uring: avoid null-ptr-deref in io_arm_poll_handler
Date: Thu, 16 Mar 2023 21:56:16 +0300
No upstream commit exists for this commit.
The issue was introduced with backporting upstream commit c16bda37594f
("io_uring/poll: allow some retries for poll triggering spuriously").
Memory allocation can possibly fail causing invalid pointer be
dereferenced just before comparing it to NULL value.
Move the pointer check in proper place (upstream has the similar location
of the check). In case the request has REQ_F_POLLED flag up, apoll can't
be NULL so no need to check there.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Signed-off-by: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>
---
io_uring/io_uring.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 445afda927f4..fd799567fc23 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -5792,10 +5792,10 @@ static int io_arm_poll_handler(struct io_kiocb *req)
}
} else {
apoll = kmalloc(sizeof(*apoll), GFP_ATOMIC);
+ if (unlikely(!apoll))
+ return IO_APOLL_ABORTED;
apoll->poll.retries = APOLL_MAX_RETRY;
}
- if (unlikely(!apoll))
- return IO_APOLL_ABORTED;
apoll->double_poll = NULL;
req->apoll = apoll;
req->flags |= REQ_F_POLLED;
--
2.34.1