- Table of contents
- Статический анализ ядра
- Типовые ситуации при разметке предупреждений в ядре
- Защитное программирование
- Недостижимый код, зависящий от конфигурации
- FREE_OF_ARITHM: Deallocating memory through a pointer 'fl' obtained as a result of arithmetic operation
- PROC_USE.VULNERABLE
- VARIABLE_IS_NOT_ARRAY.PROC
- SIGNED_TO_BIGGER_UNSIGNED
- NO_CAST.INTEGER_OVERFLOW
- DEREF_AFTER_FREE: A pointer to memory pointer that has been deallocated, is dereferenced
- SIZEOF_POINTER_TYPE
- Типовые ситуации при разметке предупреждений в ядре
- Взаимодействие с международным сообществом
Статический анализ ядра¶
Инструкции по работе с интерфейсом разметки (SVACER) доступны в разделе файлы.
Для получения доступа к временному серверу для совместной работы над разметкой предупреждений SVACE пишите:
khoroshilov@ispras.ru
На этом сервере необходимо выбрать проект linux, ветка linux-5.10.y, в которой есть единственный снэпшот с результатами.
Для того, чтобы отфильтровать те предупреждения, которые относятся к выбранным подсистемам в режиме Review необходимо нажать на кнопку Filters->Basic...
и внизу в поле Files ввести список интересующих путей, например:
security/selinux;net/ipv4
При этом надо убедиться, что кнопка .* рядом с Files нажата. По результатам анализа
- Необходимо выставить вердикт:
Confirmed
-- ошибка, которую рекомендуется исправитьWon't fix
-- истинное срабатывание, которое по тем или иным причинам исправлять нецелесообразноFalse Positive
- ложное срабатывание инструмента статического анализаUnclear
- требуется дополнительный анализ
- На вкладке
Comment
необходимо оставить комментарий, поясняющий вердикт.
Типовые ситуации при разметке предупреждений в ядре¶
Защитное программирование¶
Как пример, детекторы вида UNREACHABLE_CODE.ENUM
или UNREACHABLE_CODE.DEFAULT
сообщают о недостижимости кода в switch
для ветки по умолчанию, в которой содержится та или иная отладочная печать. Например:
switch () {
case ENUM1:
...
default:
dev_dbg(ice_pf_to_dev(pf), "Invalid container type %d\n", c_type);
return -EINVAL;
}
Этот код, действительно, недостижим при нормальной работе ядра. Тем не менее, его, как правило, имеет смысл оставить, чтобы при возникновении нештатных ситуаций, управление пошло по более контролируемой логике, и в журнале появилась информация об обнаружении нештатной ситуации.
Аналогичная ситуация возникает в детекторах вида UNREACHABLE_CODE
при вызове функций, которые всегда возвращают 0
. Тем не менее, для многих из них можно предположить, что реализация со временем может измениться, и функция начнёт возвращать код ошибки. Поэтому обработку кода ошибки можно оставить на будущее.
В этом случае рекомендуется выставить вердикт Won't fix
и написать комментарий Защитное программирование
.
Недостижимый код, зависящий от конфигурации¶
Детекторы вида UNREACHABLE_CODE.*
сообщают о недостижимости кода, который, действительно, недостижим в конфигурации, которая подвергалась статическому анализу, но может быть достижим в другой конфигурации. В SVACE в будущем планируется поддержать выявление таких ситуаций и подавлять такие предупреждения.
До тех пор при разметке предупреждений рекомендуется выставить вердикт Won't fix
и написать комментарий Код достижим в другой конфигурации
.
FREE_OF_ARITHM: Deallocating memory through a pointer 'fl' obtained as a result of arithmetic operation
¶
Срабатывают следущие детекторы: FREE_OF_ARITHM
.
Стандартный прием приведения члена структуры к содержащей его структуре. Используется для работы со списками, RCU, в различных видах циклов и пр. Так как для приведения используется макрос container_of
, который производит арифметику, то использование такого приема вполне безопасно.
Пример:
struct ip6_flowlabel {
...
struct rcu_head rcu;
...
};
static void fl_free_rcu(struct rcu_head *head)
{
struct ip6_flowlabel *fl = container_of(head, struct ip6_flowlabel, rcu);
...
kfree(fl); // // <-- FREE_OF_ARITHM
}
static void fl_free(struct ip6_flowlabel *fl)
{
...
call_rcu(&fl->rcu, fl_free_rcu);
}
При разметке предупреждений рекомендуется выставить вердикт Won't fix
и написать комментарий Использование container_of
.
PROC_USE.VULNERABLE
¶
Чаще всего возникает при использовании функции sprintf()
, как правило, для нужд sysfs
. Мейнтейнеры находят поведение
безопасным (sysfs
использует буфер размером PAGE_SIZE
) и чаще всего не принимают патчи, меняющие sprintf()
на безопасные функции.
Пример:
return sprintf(buf, "%d\n", udev->rx_lanes);
Рекомендации по разметке: Won't fix/Minor/Ignore
.
VARIABLE_IS_NOT_ARRAY.PROC
¶
Возникает при передаче переменной как массива (указатель и длина) при вызове функций типа of_property_read_*()
или copy_from_user()
.
Пример:
static int mmc_of_get_func_num(struct device_node *node)
{
u32 reg;
int ret;
ret = of_property_read_u32(node, "reg", ®);
if (ret < 0)
return ret;
return reg;
}
Рекомендации по разметке: False Positive
.
SIGNED_TO_BIGGER_UNSIGNED
¶
Возникает при присваивании выражения знакового типа переменной беззнакового типа большей разрядности (при этом происходит sign extension
). Как правило, надо исправлять типы переменных.
Пример:
int typec_set_mode(struct typec_port *port, int mode)
{
struct typec_mux_state state = { };
state.mode = mode;
return typec_mux_set(port->mux, &state);
}
Рекомендации по разметке: Confirmed/Minor/Fix required
.
NO_CAST.INTEGER_OVERFLOW¶
Возникает при неявном преобразовании выражения к типу большей разрядности, при этом переполнения на практике обычно не происходит.
Пример:
timeout_ns = udev->u1_params.sel * 3;
Рекомендации по разметке: False Positive
.
DEREF_AFTER_FREE: A pointer to memory pointer that has been deallocated, is dereferenced
¶
Срабатывают следущие детекторы: DEREF_AFTER_FREE
.
Стандартный прием безопасного удаления элемента списка при обходе. Для этого используется макрос
list_for_each_entry_safe():
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member), \
n = list_next_entry(pos, member); \
!list_entry_is_head(pos, head, member); \
pos = n, n = list_next_entry(n, member))
Пример:
static void serio_free_event(struct serio_event *event)
{
module_put(event->owner);
kfree(event);
}
static void serio_remove_pending_events(void *object)
{
struct serio_event *event, *next;
unsigned long flags;
spin_lock_irqsave(&serio_event_lock, flags);
list_for_each_entry_safe(event, next, &serio_event_list, node) { // <-- DEREF_AFTER_FREE
if (event->object == object) {
list_del_init(&event->node); // Элемент удаляется из списка
serio_free_event(event); // Освобождается память, но next элемент отстается! В конце цикла происходит инициализация event = next;
}
}
spin_unlock_irqrestore(&serio_event_lock, flags);
}
Рекомендации по разметке: False Positive
.
SIZEOF_POINTER_TYPE
¶
Данный тип детектора предназначен для обнаружения несоответствий в конструкциях вида x = (T1*)alloc(sizeof(T2))
, когда тип передаваемый в оператор sizeof()
не соответствует по размеру типу, к которому приводится результирующий указатель. Если инструмент обнаруживает похожую конструкцию, которая используется не для выделения памяти, то предупреждение будет ошибочным.
Например при использовании макроса:
#define cmpxchg(ptr, ...) \
({ \
typeof(ptr) __ai_ptr = (ptr); \
instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
arch_cmpxchg(__ai_ptr, __VA_ARGS__); \
})
#endif
где arch_cmpxchg в свою очередь расширяется в:
#define __cmpxchg_wrapper(sfx, ptr, o, n) \
({ \
__typeof__(*(ptr)) __ret; \
__ret = (__typeof__(*(ptr))) \
__cmpxchg##sfx((ptr), (unsigned long)(o), \
(unsigned long)(n), sizeof(*(ptr))); \
__ret; \
})
Рекомендации по разметке: False Positive
.
Взаимодействие с международным сообществом¶
Для отправки патчей в основную ветку ядра следуйте следующим инструкциям:
Отправка патчей в ядро.
Updated by Alexey Khoroshilov over 2 years ago · 14 revisions