Project

General

Profile

Wiki » History » Revision 13

Revision 12 (Alexey Khoroshilov, 06/03/2022 12:37 PM) → Revision 13/14 (Елена Кузьмина, 06/30/2022 04:49 PM)

{{toc}} 

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

 Инструкции по работе с интерфейсом разметки (SVACER) доступны в разделе "файлы":https://forge.ispras.ru/projects/lvc/files. 


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

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

 Для того, чтобы отфильтровать те предупреждения, которые относятся к выбранным подсистемам в режиме Review необходимо нажать на кнопку Filters->Basic... 
 и внизу в поле Files ввести список интересующих путей, например: 
 <pre> 
 security/selinux;net/ipv4 
 </pre> 
 При этом надо убедиться, что кнопка .* рядом с Files нажата. 

 По результатам анализа  
 # Необходимо выставить вердикт: 
 ** Confirmed -- ошибка, которую рекомендуется исправить 
 ** Won't fix -- истинное срабатывание, которое по тем или иным причинам исправлять нецелесообразно 
 ** False Positive - ложное срабатывание инструмента статического анализа 
 ** Unclear - требуется дополнительный анализ 
 # На вкладке Comment необходимо оставить комментарий, поясняющий вердикт. 
   Сейчас это обязательно хотя бы в самом коротком виде, т.к. это единственный способ увидеть автора проведённого исследования предупреждения. 

 h3. Типовые ситуации при разметке предупреждений в ядре 

 h4. Защитное программирование 

 Например, чекеры вида UNREACHABLE_CODE.ENUM сообщают о недостижимости кода в switch для ветки по умолчанию, в которой содержится та или иная отладочная печать, например: 

 <pre><code class="c"> 
   switch () { 
   case ENUM1: 
   ... 
   default: 
     dev_dbg(ice_pf_to_dev(pf), "Invalid container type %d\n", c_type); 
     return -EINVAL; 
   } 
 </code></pre> 

 Этот код, действительно, недостижим при нормальной работе ядра. Тем не менее, его как правило имеет смысл оставить, чтобы при возникновении нештатных ситуаций, управление пошло по более контролируемой логике и в журнале появилась информация об обнаружении нештатной ситуации. 

 В этом случае рекомендуется выставить вердикт @Won't fix@ и написать комментарий @Защитное программирование@. 

 h4. Недостижимый код, зависящий от конфигурации 

 Чекеры вида UNREACHABLE_CODE.* сообщают о недостижимости кода, в который, действительно, недостижим в конфигурации, которая подвержалась статическому анализу, но может быть достижим в другой конфигурации. В SVACE в будущем планируется поддержать выявление таких ситуаций и подавлять предупреждения. 

 До тех пор при разметке предупреждений рекомендуется выставить вердикт @Won't fix@ и написать комментарий @Код достижим в другой конфигурации@. 

 h4. FREE_OF_ARITHM: Deallocating memory through a pointer 'fl' obtained as a result of arithmetic operation  

 Срабатывают следущие чекеры: FREE_OF_ARITHM 

 Стандартный прием приведения члена структуры к содержащей его структуре. Используется для работы со списками, RCU, в различных видах циклов и пр. Т.к. для приведения используется макрос contaner_of, который производит арифметику, то использование такого приема вполне безопасно. 

 Пример: 
 <pre><code class="c"> 
 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); 
 } 
 </code></pre> 

 При разметке предупреждений рекомендуется выставить вердикт @Won't fix@ и написать комментарий @Использование container_of@. 

 h4. PROC_USE.VULNERABLE 

 Чаще всего возникает при использовании функции sprintf() - как правило, для нужд sysfs. Мейнтейнеры находят поведение 
 безопасным (sysfs использует буфер размером PAGE_SIZE) и чаще всего не принимают патчи, меняющие sprintf() на безопасные функции. 

 Пример: 
 <pre><code class="c"> 
 return sprintf(buf, "%d\n", udev->rx_lanes); 
 </code></pre> 

 Рекомендации по разметке: @Won't fix/Minor/Ignore@ . 

 h4. VARIABLE_IS_NOT_ARRAY.PROC 

 Возникает при передаче переменной как массива (указатель и длина) при вызове функций типа @of_property_read_*()@ или @copy_from_user()@. 

 Пример: 
 <pre><code class="c"> 
 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; 
 } 
 </code></pre> 

 Рекомендации по разметке: @False Positive@ Positive/Minor/Ignore@ . 


 h4. UNREACHABLE_CODE.DEFAULT 

 Возникает, например, при наличии метки @default@, на которую управление попасть не должно (все метки @case@ со значениями типа @enum@ перечислены явно). 

 Пример: 
 <pre><code class="c"> 
 /* entry requires deletion */ 
 case FSCACHE_CHECKAUX_OBSOLETE: 
	 goto stale; 
 default: 
	 BUG(); 

 </code></pre> 

 Рекомендации по разметке: @Won't fix/Minor/Ignore@ . 


 h4. SIGNED_TO_BIGGER_UNSIGNED 

 Возникает при присваивании выражения знакового типа переменной беззнакового типа большей разрядности (при этом происходит @sign extension@). Как правило, надо исправлять типы переменных. 

 Пример: 
 <pre><code class="c"> 
 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); 
 } 
 </code></pre> 

 Рекомендации по разметке: @Confirmed/Minor/Fix required@ . 

 

 h4. NO_CAST.INTEGER_OVERFLOW 

 Возникает при неявном преобразовании выражения к типу большей разрядности, при этом переполнения на практике обычно не происходит. 
 Пример: 
 <pre><code class="c"> 
 timeout_ns = udev->u1_params.sel * 3; 
 </code></pre> 

 Рекомендации по разметке: @False Positive@ Positive/Minor/Ignore@ . 

 h4. DEREF_AFTER_FREE: A pointer to memory pointer that has been deallocated, is dereferenced. 

 Срабатывают следущие чекеры: DEREF_AFTER_FREE 

 Стандартный прием безопасного удаления элемента списка при обходе. Для этого используется макрос  
 <pre><code class="c"> 
 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)) 
 </code></pre> 

 Пример: 
 <pre><code class="c"> 
 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); 
 } 
 </code></pre> 

 Совет по разметке: @False Positive@ 

 h2. Взаимодействие с международным сообществом 

 Для отправки патчей в основную ветку ядра следуйте следующим инструкциям: 
 [[How_to_send_patches_to_kernel|Отправка патчей в ядро]].