日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux社区关于链表的bug讨论我们要看一下

發(fā)布時(shí)間:2023/12/20 linux 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux社区关于链表的bug讨论我们要看一下 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近在Linux社區(qū)看到一個(gè)關(guān)于內(nèi)核鏈表的討論

原文討論鏈接:

https://lwn.net/SubscriberLink/885941/01fdc39df2ecc25f/

先用例子說(shuō)明怎么使用內(nèi)核鏈表

list.h

/* SPDX-License-Identifier: GPL-2.0 */ #ifndef LIST_H #define?LIST_H/** Copied from include/linux/...*/#undef?offsetof #define?offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)/*** container_of - cast a member of a structure out to the containing structure* @ptr: the pointer to the member.* @type: the type of the container struct this is embedded in.* @member: the name of the member within the struct.**/ #define?container_of(ptr, type, member) ({ \const?typeof(?((type *)0)->member ) *__mptr = (ptr); \(type *)( (char?*)__mptr - offsetof(type,member) );})struct?list_head {struct?list_head *next, *prev; };#define?LIST_HEAD_INIT(name) { &(name), &(name) }#define?LIST_HEAD(name) \struct?list_head name = LIST_HEAD_INIT(name)/*** list_entry - get the struct for this entry* @ptr: the &struct list_head pointer.* @type: the type of the struct this is embedded in.* @member: the name of the list_head within the struct.*/ #define?list_entry(ptr, type, member) \container_of(ptr, type, member)/*** list_for_each_entry - iterate over list of given type* @pos: the type * to use as a loop cursor.* @head: the head for your list.* @member: the name of the list_head within the struct.*/ #define?list_for_each_entry(pos, head, member) \for?(pos = list_entry((head)->next, typeof(*pos), member); \&pos->member != (head); \pos = list_entry(pos->member.next, typeof(*pos), member))/*** list_for_each_entry_safe - iterate over list of given type safe against removal of list entry* @pos: the type * to use as a loop cursor.* @n: another type * to use as temporary storage* @head: the head for your list.* @member: the name of the list_head within the struct.*/ #define?list_for_each_entry_safe(pos, n, head, member) \for?(pos = list_entry((head)->next, typeof(*pos), member), \n = list_entry(pos->member.next, typeof(*pos), member); \&pos->member != (head); \pos = n, n = list_entry(n->member.next, typeof(*n), member))/*** list_empty - tests whether a list is empty* @head: the list to test.*/ static?inline int?list_empty(const?struct?list_head *head) {return?head->next == head; }/** Insert a new entry between two known consecutive entries.** This is only for internal list manipulation where we know* the prev/next entries already!*/ static?inline void?__list_add(struct?list_head *_new,struct?list_head *prev,struct?list_head *next) {next->prev = _new;_new->next = next;_new->prev = prev;prev->next = _new; }/*** list_add_tail - add a new entry* @new: new entry to be added* @head: list head to add it before** Insert a new entry before the specified head.* This is useful for implementing queues.*/ static?inline void?list_add_tail(struct?list_head *_new, struct?list_head *head) {__list_add(_new, head->prev, head); }/** Delete a list entry by making the prev/next entries* point to each other.** This is only for internal list manipulation where we know* the prev/next entries already!*/ static?inline void?__list_del(struct?list_head *prev, struct?list_head *next) {next->prev = prev;prev->next = next; }#define?LIST_POISON1 ((void *) 0x00100100) #define?LIST_POISON2 ((void *) 0x00200200) /*** list_del - deletes entry from list.* @entry: the element to delete from the list.* Note:?list_empty() on entry does not return true after this, the entry is* in an undefined state.*/ static?inline void?list_del(struct?list_head *entry) {__list_del(entry->prev, entry->next);entry->next = (struct?list_head*)LIST_POISON1;entry->prev = (struct?list_head*)LIST_POISON2; } #endif

test.c

#include?<stdio.h> #include?<stdlib.h> #include?<string.h> #include?"list.h"struct?stu_example?{struct?list_head?of_node;int?age; };static?LIST_HEAD(stu_list_head); #define?LIST_LEN 10int?main( ) {int?i = 0;/*初始化鏈表*/struct?stu_example?stu_list[LIST_LEN];struct?stu_example?*tmp?= NULL;for??(i=0; i < LIST_LEN; i++) {list_add_tail(&stu_list[i],&stu_list_head);stu_list[i].age = i + 20;}/*遍歷鏈表*/?list_for_each_entry(tmp, &stu_list_head, of_node) {printf("age=%d\n",tmp->age);}/*刪除鏈表*/list_del(&stu_list_head);printf("Hello,world\n");return?0; }

代碼輸出

討論的重點(diǎn)是?

如下圖

因?yàn)長(zhǎng)inux內(nèi)核用的是C89標(biāo)準(zhǔn),不能在for循環(huán)里面聲明變量,所以導(dǎo)致tmp變量在使用之后的代碼中還可以繼續(xù)使用。

繼續(xù)使用并不是大問(wèn)題,大問(wèn)題是因?yàn)槔^續(xù)使用導(dǎo)致了一個(gè)USB的BUG,當(dāng)然,從代碼的結(jié)構(gòu)性上來(lái)說(shuō),我覺(jué)得也應(yīng)該做好封裝。

根據(jù)這個(gè)機(jī)制,有可能會(huì)被程序攻擊到內(nèi)核代碼

具體可以查看這個(gè)網(wǎng)址

https://www.vusec.net/projects/kasper/

里面的描述和補(bǔ)丁說(shuō)明差不多,都是因?yàn)闆](méi)有遍歷結(jié)束退出的原因。

修改后的部分補(bǔ)丁

+/* Override the default implementation from linux/nospec.h. */ +#define select_nospec(cond, exptrue, expfalse) \ +({ \ + typeof(exptrue) _out?= (exptrue); \ + \ + asm?volatile("test %1, %1\n\t"??????????\ + "cmove %2, %0"????????????\ + : "+r"?(_out) \ + : "r"?(cond), "r"?(expfalse)); \ + _out; \ +}) +/* Prevent speculative execution past this barrier. */#define barrier_nospec() alternative("", "lfence", X86_FEATURE_LFENCE_RDTSC)diff --git a/include/linux/list.h b/include/linux/list.h index dd6c2041d09c..1a1b39fdd122 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -636,7?+636,8?@@ static?inline?void?list_splice_tail_init(struct?list_head *list,*/#define list_for_each_entry(pos, head, member) \for?(pos = list_first_entry(head, typeof(*pos), member); \ - !list_entry_is_head(pos, head, member); \ + ({ bool?_cond = !list_entry_is_head(pos, head, member); \ + pos = select_nospec(_cond, pos, NULL); _cond; }); \pos = list_next_entry(pos, member))

具體網(wǎng)址:

https://lwn.net/ml/linux-kernel/20220217184829.1991035-2-jakobkoschel@gmail.com/

總結(jié)

以上是生活随笔為你收集整理的Linux社区关于链表的bug讨论我们要看一下的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。