最近在Linux社区看到一个关于内核链表的讨论

原文讨论链接:

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

先用例子说明怎么使用内核链表

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;
}

代码输出

讨论的重点是?

如下图

因为Linux内核用的是C89标准,不能在for循环里面声明变量,所以导致tmp变量在使用之后的代码中还可以继续使用。

继续使用并不是大问题,大问题是因为继续使用导致了一个USB的BUG,当然,从代码的结构性上来说,我觉得也应该做好封装。

根据这个机制,有可能会被程序攻击到内核代码

具体可以查看这个网址

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

里面的描述和补丁说明差不多,都是因为没有遍历结束退出的原因。

修改后的部分补丁

+/* 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))

具体网址:

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

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

  1. To be or Not to be - Linux社区禁止一所美国大学提交代码事件

    点击上方"开源社"关注我们 | 作者:王永雷 | 编辑:刘雪洁 | 设计:杨敏 | 责编:沈于蓝 最近 Linux 社区发生的事件 Greg Kroah-Hartman 是一名 L ...

  2. 如何加入Linux社区开发(译)

    Kernel 开发过程指南 by Jonathan Corbet, corbet@lwn.net 原文地址:http://ldn.linuxfoundation.org/documentation/h ...

  3. 因贡献Linux社区被Linus关注,受公司10万期权奖励!酷派重回大众视野...

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 前言 12月1日,酷派公司官方宣布,为表彰其员工虎跃同学 ...

  4. Linux内核数据结构——链表

    目录 目录 简介 单向链表 双向链表 环形链表 Linux内核中的链表实现 offsetof container_of container_of 第一部分 container_of 第二部分 链表初始 ...

  5. Linux社区:对不起,道歉无用!

    是否还记得前几周一个荒诞的论文事件?因为几个学生为了写论文给Linux提交问题代码,导致整个明尼苏达大学从上到下被Linux封杀的惨案.(一项无聊的研究与论文,导致整个大学被Linux封杀!) 最近这 ...

  6. Kali Linux 2017中Scapy运行bug解决

    Kali Linux 2017中Scapy运行bug解决 Scapy是一款强大的网络数据包构建工具.在Kali Linux 2017中,当在scapy的命令行中,运行res.graph()生成图形时, ...

  7. linux内核中链表代码分析---list.h头文件分析(二)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...

  8. c linux time微秒_Linux基础知识(Linux系统、Linux中的链表)

    Linux系统简介 Linux系统的结构及特点 Linux系统的结构图如下图所示: 从上图可以看出,Linux是一个典型的宏内核(一体化内核)结构.硬件系统上面时硬件抽象层,在硬件抽象层上面时内核服务 ...

  9. 暗藏 15 年,Linux 惊曝 3 大 Bug 直取 root 权限!

    Linux 又曝出一个 15 年的"陈年 Bug",Linux 真的安全吗? 整理 | 郑丽媛 出品 | CSDN(ID:CSDNnews) 操作系统界,素来流传着一种说法:Lin ...

最新文章

  1. C语言中(字符串)输入scanf()、gets()、fgets()以及getchar()、getc()函数的联系与区别
  2. SparkSQL入门_1
  3. (转)无边框窗口实现拖垃效果
  4. node JS 微信开发
  5. sonar 报错日志分析(根据日志跟踪源码执行)
  6. 在Windows Media Center中收听超过100,000个广播电台
  7. 一日一技:在Ocelot网关中实现IdentityServer4密码模式(password)
  8. 玩转算法之面试 第八章-递归与回溯
  9. Python str / bytes / unicode 区别详解 - Python零基础入门教程
  10. Windows7下安装配置PostgreSQL10
  11. Selenium驱动Firefox浏览器
  12. 数学中的物理、几何概念与含义
  13. 慵懒中长大的人,只会挨生活留下的耳光
  14. Java咖啡馆(8)——大话面向对象(下)
  15. VOT目标路径可视化
  16. Spring Boot入门教程(四):配置文件
  17. JS将秒数换算成具体的天时分秒
  18. python中可选参数是什么意思_【IT专家】python 函数参数(必选参数、默认参数、可选参数、关键字参数)...
  19. 太赫兹成像系统行业调研报告 - 市场现状分析与发展前景预测
  20. NVIDIA DeepStream配置文件解析;摄像头源RTSP拉流源输入,RTSP推流输出

热门文章

  1. pug模板引擎(原jade)
  2. javascript函数,值得参考!
  3. Memcache应用场景
  4. 亲试白天使:华硕家用级无线路由RT-N11+
  5. 如何选择合适的Web安全网关?
  6. 如何安装pfbprophet
  7. Flask爱家租房--发布新房源(总结)
  8. mongo的php查询,使用PHP进行简单查询的mongo查询速度慢
  9. excel vba 调用webbrowser_VBA 公式与函数
  10. pycharm python 模板配置_windows下pycharm安装、创建文件、配置默认模板