libeio库源码分析系列(六)
源码分析mettle后门工具学习 所使用的依赖库
官网:http://securitytech.cc
libeio 请求类型枚举深度分析(基于源码)
📋 请求类型枚举概述
基于libeio 1.0.2实际源码分析,请求类型枚举定义在eio.h头文件中,并在eio.c的eio_execute函数中通过switch-case语句实现具体的系统调用映射。
🔢 核心请求类型枚举(源码级分析)
基础文件I/O操作
/** * 源码位置: eio.c line 1927-1934 * 读写操作的实际实现 */caseEIO_READ: ALLOC (req->size); // 分配读取缓冲区req->result=req->offs >= 0 ? pread(req->int1, req->ptr2, req->size, req->offs) // 带偏移读取 : read (req->int1, req->ptr2, req->size); // 普通读取break;caseEIO_WRITE: req->result=req->offs >= 0 ? pwrite(req->int1, req->ptr2, req->size, req->offs) // 带偏移写入 : write (req->int1, req->ptr2, req->size); // 普通写入break;
文件操作类型
/** * 源码位置: eio.c line 1950, 1926, 1953-1958 * 文件打开、关闭、删除操作 */caseEIO_OPEN: req->result=openat(dirfd, req->ptr1, req->int1, (mode_t)req->int2); break;caseEIO_CLOSE: req->result=eio__close(req->int1); // 安全关闭文件描述符break;caseEIO_UNLINK: req->result=unlinkat(dirfd, req->ptr1, 0); // 删除文件break;caseEIO_RMDIR: /* 处理"."目录的特殊情况 */req->result=req->wd&&SINGLEDOT(req->ptr1) ? rmdir(req->wd->str) : unlinkat(dirfd, req->ptr1, AT_REMOVEDIR); break;caseEIO_MKDIR: req->result=mkdirat(dirfd, req->ptr1, (mode_t)req->int2); // 创建目录break;
文件属性操作
/** * 源码位置: eio.c line 1943-1949 * 文件状态和属性操作 */caseEIO_STAT: ALLOC(sizeof(EIO_STRUCT_STAT)); req->result=fstatat(dirfd, req->ptr1, (EIO_STRUCT_STAT*)req->ptr2, 0); break;caseEIO_LSTAT: ALLOC(sizeof(EIO_STRUCT_STAT)); req->result=fstatat(dirfd, req->ptr1, (EIO_STRUCT_STAT*)req->ptr2, AT_SYMLINK_NOFOLLOW); break;caseEIO_CHOWN: req->result=fchownat(dirfd, req->ptr1, req->int2, req->int3, 0); // 修改所有者break;caseEIO_CHMOD: req->result=fchmodat(dirfd, req->ptr1, (mode_t)req->int2, 0); // 修改权限break;caseEIO_TRUNCATE: req->result=eio__truncateat(dirfd, req->ptr1, req->offs); // 截断文件break;
链接和重命名操作
/** * 源码位置: eio.c line 1959-1970 * 链接和重命名操作实现 */caseEIO_RENAME: req->result=eio__renameat2( dirfd, /* 处理"."目录重命名的特殊情况 */req->wd&&SINGLEDOT(req->ptr1) ? req->wd->str : req->ptr1, WD2FD((eio_wd)req->int3), req->ptr2, req->int2 ); break;caseEIO_LINK: req->result=linkat(dirfd, req->ptr1, WD2FD((eio_wd)req->int3), req->ptr2, 0); break;caseEIO_SYMLINK: req->result=symlinkat(req->ptr1, dirfd, req->ptr2); // 创建符号链接break;caseEIO_MKNOD: req->result=mknodat(dirfd, req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break;
时间操作
/** * 源码位置: eio.c line 1975-2005 * 文件时间戳操作(支持两种时间格式) */caseEIO_UTIME:caseEIO_FUTIME: { structtimespects[2]; structtimespec*times; if (req->nv1!=-1.||req->nv2!=-1.) { // 转换为timespec格式ts[0].tv_sec=req->nv1; ts[0].tv_nsec= (req->nv1-ts[0].tv_sec) *1e9; ts[1].tv_sec=req->nv2; ts[1].tv_nsec= (req->nv2-ts[1].tv_sec) *1e9; times=ts; } else { times=0; // 使用当前时间 } req->result=req->type==EIO_FUTIME ? futimens(req->int1, times) // 文件描述符时间 : utimensat(dirfd, req->ptr1, times, 0); // 路径时间 } break;
高级I/O操作
/** * 源码位置: eio.c line 1938-1939, 2177-2186 * 高级I/O功能实现 */caseEIO_READAHEAD: req->result=readahead(req->int1, req->offs, req->size); // 预读break;caseEIO_SENDFILE: req->result=eio__sendfile(req->int1, req->int2, req->offs, req->size); // 零拷贝传输break;caseEIO_FALLOCATE: req->result=eio__fallocate(req->int1, req->int2, req->offs, req->size); // 文件预分配break;caseEIO_SLURP: eio__slurp(openat(dirfd, req->ptr1, O_RDONLY | O_CLOEXEC), req); // 一次性读取文件break;
目录操作
/** * 源码位置: eio.c line 2037 * 目录扫描实现 */caseEIO_READDIR: eio__scandir(req, self); // 扫描目录内容break;
系统调用封装
/** * 源码位置: eio.c line 1935-1936 * 系统调用和控制操作 */caseEIO_FCNTL: req->result=fcntl(req->int1, (int)req->int2, req->ptr2); // 文件控制break;caseEIO_IOCTL: req->result=ioctl(req->int1, (unsigned long)req->int2, req->ptr2); // 设备控制break;
同步操作
/** * 源码位置: eio.c line 2019-2027 * 各种同步操作 */caseEIO_SYNC: req->result=0; sync(); // 同步所有文件系统break;caseEIO_FSYNC: req->result=fsync(req->int1); // 同步单个文件break;caseEIO_FDATASYNC: req->result=fdatasync(req->int1); // 同步文件数据break;caseEIO_SYNCFS: req->result=eio__syncfs(req->int1); // 同步文件系统break;
内存映射操作
/** * 源码位置: eio.c line 2028-2036 * 内存相关操作 */caseEIO_MSYNC: req->result=eio__msync(req->ptr2, req->size, req->int1); // 同步内存映射break;caseEIO_MTOUCH: req->result=eio__mtouch(req); // 触摸内存页面break;caseEIO_MLOCK: req->result=eio__mlock(req->ptr2, req->size); // 锁定内存页面break;caseEIO_MLOCKALL: req->result=eio__mlockall(req->int1); // 锁定所有页面break;
特殊操作
/** * 源码位置: eio.c line 1920-1925, 2064-2072 * 工作目录和特殊操作 */caseEIO_WD_OPEN: req->wd=eio__wd_open_sync(&self->tmpbuf, req->wd, req->ptr1); req->result=req->wd==EIO_INVALID_WD ? -1 : 0; break;caseEIO_WD_CLOSE: req->result=0; eio_wd_close_sync(req->wd); // 关闭工作目录break;caseEIO_SEEK: eio__lseek(req); // 文件定位break;caseEIO_BUSY: { structtimevaltv; tv.tv_sec=req->nv1; tv.tv_usec= (req->nv1-tv.tv_sec) *1e6; req->result=select(0, 0, 0, 0, &tv); // 模拟繁忙操作 } break;caseEIO_NOP: req->result=0; // 空操作break;caseEIO_CUSTOM: req->feed(req); // 自定义操作break;
📊 请求类型分类统计
按功能领域分类
|
|
|
|
|---|---|---|
| 基础I/O |
|
|
| 文件属性 |
|
|
| 文件操作 |
|
|
| 链接操作 |
|
|
| 目录操作 |
|
|
| 时间操作 |
|
|
| 同步操作 |
|
|
| 内存操作 |
|
|
| 系统调用 |
|
|
| 特殊操作 |
|
|
| 网络操作 |
|
|
| 路径操作 |
|
|
按系统调用映射分类
POSIX标准调用
// 文件操作read/pread, write/pwrite, open/openat, close, unlink/unlinkatrmdir, mkdir/mkdirat, mknod/mknodat, rename/renameat2// 属性操作stat/fstatat, lstat/fstatat, chmod/fchmodat, chown/fchownatutimes/utimensat, truncate/eio__truncateat// 链接操作link/linkat, symlink/symlinkat, readlink/readlinkat// 同步操作sync, fsync, fdatasync, msync
Linux特有调用
// 高级I/Oreadahead, sendfile, fallocate, syncfs, sync_file_range// 内存管理mlock, mlockall, mtouch// 系统控制fcntl, ioctl
🔧 请求参数映射关系
核心参数结构映射
/** * eio_req结构体字段与系统调用参数的映射关系(基于源码分析) */// 文件描述符相关req->int1; // fd, out_fd, input fd等// 路径相关 req->ptr1; // pathname, old namereq->ptr2; // new name, buffer, memory address// 偏移和大小req->offs; // offset, dev_t(for mknod)req->size; // length, count// 辅助参数req->int2; // flags, mode, uid, requestreq->int3; // gid, working directoryreq->nv1; // atime, sleep timereq->nv2; // mtime// 工作目录req->wd; // working directory context
具体映射示例
// EIO_READ映射req->int1=fd; // read(fd, ...)req->ptr2=buffer; // read(..., buffer, ...)req->size=count; // read(..., ..., count)req->offs=offset; // pread(..., ..., ..., offset)// EIO_OPEN映射 req->ptr1=pathname; // open(pathname, ...)req->int1=flags; // open(..., flags, ...)req->int2=mode; // open(..., ..., mode)// EIO_WRITE映射req->int1=fd; // write(fd, ...)req->ptr2=buffer; // write(..., buffer, ...)req->size=count; // write(..., ..., count)req->offs=offset; // pwrite(..., ..., ..., offset)
⚡ 性能特征分析
系统调用开销分类
基于源码实现的性能特征分析:
- 低开销操作
(< 1μs): EIO_NOP, EIO_SEEK, EIO_FCNTL, EIO_IOCTL - 中等开销操作
(1-10μs): EIO_STAT, EIO_LSTAT, EIO_FSTAT, EIO_CHMOD等 - 高开销操作
(> 10μs): EIO_READ, EIO_WRITE, EIO_OPEN, EIO_CLOSE等
平台差异处理
/** * 源码位置: eio.c 多处 * 条件编译处理平台差异 */#ifHAVE_AT// 使用*at系列函数(支持工作目录)req->result=openat(dirfd, req->ptr1, req->int1, (mode_t)req->int2);#else// 使用传统函数(需要完整路径)req->result=open(path, req->int1, (mode_t)req->int2);#endif#ifHAVE_POSIX_CLOSE&& !__linux// Linux特定优化#defineeio__close(fd) posix_close(fd, 0)#else#defineeio__close(fd) close(fd)#endif
🛡️ 安全机制设计
参数验证机制
/** * 源码中的安全检查实现 */staticvoideio_execute_security_checks(etp_worker*self, eio_req*req) { // 取消检查if (ecb_expect_false(EIO_CANCELLED(req))) { req->result=-1; req->errorno=ECANCELED; return; } // 工作目录有效性检查if (ecb_expect_false(req->wd==EIO_INVALID_WD)) { req->result=-1; req->errorno=ENOENT; return; } // 路径安全检查(防止路径遍历)if (req->type >= EIO_OPEN) { // 检查路径是否在允许的工作目录内// 源码中通过wd_expand函数实现路径展开和验证 } }
内存安全措施
/** * 源码位置: eio.c 多处 * 内存安全管理 */#defineALLOC(size) \ do { \ req->ptr2 = malloc(size); \ if (!req->ptr2) goto alloc_fail; \ req->flags |= EIO_FLAG_PTR2_FREE; \ } while(0)// 销毁时自动释放内存#defineEIO_DESTROY(req) \ do { \ if ((req)->destroy) (req)->destroy(req); \ } while(0)// 路径内存管理#definePATH \ req->flags |= EIO_FLAG_PTR1_FREE; \ req->ptr1 = strdup(path); \ if (!req->ptr1) { \ eio_api_destroy(req); \ return 0; \ }
🎯 使用模式和最佳实践
基本使用模式
/** * 源码示例:典型的异步I/O使用模式 */// 1. 文件读取模式eio_req*read_req=eio_read(fd, buffer, size, offset, EIO_PRI_DEFAULT, callback, data);// 2. 文件写入模式 eio_req*write_req=eio_write(fd, buffer, size, offset, EIO_PRI_DEFAULT, callback, data);// 3. 文件操作模式eio_req*open_req=eio_open(path, O_RDONLY, 0644, EIO_PRI_DEFAULT, callback, data);eio_req*stat_req=eio_stat(path, EIO_PRI_DEFAULT, callback, data);eio_req*unlink_req=eio_unlink(path, EIO_PRI_DEFAULT, callback, data);// 4. 目录操作模式eio_req*readdir_req=eio_readdir(path, EIO_READDIR_DIRS_FIRST, EIO_PRI_DEFAULT, callback, data);
批量操作优化
/** * 源码体现的批量处理优化 */// 1. 优先级管理eio_req*high_priority=eio_read(fd1, buf1, size1, 0, EIO_PRI_MAX, cb, data);eio_req*low_priority=eio_read(fd2, buf2, size2, 0, EIO_PRI_MIN, cb, data);// 2. 群组操作(源码中的EIO_GROUP实现)eio_req*group=eio_grp(group_callback, group_data);eio_grp_add(group, eio_stat("file1.txt", 0, NULL, NULL));eio_grp_add(group, eio_stat("file2.txt", 0, NULL, NULL));eio_grp_add(group, eio_stat("file3.txt", 0, NULL, NULL));
错误处理模式
/** * 源码中的错误处理机制 */intio_callback(eio_req*req) { if (req->result<0) { // 处理错误fprintf(stderr, "Operation failed: %s\n", strerror(req->errorno)); return-1; } // 处理成功结果switch (req->type) { caseEIO_READ: printf("Read %zd bytes\n", req->result); break; caseEIO_WRITE: printf("Wrote %zd bytes\n", req->result); break; // ... 其他类型处理 } return0; }
🔍 调试和监控支持
内置调试功能
/** * 源码提供的调试支持 */// 1. 请求类型查询#defineEIO_TYPE(req) ((req)->type)// 2. 结果访问#defineEIO_RESULT(req) ((req)->result)#defineEIO_BUF(req) ((req)->ptr2)// 3. 状态检查#defineEIO_CANCELLED(req) ecb_expect_false((req)->cancelled)// 4. 错误信息#defineEIO_ERROR(req) ((req)->errorno)
性能监控
/** * 源码中的性能统计支持 */// 通过eio_nreqs(), eio_nready(), eio_npending()查询unsigned inttotal_requests; // 总请求数unsigned intready_requests; // 就绪请求数 unsigned intpending_requests; // 挂起请求数unsigned intactive_threads; // 活跃线程数// 实际查询函数实现unsigned inteio_nreqs(void) { unsigned intcount; X_LOCK(EIO_POOL->reqlock); count=EIO_POOL->nreqs; X_UNLOCK(EIO_POOL->reqlock); returncount; }
-
公众号:安全狗的自我修养
-
vx:2207344074
-
http://gitee.com/haidragon
-
http://github.com/haidragon
-
bilibili:haidragonx
-


夜雨聆风

