Содержание

Сообщение об ошибке в виде патча

Ниже на примере рассматривается подготовка и отправка в kernel.org почтовой версии набора коммитов (патча) с исправлением ошибки, найденной в в коде драйвера при помощи Svace. Более полную информацию о разработке, подготовке и отправке патчей, в том числе для случаев изменений в коде драйверов и связанном с платформами конечных устройств, а также о требованиях к отправляемому коду, можно получить в документации на 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 = ВАША ПОЧТА

Обновление репозитория до самой свежей версии и создание новой ветки.

Перед внесением изменений в код ядра необходимо склонировать или обновить соответствующий репозиторий ядра и создать новую ветку для подготовки патча.

Как правило, клонируется или обновляется основной репозиторий ядра:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

или, если репозиторий был уже склонирован ранее

git pull

Создаем отдельную ветку для подготовки исправления (в рассматриваемом примере ветка названа по имени драйвера):

git checkout -b usb_gadget master

Вносим необходимые исправления в код, соблюдая принятые правила форматирования

При внесении изменений в код необходимо соблюдать принятые в сообществе разработчиков ядра Linux правила форматирования кода (см. Linux kernel coding style, root/Documentation/process/coding-style.rst).

Проверяем компилируемость ядра

После внесения изменений в код запускаем сборку ядра, по завершении которой необходимо проверить, что измененные файлы были скомпилированы:

make allmodconfig
make prepare
make modules_prepare
make M=drivers/xxx/  #или
make drivers/xxx/filename.o

Коммитим исправления

Делаем коммит. Используем --signoff, чтобы добавить строчку "Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>" (обязательно нужна).

git commit --signoff drivers/usb/gadget/inode.c

В теле коммита, для простоты, можно сразу писать багрепорт. Шаблон такой:

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.

Вместо usb-gadget нужен определённый идентифицирующий префикс; его можно посмотреть в логе изменений конкретного файла.

При совместной разработке патча в конце коммита желательно указать участвующих коллег:

Co-developed-by: Co-Author <coauthor@ispras.ru>
Signed-off-by: Co-Author <coauthor@ispras.ru>

Hint. Если известен коммит, в котором была внесена исправляемая ошибка, то в текст коммита (перед строчкой "Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>") рекомендуется вставить строчку с префиксом "Fixes:". Её можно сгенерировать при помощи команды:

git show -s --pretty="format:Fixes: %h (\"%s\")" HASH-OF-COMMIT-THAT-INTRODUCED-BUG

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

При поиске коммита, который внёс ошибку важно учитывать перемещения файла между директориями. Для этого бывает удобно воспользоваться опцией --follow, которая позволяет увидеть историю изменений в файле с учётом его перемещений внутри репозитория:

git log -p --follow drivers/usb/gadget/legacy/inode.c

Создаем сам патч

git format-patch master..usb_gadget

Гит сделает что-то типа письма из того коммита, который был сделан ранее.

Hint. Имя текущей ветки можно и опустить:

git format-patch master..

Hint. При генерации второй и последующих версий используйте аргумент -v:

git format-patch -v 2 master..

Проверяем его форматирование

./scripts/checkpatch.pl 0001-xxx.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
Cc: 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. The
patch adds 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

Внимательно проверяем орфографию

Например, можно скопировать текст из 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 спрашивает кому отправить письма и т.д. Если в теле патча всё указано верно, то можно смело нажимать Enter ничего не вводя и git воспользуется значениями указанными в теле патча.

Сообщение об ошибке без патча

Если вкратце, то готовим такое же письмо как и выше, и посылаем его тем же адресатам (см. ./scripts/get_maintainer.pl -f path_to_file), но только с описанием проблемы и её последствий, без предложения по исправлению. Посылаем из любого почтового клиента простым текстом (не HTML).

В конце письма необходимо вставить строчку:

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Перенос патчей в стабильную ветку ядра

1. Подготовка репозитория

Клонируем репозиторий со стабильными версиями ядра:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
cd linux-stable

Для перехода на ветку, в которою переносим патч, выполните команду:

git checkout linux-5.10.y

Создайте отдельную ветку для подготовки исправления (в рассматриваемом примере ветка названа по имени драйвера):

git checkout -b ath9k linux-5.10.y

2. Внесение необходимых изменений в код

Предполагается, что мы знаем хэш коммита, который необходимо перенести. Это обязательно должен быть хэш коммита в основном репозитории ядра https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git.

Первым шагом необходимо проверить смогут ли изменения, внесенные коммитом, чисто примениться к стабильной ветке:

git cherry-pick HASH-OF-COMMIT-THAT-NEEDS-TO-BE-BACKPORTED

Смотрим на вывод команды - существует несколько вариантов:

  • Патч чисто применен. Отлично! Успешный git cherry-pick автоматически применяет коммит к текущей ветке (что можно увидеть с помощью git log).
  • Во время применения изменений произошел конфликт (CONFLICT). Это значит, что нам нужно вручную попытаться адаптировать изменения, внесенные коммитом, к коду стабильной ветки. Открываем файл, в котором произошел конфликт, находим конфликтное место и, по возможности, разрешаем конфликт. Важно осознавать, не привнесут ли ручные изменения новых багов и не нарушат ли логику кода. После коммитим свои исправления:
    git add FILE_WITH_CONFLICT 
    git commit -m "Fixed conflict in [FILE_WITH_CONFLICT]"

Иногда бывает, что менее трудоемким и более безопасным путем будет откат к изначальному состоянию:

git cherry-pick --abort

Возможно выяснится, что предварительно необходимо перенести ряд других коммитов и после этого вернуться к переносу или адаптации целевого коммита.

Рекомендуется ознакомиться с документацией: man git-cherry-pick, либо https://git-scm.com/docs/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 1/1]*. При переносе патчей используется письмо с номером 0 (сопроводительное письмо для обоснования необходимости переноса), поэтому всегда посылаем серией. Если бэкпортируемых патчей два и более, то заключаем их в серию патчей. Например, если патчей два, то в первом письме указываем [PATCH 5.10 1/2], во втором соответственно [PATCH 5.10 2/2].

Через строку после From: Автор оригинального коммита пишем, не сокращая хэш коммита:

commit HASH-OF-COMMIT-THAT-NEEDS-TO-BE-BACKPORTED upstream.

Обязательно подписываем патч:

Signed-off-by: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА>

Текст описания оригинального патча оставляем как есть.

Если нами были внесены какие-либо адаптивные изменения, их стоит описать после текста оригинального патча, до строк с подписями.

Основными адресатами являются: stable@vger.kernel.org и Greg Kroah-Hartman <gregkh@linuxfoundation.org>.

Остальных адресатов, которым отправим копии, идентифицируем с помощью скрипта. В конце добавляем:

Cc: lvc-project@linuxtesting.org

В результате получится примерно следующее:

From 63845fa0bdcd3ea538c4f1e5d298a3b0e343fe20 Mon Sep 17 00:00:00 2001 
From: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА> 
To: stable@vger.kernel.org 
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> 
Cc: Kalle Valo <quic_kvalo@quicinc.com>
Cc: Alexey Khoroshilov <khoroshilov@ispras.ru>
Cc: lvc-project@linuxtesting.org 
Date: Fri, 12 Aug 2022 22:06:23 +0900 
Subject: [PATCH 5.10 1/1] ath9k_htc: fix NULL pointer dereference at ath9k_htc_rxep() 

From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>

commit b0ec7e55fce65f125bd1d7f02e2dc4de62abee34 upstream. 

syzbot is reporting lockdep warning followed by kernel panic at 
ath9k_htc_rxep() [1], for ath9k_htc_rxep() depends on ath9k_rx_init() 
being already completed. 

Since ath9k_htc_rxep() is set by ath9k_htc_connect_svc(WMI_BEACON_SVC) 
from ath9k_init_htc_services(), it is possible that ath9k_htc_rxep() is 
called via timer interrupt before ath9k_rx_init() from ath9k_init_device() 
is called. 

Since we can't call ath9k_init_device() before ath9k_init_htc_services(), 
let's hold ath9k_htc_rxep() no-op until ath9k_rx_init() completes. 

Link: https://syzkaller.appspot.com/bug?extid=4d2d56175b934b9a7bf9 [1] 
Reported-by: syzbot <syzbot+4d2d56175b934b9a7bf9@syzkaller.appspotmail.com>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Signed-off-by: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА> 
--- 
drivers/net/wireless/ath/ath9k/htc.h            | 1 + 
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 8 ++++++++ 
2 files changed, 9 insertions(+) 

diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h 
index 0a1634238e67..4f71e962279a 100644 
--- a/drivers/net/wireless/ath/ath9k/htc.h 
+++ b/drivers/net/wireless/ath/ath9k/htc.h 
@@ -281,6 +281,7 @@ struct ath9k_htc_rxbuf { 
struct ath9k_htc_rx { 
struct list_head rxbuf; 
spinlock_t rxbuflock; 
+ 	 bool initialized; 
}; 

#define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */ 
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c 
index 30ddf333e04d..592034ea4b68 100644 
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c 
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c 
@@ -1133,6 +1133,10 @@ void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, 
struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 
unsigned long flags; 

+ 	 /* Check if ath9k_rx_init() completed. */ 
+ 	 if (!data_race(priv->rx.initialized)) 
+ 		 goto err; 
+ 
spin_lock_irqsave(&priv->rx.rxbuflock, flags); 
list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 
if (!tmp_buf->in_process) { 
@@ -1188,6 +1192,10 @@ int ath9k_rx_init(struct ath9k_htc_priv *priv) 
list_add_tail(&rxbuf->list, &priv->rx.rxbuf); 
} 

+ 	 /* Allow ath9k_htc_rxep() to operate. */ 
+ 	 smp_wmb(); 
+ 	 priv->rx.initialized = true; 
+ 
return 0; 

err: 
--  
2.25.1

5. Сопроводительное письмо

Также следует включить письмо с кратким описанием того, почему мы бэкпортируем коммит.

Письмо нужно включить в отправляемую серию патчей под номером 0.

Примерный вид письма:

From: ВАШИ ИМЯ И ФАМИЛИЯ <ПОЧТА> 
To: stable@vger.kernel.org
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Cc: Kalle Valo <quic_kvalo@quicinc.com>
Cc: Alexey Khoroshilov <khoroshilov@ispras.ru>
Cc: lvc-project@linuxtesting.org 
Date: Mon, 1 Aug 2022 18:40:23 -0300 
Subject: [PATCH 5.10 0/1] ath9k_htc: fix NULL pointer dereference at ath9k_htc_rxep() 

Syzkaller reports NULL pointer dereference issue at ath9k_htc_rxep() 
in 5.10 stable releases. The problem has been fixed by the following 
patch which can be cleanly applied to the 5.10 branch. 

Found by Linux Verification Center (linuxtesting.org) with Syzkaller.

6. Отправка патчей

Как обычно используем команду git send-email:

git send-email 0000-xxx.patch 0001-yyy.patch 0002-zzz.patch 0003-xyz.patch