“Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?” ― Brian Kernighan
用户态调试:下面的代码模拟了一个简化的密码认证过程,程序从标准输入读入长度为10的令牌,逐位与1异或后和存储的密码比较,如果和10位密码匹配则输出“Password OK”。你能发现其中的 Bug 吗👀 (不考虑运行环境的安全性)
/* auth.c */ #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #define PW_LEN 10 int main(int argc, const char *argv[]){ int fd; unsigned int i; char pw_buf[PW_LEN+1] = {'\0'}; char pw_buf2[PW_LEN+1] = {'\0'}; if(fd=open("./password",O_RDONLY,0400) < 0) return 1; if(!(read(fd,pw_buf,PW_LEN) > 0)){ close(fd); return 1; } printf("input password: \n"); fgets(pw_buf2, PW_LEN+1, stdin); for(i = 0; i < PW_LEN; i++) pw_buf2[i] ^= 1; if(!strncmp(pw_buf, pw_buf2, PW_LEN)) printf("Password OK\n"); else printf("Wrong !\n"); close(fd); return 0; }
内核态调试:在Linux 中,time()
系统调用的功能为返回一个元年时间,其在0.11内核中的实现代码如下,当 tloc
参数不为零,则将 tloc
指向的变量置为元年时间,否则直接返回元年时间,你能发现其实现的Bug吗👀 (如果你还没有学习到系统调用的机制,这一部分可以先略过,以后再来看内核的调试)
/* sys.c */ int sys_time(long * tloc) { int i; i = CURRENT_TIME; if (tloc) { verify_area(tloc,4); put_fs_long(i,(unsigned long *)tloc); } return i; } /* unistd.h */ #define _syscall0(type,name) \ type name(void) \ { \ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name)); \ if (__res >= 0) \ return (type) __res; \ errno = -__res; \ return -1; \ }
讲解视频:bilibili链接
参考资料: