[故障注入]基于LD_PRELOAD对open进行故障注入

上一篇文章讲解了环境变量LD_PRELOAD在故障注入中的用法。
下面进行一个实战,对open进行故障注入

被注入程序

velscode@ubuntu:~/code$ cat open.c 
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
	int fd = open("./file1", O_CREAT | O_RDWR);
	printf("fd = %d, errno = %d(%s)\n", fd, errno, strerror(errno));	
}

该程序试图创建并打开一个文件,在正常情况下,它似乎总是成功

velscode@ubuntu:~/code$ gcc open.c -o open
velscode@ubuntu:~/code$ ./open 
fd = 3, errno = 0(Success)
velscode@ubuntu:~/code$ ./open 
fd = 3, errno = 0(Success)
velscode@ubuntu:~/code$ ./open 
fd = 3, errno = 0(Success)
velscode@ubuntu:~/code$ ./open 
fd = 3, errno = 0(Success)
velscode@ubuntu:~/code$ ./open 
fd = 3, errno = 0(Success)

故障注入程序

velscode@ubuntu:~/code$ cat hack.c
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>

int open(const char *pathname, int flags)
{
	srand((unsigned int)time(NULL));
	if (random() % 10 < 5) {
		printf("Hack open!\n");
		errno = 2; // No Such file
		return -1;
	} else {
		printf("Not Hack open\n");
		return openat(-100, pathname, flags, 0);
	}
	
	return 0;
}

一半概率返回-1(同时设置错误码为-2),一半概率正常放行open

编译 & 执行结果

velscode@ubuntu:~/code$ gcc -shared -o hack.so hack.c -fPIC
velscode@ubuntu:~/code$ export LD_PRELOAD=./hack.so

velscode@ubuntu:~/code$ ./open
Not Hack open
fd = 3, errno = 0(Success)
velscode@ubuntu:~/code$ ./open
Not Hack open
fd = 3, errno = 0(Success)
velscode@ubuntu:~/code$ ./open
Hack open!
fd = -1, errno = 2(No such file or directory)
velscode@ubuntu:~/code$ ./open
Hack open!
fd = -1, errno = 2(No such file or directory)
velscode@ubuntu:~/code$ ./open
Not Hack open
fd = 3, errno = 0(Success)

可以看到,目标程序概率性成功,概率性open调用失败

补充

有人会问,拦截并返回 错误码的场景很好写,但是正常放行部分的代码该怎么写呢?因为此时你已经无法正常调用open了,为什么上述代码里可以用openat代替呢?

这个可以看下glibc的源代码

先找下open的入口

velscode@ubuntu:~/code/glibc$ grep " open(" -rn

intl/loadmsgcat.c:448:# define open(name, flags)	__open_nocancel (name, flags)

这里可以看到,用宏做了一层转换,实际上是调用__open_nocancel

那我们再搜这个,看看里面是怎么实现的

int
__open_nocancel (const char *file, int oflag, ...)
{
  int mode = 0;

  if (__OPEN_NEEDS_MODE (oflag))
    {
      va_list arg;
      va_start (arg, oflag);
      mode = va_arg (arg, int);
      va_end (arg);
    }

  return INLINE_SYSCALL_CALL (openat, AT_FDCWD, file, oflag, mode);
}

INLINE_SYSCALL_CALL就不展开说了,这里已经很明显了。open之下调用的就是openat

如果不使用mode,直接赋0

这里这个AT_FDCWD是一个常量,通过搜索可以知道值为-100

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值