我不是专业的C程序员。我在使用GDB调试程序时遇到问题。 (我试图解决的错误与我在这里询问的问题无关。)我的问题是,当我直接从shell运行二进制文件时程序运行正常,但是当我使用GDB运行它时程序崩溃。 / p>
以下是一些有用的程序信息:它是一个20多年历史的数据库软件,最初是为Solaris编写的(我认为),但是从移植到Linux,这是setuid(但不是root,感谢上帝。)
尝试打开文件进行写入时,程序在GDB中崩溃。使用GDB,我能够确定发生崩溃,因为以下系统调用失败:
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
为了澄清:path
是不应该存在的锁文件的路径。如果存在锁定文件,则程序在进入此系统调用之前会干净地关闭。
我不明白为什么这个系统调用会失败,因为1)该程序运行的用户对包含path
的目录具有rwx权限(我已通过检查存储在{的变量值验证了这一点{1}}),2)当我没有使用GDB进行调试时,程序成功打开文件进行写入。
我有什么理由不能
答案 0 :(得分:8)
关键是这一点:
...是setuid(但不是root,感谢上帝)。
当您在(任何)调试器下运行程序(使用任何stop-and-inspect / modify程序工具)时,内核会禁用setuid-ness,即使对于非root setuid也是如此。
如果你考虑一下这有点意义。考虑一个保持“高分”文件的游戏,并使用“setuid游戏”来做到这一点,用:
fd = open(GAME_SCORE_FILE, open_mode, file_mode);
score_data = read_scores(fd);
/* set breakpoint here or so */
if (check_for_new_high_score(current_score, score_data)) {
printf("congratulations, you've entered the High Scores records!\n");
save_scores(fd, score_data);
}
close(fd);
访问“高分”文件受文件权限保护:只有“游戏”用户才能写入。
但是,如果您在调试器下运行游戏,则可以在标记的行处设置断点,并将current_score数据设置为某个超高值,然后恢复该程序。
为了避免允许调试器破坏setuid程序的内部数据,内核只是在运行启用了调试工具的代码时禁用setuid-ness。如果您可以向用户su
(或sudo
或其他任何内容),表明您无论是否有任何调试都拥有权限,那么您可以以该用户身份运行gdb本身,以便程序以用户身份运行它“会有”设定为。