为什么在Docker里使用gdb调试器会报错
背景
前几天一个小伙伴发邮件问我,他在docker内部使用gdb调试时刻遇到了gdb如下报错信息ptrace:Operation not permitted
当时我的答复是在docker create或者docker run时刻开启万精油--privileged参数。小伙伴的问题就此解决了。
但是事实并非如此简单
Docker上涉及到gdb调试权限的特性
capabilities
Docker借用了linux对进程设置capabilities,而其子进程继承父进程capabilites特性来完成对容器capacities的控制。Docker create和docker run参数中有下面两个参数可以对容器默认的capabilites进行修改:--cap-add //添加某个capabilites属性 --cap-del //剔除某个默认的capabilites属性
cap-add和cap-del可以设置的参数可以通过下面链接查询到:
https://docs.docker.com/engine/reference/commandline/run/
- Docker 将gdb调试需要SYS_PTRACE属性被禁止掉了,所以gdb在调试的时候会显示ptrace被禁止。所以想在docker内部调试gdb解决办法就是create和run的时候带上--cap-add sys_ptrace*
例如:
docker run -it --cap-add sys_ptrace centos:latest /bin/bash root@7f5a2130e975>cd /home/ root@7fa2130e975> vi test.c \#include <stdio.h> int main(){ int i = 0; printf(“Testing begin\n”); While(1){ printf(“Loop cnt:%d\n”,i++); sleep(10); } } root@7fa2130975>gcc -c -g -o test.o test.c root@7fa2130975>gcc -o test -g test.o root@7fa2130975>./test& [1] 18 root@7fa2130975>gdb attach 18 //ok可以调试了
但是这并不是问题的全部,对于上述测试程序,如果执行下面命令gdb又有告警出来
root@7fa2130975>gdb ./test (gdb) r Warning:Error disabling address space randomization:Operation not permitted
虽然依然可以调试,但是我们还是需要搞清楚上述告警的意思。地址随机化是linux一项安全特性,它允许内核进程启动每次加载库的时候都在随机化的分布在进程虚拟内存地址空间上(早期固定的库要加载到固定地方,如果固定地方被占用才加载到别地方。会造成多次加载程序,其库地址都不变。如此有安全隐患)。在gdb调试中gdb默认需要关闭linux的地址随机化功能,可以通过gdb 命令set disable-randomization off关闭。如果在地址随机化下调试同一段程序,多次run时候可以看到它的运行地址和函数地址不一致,这没有什么太大的问题。问题可以结束了
关于gdb 设置地址随机化开关详情见下面链接:
http://visualgdb.com/gdbreference/commands/set_disable-randomization
当然上述告警其实也可以不通过gdb设置来完成,可以通过下面介绍的Docker参数可以达成。
seccomp
Docker默认情况下为每个容器都设置了一个默认的seccom profile。一般情况下无需修改。但是docker依然支持
docker create或者docker run时候通过--security-opt seccomp=xxx参数来设置docker容器的seccomp策略。
xxx可以是一个json格式文件,里面定义了docker容器每个具体的seccomp规则。也可以是字符unconfined表示关闭默认的docker seccomp 规则。
可以通过下面命令彻底关闭docker默认seccomp引入的任何限制docker run -it --security-opt seccomp=unconfined centos:lastes
在运行上述gdb 调试命令run一个进程,告警信息终于彻底消失了。
Docker设置的seccomp 默认profile规则可以通过如下链接查询到:
https://docs.docker.com/engine/security/seccomp/
本文就不再做详细展开了。
Docker背后的实现技术
Docker实现seccomp控制
从Linux 2.6.23开始支持这种特性对进程能够使用的系统调用进行控制,如此可以进行一些安全性策略。sandbox就是依赖于此技术。docker梳理了Linux的系统调用,从300+个系统调用中屏蔽掉了44个系统调用,但是又最大程度的不影响正常的应用使用系统。
- 在Docker engine上有一个叫seccomp模块提供了为docker提供默认seccomp规则(GetDefaultProfile()函数),而我们在命令行配置的seccomp属性会覆盖默认的seccomp规则(在setSeccomp()函数里)。最终规则在engine内部创建runc spec时刻函数createSpec生产。将seccomp传递到oci runtime spec的spec.linux.seccomp字段里。
- 而runc通过seccomp库的InitSeccomp()函数,在Init一个容器时刻和exec触发的将一个进程setns到容器内部时刻调用此函数 将seccomp属性设置到容器的init进程或者exec进程里。
- Linux进程属性里有seccomp属性,此属性也会父子继承,通过/proc/$pid/status里可以看到进程的seccomp属性。
Docker实现capabilities
从Linux 2.1开始支持的特性,将超级用户的权限划分为多个组,每个进程都有一个capabilities属性,子进程从自己的父进程中基础capacities。这个特性和sudo不一样,因为sudo控制粒度太粗;而capabilities控制粒度很精细。linux有一系列的调用可以设置、查看,清除和比较进程的capabilities。可以通过:man cap_set_flag
来查看这一系列的系统调用。而具体进程的capacities可以通过/proc/$pid/status中:
Capxxx字段看到,本文就不再展开。感兴趣的朋友可以参考
https://www.cnblogs.com/iamfy/archive/2012/09/20/2694977.html
- 在oci runtime spec里规定了spec.Process.Capabilities属性。runc中finializeNamespace()根据此属性对进程的capabilities进行设置。此函数会在init容器和exec加一个进程到容器时刻调用。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
前后端分离SpringBoot项目,Docker部署后端Jar包
前后端分离SpringBoot项目,Docker部署后端Jar包 Docker制作后端项目镜像 第一步 下载Docker 使用的是CentOS7,内核低于3.0好像不行,查看内核命令 uname -r yum install docker 1 常用docker命令 启动docker:systemctl start docker 停止docker:systemctl stop docker 重启docker:systemctl restart docker 查看docker状态:systemctl status docker 开机启动:systemctl enable docker 查看镜像: docker images 搜索镜像:docker search 镜像名称 下载镜像:docker pull 镜像名称 删除镜像:docker rmi 删除容器:docker rm 查看容器:docker ps 查看停止的容器:docker ps -a 查看最后一次运行的容器:docker pa -l … 第二步 创建文件夹 mkdir docker 然后cd docker/ 创建Dockerfi...
- 下一篇
java学习路线图(2018年最新版)
java学习路线图(2018年最新版) 最近有些网友问我如何自学 Java 后端,还有些是想从别的方向想转过来,但都不太了解 Java 后端究竟需要学什么,究竟要从哪里学起,哪些是主流的 Java 后端技术等等,导致想学,但又很迷茫,不知从何下手。我就以过来人的经历,写在这篇博客里,不一定都对,但都是我根据自己的经历总结出来的,供你们的参考。 Java 基础 Java 是一门纯粹的面向对象的编程语言,所以除了基础语法之外,必须得弄懂它的 oop 特性:封装、继承、多态。此外还有泛型、反射的特性,很多框架的技术都依赖它,比如 Spring 核心的 Ioc 和 AOP,都用到了反射,而且 Java 自身的动态代理也是利用反射实现的。此外还有 Java 一些标准库也是非常常见,比如集合、I/O、并发,几乎在 Web 开发中无处不在,也是面试经常会被问到的,所以在自学 Java 后端之前,不妨先打好这些基础,另外还有 Java8 的一些新特性,也要重点关注,比如 Lambda 表达式、集合的 Stream 流操作、全新的 Date API 等等,关于新特性,我也写了几篇关于这方面的博客,请自行...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS6,CentOS7官方镜像安装Oracle11G
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2全家桶,快速入门学习开发网站教程
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8