为切换用户运行的程序开启段错误时生成core的方法

当线上程序发生段错误时,内核会把会发送SIGSEGV信号给程序,使程序中断,如果系统开启产生core dump功能,则系统会该程序的内存写入到core文件。不过大多数Linux发布版中,core dump是默认不开启的,可以使用命令ulimit -c来查看core file的大小限制以及配置开启core dump。
如果程序调用了seteuid()/setegid()改变 了进程的有效用户或组,即使开启core dump,该程序在段错误后系统默认不会生成对应的core文件。

以下有三种方式可以这类进程设置在段错误时生成core

1.设置ulimit -c以及suid_dumpable文件

这种方式简单粗暴,但是只对该终端执行的程序生效

  • 设置core file大小限制为无限制

    ulimit -c unlimited  
    
  • 将/proc/sys/fs/suid_dumpable文件的内容改为1(一般默认是0):

    echo 1 > /proc/sys/fs/suid_dumpable
    
  • 重启程序
  • 如果想让修改永久生效,则需要在在配置文件加上ulimit -c unlimited,如 .bash_profile、/etc/profile或/etc/security/limits.conf

2.在程序中显示调用setrlimit以及prctl系统调用

setrlimit主要作用是设置core file限制为无限制
在执行setuid后显式prctl调用保证进程在段错误后也会生成core 文件

struct rlimit r;
r.rlim_cur=RLIM_INFINITY;
r.rlim_max=RLIM_INFINITY;
setrlimit (RLIMIT_CORE,&r);
......
setuid(user_id)
......
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)

3.通过gdb方式 attach进程后,对进程进行系统调用设置

这种方式只对运行的进程也生效,并且也不需要更改源程序代码,但不方便之处在于程序重新启动后无效

gdb -x core.cmd -p 进程号

core.cmd的内容

print "prctl(4, 1, 0, 0, 0)"
print prctl(4, 1, 0, 0, 0)
set $rlim = &{0ll, 0ll}
print "getrlimit(4, $rlim)"
print getrlimit(4, $rlim)
print *$rlim
set *$rlim[0] = -1
print "setrlimit(4, $rlim)"
print setrlimit(4, $rlim)
print "signal(6,(void (*) (int)) 0)"
print signal(6,(void (*) (int)) 0)

其实与第二点类似,都是通过系统调用方法来开启单个进程的core dump功能