Project

General

Profile

Actions

Статический анализ ядра

Инструкции по работе с интерфейсом разметки (SVACER) доступны в разделе файлы.

Для получения доступа к временному серверу для совместной работы над разметкой предупреждений SVACE пишите:

На этом сервере необходимо выбрать проект linux, ветка linux-5.10.y, в которой есть единственный снэпшот с результатами.

Для того, чтобы отфильтровать те предупреждения, которые относятся к выбранным подсистемам в режиме Review необходимо нажать на кнопку Filters->Basic...
и внизу в поле Files ввести список интересующих путей, например:

security/selinux;net/ipv4

При этом надо убедиться, что кнопка .* рядом с Files нажата.

По результатам анализа
  1. Необходимо выставить вердикт:
    • Confirmed -- ошибка, которую рекомендуется исправить
    • Won't fix -- истинное срабатывание, которое по тем или иным причинам исправлять нецелесообразно
    • False Positive - ложное срабатывание инструмента статического анализа
    • Unclear - требуется дополнительный анализ
  2. На вкладке 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", &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 about 2 years ago · 14 revisions