我正在尝试使用John Viega的C和C ++安全编程手册编译代码。以下代码段打开了一个可执行文件:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
int main(int argc, char *argv[ ]){
unsigned long entry;
unsigned char *buf;
struct stat sb;
int fd;
if (stat(argv[1], &sb)) {
fprintf(stderr, "Stat failed: %s\n", strerror(errno));
return 2;
}
if ((fd = open(argv[1], O_RDWR | O_EXCL)) < 0) {
fprintf(stderr, "Open failed: %s\n", strerror(errno));
return 3;
}
buf = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if ((int)buf < 0) {
fprintf(stderr, "Open failed: %s\n", strerror(errno));
close(fd);
return 4;
}
}
我在Ubuntu 15.10 x86_64(pr
)上用gcc 5.2.1编译了上面的代码。我已经从可执行文件(pr2
)创建了一个副本。
我不明白为什么以下电话有时会成功,有时候不会(获得Open failed: Success
,返回4
):
./pr pr2
答案 0 :(得分:3)
不要将buf
投射到int
。这是一个荒谬的行动。指针可能很容易在超过INT_MAX
的范围内,导致转换的整数为某个没有实际意义的负值。
相反,请检查mmap
的返回值是否为MAP_FAILED
((void*)-1
):
buf = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
close(fd);
return 4;
}
答案 1 :(得分:3)
您未正确检查mmap
的返回值。您需要专门检查MAP_FAILED
:
if (buf == MAP_FAILED) {
// note the change in error message
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
close(fd);
return 4;
}
另外,更改错误消息,以便您知道mmap
失败而不是open
。
答案 2 :(得分:3)
您未正确测试失败:
if ((int)buf < 0)
从man mmap
可以看出,你需要这样做:
if (buf == MAP_FAILED)
或者这个:
if (buf == (void*)-1)
否则,您正在转换一个有效的指向int的指针,该指针恰好是负数,但不是-1,如果不是,则将其视为错误。