​更多内核安全、eBPF分析和实践文章,请关注博客和公众号:

CSDN博客:内核功守道
公众号: 内核功守道

知识背景

正如Linus Torvalds曾经说过的,大多数安全问题都是bug造成的,而bug又是软件开发过程的一部分,是软件就有bug。至于是安全还是非安全漏洞BUG,内核社区的做法就是尽可能多的测试,找出更多潜在漏洞这样近似于黑名单的做法。Greg Kroah-Hartman说:“一旦我们修复了它,我们就将它放到我们的栈分析规则中,以便于以后不再重新出现这个bug。”

如果没有2015年11月5号华盛顿邮报的一篇关于内核安全性的爆炸性专题报道《Net of insecurity the kernel of the argument》,内核社区应该仍会固守“A bug is bug”的理念(虽然如今也没有改变太多)。这篇文章狠狠的批评了内核社区对内核安全的态度,批评Linux “没有一个系统性的机制能在黑客之前发现和解决安全问题,或引入更新的防御技术”,“甚至Linux内核开发社区都没有一个首席安全官”等等。

我们都知道内核社区的传统就是相对安全性更侧重于性能和功能(这也是各大厂商最关注的部分),在需要牺牲性能来改善内核安全性时并不愿意折衷处理。其实从另一个角度来看,也不是内核社区不想合入有用的安全Patch,从LKML里面关于LSM或者其他Security相关的订阅人数、世界上独立的内核安全公司数量来看,除了一些内核安全机制有相应大公司或大社区维护(SELinux (NSA)、AppArmor (OpenSuSE/Ubuntu)、PaX / grsecurity (Spender)),以及PaX / grsecurity和内核社区的历史渊源,所以在全球范围内,真实有效的内核安全开发者是少之又少。

再加上内核代码提交走的流程比较繁琐,应用到具体内核版本上,又存在周期长以及版本适配的问题,如下图,所以导致内核在安全方面发展的速度明显慢于其他模块。

  • 一个Linux内核漏洞的修复从Upstream到发行版内核(生产环境)的链条过长,因为实际情况是没有人会真正意义上使用"Upstream"的内核;
  • 内核稳定分支以及发行版社区难以跟进每一个安全修复的分析,回归测试以及防御手段,甚至会出现漏掉的情况;
  • Linux内核社区坚持"Security through obscurity"哲学,这意味着内核社区从来不主动申请CVE漏洞编号,即使如此,2021年1月到8月,有CVE编号的内核漏洞超过110个
  • 漏洞军火商有自己的生态,他们并不关心是否有CVE的存在而只关注漏洞的成因以及漏洞利用的方法

随着智能化、数字化、云化的飞速发展,全球基于Linux系统的设备数以百亿计,而这些设备的安全保障主要取决于主线内核的安全性和健壮性。当某一内核LTS版本被发有漏洞,这样相关的机器都会面临被攻破利用的局面,损失难以估计。

                                    Critical & High CVE lifetimes

基于以上历史原因,内核自防护项目KSPP(Kernel Self Protection Project)应运而生。KSPP是由Linux基金会旗下的CII(基础架构联盟)管理,其吸纳了来自诸多大厂商(Google, RedHat,Intel,ARM等)的工程师进行联合工作,旨在缓解Linux内核自身安全缺陷,增强对内核漏洞的防御,主要参考了主要工作是参考PaX / grsecurity的实现来移植或者重新实现类似的功能然后推进到Linux内核主线。

第一个加固内核安全的Patch合并到了主线Linux 4.6上,自此,KSPP开始了自己的使命,不限于对以下几点,对内核安全性做了增强和优化:

  1. 缩小攻击面
  2. 限制内核的内存使用权限
  3. 只读数据和可执行代码不可写
  4. 函数指针和重要变量不可写
  5. User space和Kernel space内存分离
  6. 过滤无用系统调用
  7. 内存完整性
  8. KASLR

加固内核Config文件配置

从KSPP项目角度出发,以上所有内核安全方案的基础,都在于对内核Config文件的加固配置。下面从通用配置、GCC配置、命令行调试配置、ARM和X86的32位以及64位体系架构,这几个涵盖面最广的角度来分别讲解具体推荐配置,这些配置不仅用于加固内核安全,更可以用在内核稳定性和性能优化上,具体大家可以在实验环境下验证效果。

  1. 内核通用配置
  2. GCC编译器
  3. 命令行调试配置
  4. X86_32
  5. X86_64
  6. ARM
  7. ARM64

内核通用配置

#Debug开关,以便调试
CONFIG_BUG=y

#内核页表安全配置
CONFIG_DEBUG_KERNEL=y (4.11版本之前)
CONFIG_DEBUG_RODATA=y (4.11版本)
CONFIG_STRICT_KERNEL_RWX=y (4.11至最新版本)

#报告危险内存权限情况(注:不是所有平台都适用)
CONFIG_DEBUG_WX=y

#启用直接物理内存访问
CONFIG_STRICT_DEVMEM=y
CONFIG_IO_STRICT_DEVMEM=y

#SYN 防护
CONFIG_SYN_COOKIES=y

#多重加固验证常见的结构体异常
CONFIG_DEBUG_CREDENTIALS=y
CONFIG_DEBUG_NOTIFIERS=y
CONFIG_DEBUG_LIST=y
CONFIG_DEBUG_SG=y
CONFIG_BUG_ON_DATA_CORRUPTION=y
CONFIG_SCHED_STACK_END_CHECK=y

#使能seccomp BPF
CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y

#使能用户层Ptrace保护机制
CONFIG_SECURITY=y
CONFIG_SECURITY_YAMA=y

#使能usercopy边界检查,并禁止fallback,以获得完整的白名单执行CONFIG_HARDENED_USERCOPY=y
#CONFIG_HARDENED_USERCOPY_FALLBACK is not set
#CONFIG_HARDENED_USERCOPY_PAGESPAN is not set

#随机分配空闲列表,加固meatadata
CONFIG_SLAB_FREELIST_RANDOM=y
CONFIG_SLAB_FREELIST_HARDENED=y

#High-order页分配空闲列表
CONFIG_SHUFFLE_PAGE_ALLOCATOR=y

#使能Slub分配器检查
CONFIG_SLUB_DEBUG=y

#当Higher-level分配的内存释放后立即擦除,需要使能page_poison=1
CONFIG_PAGE_POISONING=y
CONFIG_PAGE_POISONING_NO_SANITY=y
CONFIG_PAGE_POISONING_ZERO=y

#使能内核栈保护
CONFIG_VMAP_STACK=y

#使能引用计数检查
CONFIG_REFCOUNT_FULL=y

#在构建时和运行时检查str*()和mem*()函数中可能溢出结构的内存拷贝
CONFIG_FORTIFY_SOURCE=y

#避免通过dmesg暴露内存地址
CONFIG_SECURITY_DMESG_RESTRICT=y

#使能系统调用入口上的随机内核栈偏移量计算(5.13版本后)
CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y

#使能内存溢出检测,类似于KASAN,但是开销几乎为0,可以全环境复现问题时是使用
CONFIG_KFENCE=y

#使能编译警告,便于调试 (5.15版本后)
CONFIG_WERROR=y

#强制IOMMU TLB失效,使设备永远无法访问过时的数据内容CONFIG_IOMMU_DEFAULT_DMA_STRICT=y

#在退出函数时,擦除所有调用者使用的寄存器痕迹,以防止ROP攻击CONFIG_ZERO_CALL_USED_REGS=y

#禁止物理内存直接写入
#CONFIG_ACPI_CUSTOM_METHOD is not set

#禁止基于brk的ASLR
#CONFIG_COMPAT_BRK is not set

#禁止内核内存直接写入
#CONFIG_DEVKMEM is not set

#禁止内核Kcore布局图
#CONFIG_PROC_KCORE is not set

#禁止VDSO ASLR
#CONFIG_COMPAT_VDSO is not set

#建议4.1版本之前关闭此选项,阻断堆内存攻击
#CONFIG_INET_DIAG is not set

#关闭传统PTY接口
#CONFIG_LEGACY_PTYS is not set

#使能SELinux运行时调整功能
#CONFIG_SECURITY_SELINUX_DISABLE is not set

#出现内核oops时,立即重启
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_TIMEOUT=-1

#关闭Root用户通过加载模块来修改内核内存
#CONFIG_MODULES is not set

#如果的确需要使用Root权限来操作内核,在使能CONFIG_MODULE=y后,建议打开如下配置:

CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_STRICT_MODULE_RWX=y
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=y
CONFIG_MODULE_SIG_ALL=y
CONFIG_MODULE_SIG_SHA512=y
CONFIG_MODULE_SIG_HASH=“sha512”
CONFIG_MODULE_SIG_KEY=“certs/signing_key.pem”

GCC

#使能GCC Plugins
CONFIG_GCC_PLUGINS=y

#使能-fstack-protector-strong (gcc 4.9+) 以全范围覆盖检测Stack Canary
#内核4.18版本之前,如下配置:
#CONFIG_CC_STACKPROTECTOR=y
#CONFIG_CC_STACKPROTECTOR_STRONG=y

#内核4.18版本之后,如下配置:
CONFIG_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR_STRONG=y

#使能在函数入口初始化所有堆栈变量,要求Clang和GCC 12版本以上CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL=y(GCC 12前)
CONFIG_INIT_STACK_ALL_ZERO=y

#系统启动时收集更多的entropy信息
CONFIG_GCC_PLUGIN_LATENT_ENTROPY=y

#强制所有结构体在传递给其他函数之前进行初始化
CONFIG_GCC_PLUGIN_STRUCTLEAK=y
CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL=y

#系统调用推出后擦除堆栈信息,减少堆栈内旧数据的生命周期CONFIG_GCC_PLUGIN_STACKLEAK=y

#随机化系统结构的布局。这可能会对性能产生巨大的影响,所以请谨慎使用或使用
#CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE=y
CONFIG_GCC_PLUGIN_RANDSTRUCT=y

X86_64

#禁止分配内存起始阶段的64K内地址
CONFIG_DEFAULT_MMAP_MIN_ADDR=65536

#禁止MSR寄存器写权限
#CONFIG_X86_MSR is not set

#使能随机分配内核和内存地址
CONFIG_RANDOMIZE_BASE=y
CONFIG_RANDOMIZE_MEMORY=y

#Libc不再需要用户空间中的固定位置映射
CONFIG_LEGACY_VSYSCALL_NONE=y

#使能内核页表隔离机制,以删除整个缓存计时侧通道类
CONFIG_PAGE_TABLE_ISOLATION=y

#缩小暴露的攻击面
#CONFIG_IA32_EMULATION is not set
#CONFIG_X86_X32 is not set
#CONFIG_MODIFY_LDT_SYSCALL is not set

#完全删除vsycall,以避免它成为任何类型的固定位置的ROP目标。
vsyscall=none

X86_32

#32-bit 内核上, 使能PAE

#CONFIG_M486 is not set
#CONFIG_HIGHMEM4G is not set
CONFIG_HIGHMEM64G=y
CONFIG_X86_PAE=y

#禁止分配内存起始阶段的64K内地址
CONFIG_DEFAULT_MMAP_MIN_ADDR=65536

#禁止MSR寄存器写权限
#CONFIG_X86_MSR is not set

#使能随机分配内核地址
CONFIG_RANDOMIZE_BASE=y

#使能内核页表隔离机制,以删除整个缓存计时侧通道类
CONFIG_PAGE_TABLE_ISOLATION=y

#禁止16位程序模拟和相关的LDT操作
#CONFIG_MODIFY_LDT_SYSCALL is not set

ARM64

#禁止分配内存起始阶段的32K内地址,不是64K的原因是因为ARM加载器需要使用这段地址
CONFIG_DEFAULT_MMAP_MIN_ADDR=32768

#使能随机分配内核地址
CONFIG_RANDOMIZE_BASE=y

#使能PAN模拟器.
CONFIG_ARM64_SW_TTBR0_PAN=y

#使能内核页表隔离机制,以删除整个缓存计时侧通道类
CONFIG_UNMAP_KERNEL_AT_EL0=y

Arm

#禁止分配内存起始阶段的32K内地址,不是64K的原因是因为ARM加载器需要使用这段地址
CONFIG_DEFAULT_MMAP_MIN_ADDR=32768

#最大化用户空间内存和ASLR
CONFIG_VMSPLIT_3G=y

#对于老的Qualcomm内核版本,如下配置
CONFIG_STRICT_MEMORY_RWX=y

#使能PXN/PAN模拟器
CONFIG_CPU_SW_DOMAIN_PAN=y

#禁止陈旧接口,缩减攻击面
#CONFIG_OABI_COMPAT is not set

命令行调试配置

#擦除Slab和页分配的内存(5.3版本后)
init_on_alloc=1
init_on_free=1

#使能系统调用入口上的随机内核栈偏移量计算(5.13版本后)
randomize_kstack_offset=on

#禁用slab合并,使得许多堆溢出攻击更加困难
slab_nomerge

#始终启用内核页表隔离,即使CPU声称它对Meltdown是安全的
pti=on

#预防L1TF
nosmt

#使能SLUB redzoning和健康检查
slub_debug=ZF

#使能Slab/Slub分配器的内存溢出检测功能,需在内核5.3后版本上,使能CONFIG_SLUB_DEBUG=y
slub_debug=P

#使能伙伴系统分配器的内存溢出检测功能,需要在内核5.3版本上,使能CONFIG_PAGE_POISONING=y
page_poison=1

#强制IOMMU TLB失效,使设备永远无法访问过时的数据内容
iommu.passthrough=0 iommu.strict=1

结论

内核安全问题,牵一发而动全身,尤其是在配置方面,所以如果有的时候在稳定性或者性能优化上卡住,不妨从内核配置的角度,结合上文的详细说明,换个角度来分析问题,可能会有更好的收获。这篇文章着重从内核安全配置的角度来分析了KSPP,在LSM机制、漏洞利用分析、栈溢出攻击等方面会有真实利用场景,后续会逐步更新相关文章。

万字长文---手把手教你加固内核安全配置相关推荐

  1. 万字长文手把手教你搭建家庭私有云

    万字长文手把手教你搭建家庭私有云 随着互联网的普及,现在的云产品越来越多,像生活中常用的网盘.视频软件.音乐软件.电子书.云笔记等等越来越离不开我们的生活,但是想必大家也受够了"非会员&qu ...

  2. yili邮箱服务器配置,手把手教 个人SMTP服务器的配置 -电脑资料

    导读:,因此我们要手工添加,管理员身份登录Windows Server 2003 系统.依次进入"控制面板→添加或删除程序→添加/删除Windows组件",在弹出的"Wi ...

  3. 手把手教你在C++中配置Gurobi

    手把手教你在C++中配置Gurobi C++中配置Gurobi:视频教程 C++中配置Gurobi 新建C++项目 配置C/C++外部包含目录 配置链接器的附加目录库和附加依赖项 案例测试 参考资料 ...

  4. Linux疑难杂症解决方案100篇(十五)-万字长文带你深入Linux 内核学习:环境搭建和内核编译

    一.linux内核学习之一:环境搭建--安装Debian7.3 本系列文章假设读者已对linux有一定的了解,其实学习linux内核不需要有很深的关于linux的知识,只需要了解以下内容:linux基 ...

  5. 手把手教你Linux内核编译(三天吐血经历)

    一.实验前的准备: Vmware + ubuntu10.10 (32位)+ linux-2.6.32.71.tar.xz 安装虚拟机教程:http://jingyan.baidu.com/articl ...

  6. 精品:千字长文手把手教你使用字节跳动的火山引擎veImageX

    经过我的研究发现,这个方法竟然比较通用,于是转载群发之 veImageX 是字节跳动旗下的火山引擎推出的图像.文档等各类素材上传.托管.智能处理和 CDN 分发一站式解决方案,WPJAM Basic ...

  7. 万字长文手把手带你部署 Train版OpenStack

    Openstack-Train 1.环境准备 1.1.主机配置 hostname system host resource IP controller centos7 4G内存.4核 192.168. ...

  8. pycharm配置python解释器_Python大佬手把手教你进行Pycharm活动模板配置

    新的一年,祝大家身体健康,万事如意! /1 前言/ 嘿,各位小伙伴大家好,今天Python进阶者又要带来什么奇技淫巧呢?期待一下吧~~ 今天给小火煲们带来的干货是Pycharm活动模板配置,来听我细细 ...

  9. centos daemonize_手把手教你在centos上配置Django项目(超详细步骤)

    前言 关于Django的部署,本人也踩了很多坑,这篇文章一步一步教你怎么进行部署,只需要你按照我的步骤来就OK了!这里我们使用的服务器是一个全新的服务器,没有安装任何东西. 基础环境搭建步骤 ★ 注意 ...

最新文章

  1. 消控中心人员配置_物业公司(项目)各岗位员工配置人数及标准(供参考)
  2. 指定ASP .NET Core Web应用端口
  3. 第十六届无线节能信标灯规格说明
  4. Customer Success Case Study Library
  5. 苹果手机安装应用后无法上网问题的解决方法
  6. 手工编译Android程序
  7. EOS 智能合约源代码解读 (5)class contract
  8. 苹果 “Find My” 功能中的漏洞可暴露用户的位置信息
  9. arcface的前世今生
  10. 共探人工智能新发展,AICON 2022即将重磅开启
  11. 【Linux】目录权限和默认权限
  12. 51单片机LED数码管
  13. VSS2005局域网配置
  14. 基于R语言进行热浪指数的计算_HWMid
  15. 第十三届蓝桥杯EDA赛项国奖心得分享
  16. K_A08_009 基于 STM32等单片机驱动TB6612模块按键控制直流电机正反转加减速启停
  17. 类型多样的CAD软件插件素材,速来收藏
  18. Linux配置证书登录
  19. Redis 使用指南:深度解析 info 命令
  20. 前端代码覆盖率遇到问题及总结(一)

热门文章

  1. BigDecimal如何保留小数位
  2. [激光原理与应用-63]:激光器-光学-探测光、泵浦光和种子光三种光的区别
  3. CAM图纸管理系统cad雕刻裁切系统
  4. 在Isight软件里如何调用matlab子程序?
  5. 从零开始搭建自己的云服务器
  6. 关于直播电商平台的一些数据
  7. FCM推送 push
  8. 小学六年级上册计算机教学总结,小学六年级语文教学工作总结
  9. 解决 plt.savefig() 生成空白图片的问题
  10. html页面统计在线人数,统计在线人数couter