检查签名的Linux共享目前负荷
-
18-09-2019 - |
题
目标:负荷。因此,或可执行已经验证的签署(或核实对任意的算法)。
我希望能够验证。以可执行和后载/执行。因此/执行与dlopen里/...
扳手在这的是,似乎没有方案的方式来检查-那么-负荷。一个可以检查该文件并随后将其装载后..但是有一个窗口的机会,在这些人可以交换出该文件的另一种。
一个可能的解决方案,我可以认为是二进制,检查签名,然后dlopen里/execvt的 /proc/$PID/fd
....但是我不知道如果这是一个可行的解决方案。
由于文件系统锁是咨询Linux他们不是那么有用于此目的的...(嗯,有 mount -o mand
...但是,这是东西userlevel,不根使用)。
解决方案
的问题是在形成一种主要不可解你给,因为共享对象通过MMAP()ING加载处理的内存空间。所以,即使你的可能的请确保执行dlopen()操作的是你检查了一个声明的文件就OK了,谁可以写入文件可以在修改加载的对象的已加载后,任何的时间。 (这就是为什么你不写他们升级运行二进制文件 - 而不是删除,然后安装,因为写入他们很可能会崩溃,所有正在运行的情况下)。
您最好的办法是,以确保只有您运行的是可以写入文件的用户,然后检查它,然后dlopen()的它。您的用户(或root)仍然可以忙里偷闲不同的代码,但这些权限可以只ptrace的)处理(你好歹做他们的投标。
其他提示
许多动态的连接(包括Glibc s)支持设置 LD_AUDIT
环境可变的一个结肠-分开列的共用图书馆。这些图书馆是允许挂钩的各个地点的动态图书馆加载过程。
#define _GNU_SOURCE
#include <dlfcn.h>
#include <link.h>
unsigned int la_version(unsigned int v) { return v; }
unsigned int la_objopen(struct link_map *l, Lmid_t lmid, uintptr_t *cookie) {
if (!some_custom_check_on_name_and_contents(l->l_name, l->l_addr))
abort();
return 0;
}
编制这种用 cc -shared -fPIC -o test.so test.c
或类似的。
你可以看到 glibc/elf/tst-auditmod1.c
或 latrace 更多的实例,或者读取 接头和图书馆指南.
非常非常具体的要Glibc内部,但是你仍然可以勾到 libdl
在运行时间。
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
extern struct dlfcn_hook {
void *(*dlopen)(const char *, int, void *);
int (*dlclose)(void *);
void *(*dlsym)(void *, const char *, void *);
void *(*dlvsym)(void *, const char *, const char *, void *);
char *(*dlerror)(void);
int (*dladdr)(const void *, Dl_info *);
int (*dladdr1)(const void *, Dl_info *, void **, int);
int (*dlinfo)(void *, int, void *, void *);
void *(*dlmopen)(Lmid_t, const char *, int, void *);
void *pad[4];
} *_dlfcn_hook;
static struct dlfcn_hook *old_dlfcn_hook, my_dlfcn_hook;
static int depth;
static void enter(void) { if (!depth++) _dlfcn_hook = old_dlfcn_hook; }
static void leave(void) { if (!--depth) _dlfcn_hook = &my_dlfcn_hook; }
void *my_dlopen(const char *file, int mode, void *dl_caller) {
void *result;
fprintf(stderr, "%s(%s, %d, %p)\n", __func__, file, mode, dl_caller);
enter();
result = dlopen(file, mode);
leave();
return result;
}
int my_dlclose(void *handle) {
int result;
fprintf(stderr, "%s(%p)\n", __func__, handle);
enter();
result = dlclose(handle);
leave();
return result;
}
void *my_dlsym(void *handle, const char *name, void *dl_caller) {
void *result;
fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, name, dl_caller);
enter();
result = dlsym(handle, name);
leave();
return result;
}
void *my_dlvsym(void *handle, const char *name, const char *version, void *dl_caller) {
void *result;
fprintf(stderr, "%s(%p, %s, %s, %p)\n", __func__, handle, name, version, dl_caller);
enter();
result = dlvsym(handle, name, version);
leave();
return result;
}
char *my_dlerror(void) {
char *result;
fprintf(stderr, "%s()\n", __func__);
enter();
result = dlerror();
leave();
return result;
}
int my_dladdr(const void *address, Dl_info *info) {
int result;
fprintf(stderr, "%s(%p, %p)\n", __func__, address, info);
enter();
result = dladdr(address, info);
leave();
return result;
}
int my_dladdr1(const void *address, Dl_info *info, void **extra_info, int flags) {
int result;
fprintf(stderr, "%s(%p, %p, %p, %d)\n", __func__, address, info, extra_info, flags);
enter();
result = dladdr1(address, info, extra_info, flags);
leave();
return result;
}
int my_dlinfo(void *handle, int request, void *arg, void *dl_caller) {
int result;
fprintf(stderr, "%s(%p, %d, %p, %p)\n", __func__, handle, request, arg, dl_caller);
enter();
result = dlinfo(handle, request, arg);
leave();
return result;
}
void *my_dlmopen(Lmid_t nsid, const char *file, int mode, void *dl_caller) {
void *result;
fprintf(stderr, "%s(%lu, %s, %d, %p)\n", __func__, nsid, file, mode, dl_caller);
enter();
result = dlmopen(nsid, file, mode);
leave();
return result;
}
static struct dlfcn_hook my_dlfcn_hook = {
.dlopen = my_dlopen,
.dlclose = my_dlclose,
.dlsym = my_dlsym,
.dlvsym = my_dlvsym,
.dlerror = my_dlerror,
.dladdr = my_dladdr,
.dlinfo = my_dlinfo,
.dlmopen = my_dlmopen,
.pad = {0, 0, 0, 0},
};
__attribute__((constructor))
static void init(void) {
old_dlfcn_hook = _dlfcn_hook;
_dlfcn_hook = &my_dlfcn_hook;
}
__attribute__((destructor))
static void fini(void) {
_dlfcn_hook = old_dlfcn_hook;
}
$ cc -shared -fPIC -o hook.so hook.c $ cat > a.c #include <dlfcn.h> int main() { dlopen("./hook.so", RTLD_LAZY); dlopen("libm.so", RTLD_LAZY); } ^D $ cc -ldl a.c $ ./a.out my_dlopen(libm.so, 1, 0x80484bd)
不幸的是,我的调查我的结论是,甚至如果你能挂钩 glibc/elf/dl-load.c:open_verify()
(你不能),这是不可能使这场比赛-免费,对有人写过的段的图书馆。
这个项目 据说解决了这一内核的水平。
DigSig目前提供:
- 运行时间签名认证的精灵的二进制文件和共用图书馆。
- 支持文件的签名的撤销。
- 一名高速缓存机制,以增强性能。
我提出以下解决方案,应在不工作的库*)
int memfd = memfd_create("for-debugging.library.so", MFD_CLOEXEC | MFD_ALLOW_SEALING);
assert(memfd != -1);
// Use any way to read the library from disk and copy the content into memfd
// e.g. write(2) or ftruncate(2) and mmap(2)
// Important! if you use mmap, you have to unmap it before the next step
// fcntl( , , F_SEAL_WRITE) will fail if there exists a writeable mapping
int seals_to_set = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL;
int sealing_err = fcntl(memfd, F_ADD_SEALS, seals_to_set);
assert(sealing_err == 0);
// Only now verify the contents of the loaded file
// then you can safely *) dlopen("/proc/self/fd/<memfd>");
*)不实际上不受攻击测试它。在生产中无需进一步调查中不要使用。