#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "exp.h" #define DEVNAME "/dev/fuse" #define FSTYPE "fuse" #define MNT "./tmp" void fatal(const char *msg) { perror(msg); exit(1); } static void xwritefile(const char *path, const char *data) { int fd = open(path, O_WRONLY); if (fd == -1) err(1, "open %s", path); ssize_t len = (ssize_t)strlen(data); if (write(fd, data, len) != len) err(1, "write %s", path); close(fd); } void create_ns() { // 创建新的命名空间 char buf[0x1000]; uid_t uid, gid; uid = getuid(); gid = getgid(); if (unshare(CLONE_NEWNS | CLONE_NEWUSER) == -1) fatal("unshare"); xwritefile("/proc/self/setgroups", "deny"); sprintf(buf, "1000 %d 1", uid); xwritefile("/proc/self/uid_map", buf); sprintf(buf, "1000 %d 1", gid); xwritefile("/proc/self/gid_map", buf); } void mount_pfuse(int fd) { // 挂载fuse文件系统 mkdir(MNT, 0777); char opts[0x1000]; struct stat stbuf; int res = lstat(MNT, &stbuf); if (res < 0) fatal("lstat"); mode_t rootmode = stbuf.st_mode & S_IFMT; sprintf(opts, "fd=%d,rootmode=%o,user_id=%u,group_id=%u", fd, rootmode, getuid(), getgid()); // system("id"); puts(opts); int ret = mount(DEVNAME, MNT, FSTYPE, MS_NOSUID | MS_NODEV, opts); if (ret < 0) { fatal("mount"); } puts("[+] mount success!"); system("mount"); // 查看已经挂载的文件系统 } void clear(int fd) { int ret = umount(MNT); if (ret < 0) fatal("umount"); puts("umount success"); close(fd); } int fuse_dev_open(char *path) { int fd = open(path, O_RDWR); if (fd < 0) fatal("open"); return fd; } void fuse_dev_read(int fd, char *buf, int len) { int ret = 0; ret = read(fd, buf, len); if (ret < 0) fatal("read"); } void fuse_dev_write(int fd, char *buf, int len) { int ret = 0; ret = write(fd, buf, len); if (ret < 0) fatal("write"); } void fuse_show_req_head(struct fuse_in_header *in) { fflush(stdout); // 刷新标准输出输出 puts("-----------------------"); puts("[+] head in"); printf("[+] len:\t%d\n", in->len); printf("[+] opcode:\t%s[%d]\n", fuse_ll_ops[in->opcode], in->opcode); printf("[+] unique:\t%d\n", in->unique); printf("[+] nodeid:\t%d\n", in->nodeid); printf("[+] uid:\t%d\n", in->uid); printf("[+] gid:\t%d\n", in->gid); printf("[+] padding:\t%d\n", in->padding); puts("-----------------------"); } char *fuse_receive_req(int fd) { puts("[+] start recv"); size_t bufsize = getpagesize() + 0x1000; char *buf = malloc(bufsize); fuse_dev_read(fd, buf, bufsize); struct fuse_in_header *in = (struct fuse_in_header *)buf; fuse_show_req_head(in); puts("[+] end recv"); return buf; } void fuse_send_reply(int fd, void *arg, size_t argsize, int error, size_t unique) { struct iovec iov[2]; int count = 1; // 第一个iov存储out头 struct fuse_out_header out; iov[0].iov_base = &out; iov[0].iov_len = sizeof(struct fuse_out_header); out.unique = unique; out.error = error; // 第二个iov存储参数信息 if (argsize) { iov[1].iov_base = (void *)arg; iov[1].iov_len = argsize; count++; } out.len = iov_length(iov, count); printf("unique: %llu, success, outsize: %i\n", (unsigned long long)out.unique, out.len); int res = writev(fd, iov, count); printf("fd: %d\n", fd); if (res < 0) fatal("fuse send reply"); } void fuse_show_init_in(struct fuse_init_in *in) { fflush(stdout); // 刷新标准输出输出 puts("-----------------------"); puts("[+] init in"); printf("[+] major:\t%d\n", in->major); printf("[+] minor:\t%d\n", in->minor); printf("[+] max_readahead:\t%d\n", in->max_readahead); printf("[+] flags:\t%x\n", in->flags); } void fuse_do_init(int fd) { // 获取头部结构; char *buf = 0; buf = fuse_receive_req(fd); struct fuse_in_header *in = (struct fuse_in_header *)buf; // fuse_show_req_head(in); struct fuse_init_in *arg; arg = (struct fuse_init_in *)&in[1]; fuse_show_init_in(arg); // 返回 参数 struct fuse_init_out outarg; memset(&outarg, 0, sizeof(outarg)); outarg.major = FUSE_KERNEL_VERSION; outarg.minor = FUSE_KERNEL_MINOR_VERSION; outarg.max_readahead = getpagesize() + 0x1000 - 4096; outarg.flags = 0x11; outarg.max_background = 0; outarg.congestion_threshold = 0; outarg.max_write = getpagesize() + 0x1000 - 4096; fuse_send_reply(fd, &outarg, sizeof(outarg), 0, in->unique); } void fuse_do_getattr(int fd) { char *sbuf; struct fuse_in_header *in; sbuf = fuse_receive_req(fd); in = (struct fuse_in_header *)sbuf; // fuse_show_req_head(in); // 解析参数进行设置 struct fuse_getattr_in *arg = (struct fuse_getattr_in *)&in[1]; // struct fuse_file_info fi; // if (arg->getattr_flags & FUSE_GETATTR_FH) // { // memset(&fi, 0, sizeof(fi)); // fi.fh = arg->fh; // fi.fh_old = fi.fh; // fip = &fi; // } // 设置返回值 struct stat st; st.st_ino = in->nodeid; st.st_mode = S_IFREG | 04777; st.st_uid = 1000; st.st_gid = 1000; st.st_size = 100; struct fuse_attr_out outarg; memset(&outarg, 0, sizeof(outarg)); outarg.attr_valid = 0; outarg.attr_valid_nsec = 0; convert_stat(&st, &outarg.attr); fuse_send_reply(fd, &outarg, sizeof(outarg), 0, in->unique); } void fuse_do_lookup(int fd) { fflush(stdout); puts("-----------------------"); puts("[+] start look up"); char *sbuf; struct fuse_in_header *in; sbuf = fuse_receive_req(fd); in = (struct fuse_in_header *)sbuf; char *name = ((char *)&in[1]); printf("[+] lookup name: %s\n", name); struct fuse_entry_param e; memset(&e, 0, sizeof(struct fuse_entry_param)); // 清空内存 e.ino = 5; e.generation = 1234; e.entry_timeout = 0; e.attr_timeout = 0; e.attr.st_ino = in->nodeid; e.attr.st_mode = S_IFREG | 0777; e.attr.st_uid = 1000; e.attr.st_gid = 1000; e.attr.st_size = 10000; // 长度太小? struct fuse_entry_out outarg; memset(&outarg, 0, sizeof(outarg)); fill_entry(&outarg, &e); // getchar(); printf("unique: %d\n", in->unique); fuse_send_reply(fd, &outarg, sizeof(outarg), 0, in->unique); puts("[+] end look_up"); } void fuse_do_open(int fd) { fflush(stdout); puts("-----------------------"); puts("[+] start do_open"); char *sbuf; struct fuse_in_header *in; sbuf = fuse_receive_req(fd); in = (struct fuse_in_header *)sbuf; struct fuse_open_in *inarg = (struct fuse_open_in *)&in[1]; printf("[+] open flag : %x\n", inarg->flags); printf("[+] open unused : %x\n", inarg->unused); struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.flags = inarg->flags; fi.direct_io = 1; // 设置direct io 为 1 struct fuse_open_out outarg; memset(&outarg, 0, sizeof(outarg)); fill_open(&outarg, &fi); printf("unique: %d\n", in->unique); fuse_send_reply(fd, &outarg, sizeof(outarg), 0, in->unique); puts("[+] end do_open"); } void fuse_do_read(int fd) { fflush(stdout); puts("-----------------------"); puts("[+] start do_read"); char *sbuf; struct fuse_in_header *in; sbuf = fuse_receive_req(fd); in = (struct fuse_in_header *)sbuf; struct fuse_read_in *inarg = (struct fuse_read_in *)&in[1]; struct fuse_bufvec *buf; void *mem; size_t size = inarg->size; char outarg[0x100]; strcpy(outarg, "hello world!"); printf("unique: %d\n", in->unique); fuse_send_reply(fd, outarg, strlen(outarg), 0, in->unique); puts("[+] end do_read"); } void fuse_do_write(fd) { fflush(stdout); puts("-----------------------"); puts("[+] start do_write"); // splice read requset from pipe puts("[+] create pipe"); int pfd[2], ret; ret = pipe(pfd); if (ret < 0) fatal("pipe"); size_t bufsize = getpagesize() + 0x1000; ret = splice(fd, NULL, pfd[1], NULL, bufsize, 0); if (ret < 0) fatal("splice"); // 通过splice读取头部; struct fuse_in_header in; ret = read(pfd[0], &in, sizeof(struct fuse_in_header)); if (ret < 0) fatal("read head"); fuse_show_req_head(&in); puts("[+] send reply finish write"); struct fuse_write_out outarg; outarg.size = 1; outarg.padding = 0; printf("unique: %d\n", in.unique); fuse_send_reply(fd, &outarg, sizeof(outarg), 0, in.unique); // 阻塞等待子进程释放page int t = 0; do { fflush(stdout); puts("[+] input 1 to contine, other to block"); scanf("%d", &t); puts("[+] ..."); } while (t != 1); struct fuse_write_in inarg; struct fuse_bufvec bufv; ret = read(pfd[0], &inarg, sizeof(struct fuse_write_in)); if (ret < 0) fatal("read write in"); /* struct fuse_write_in { __u64 fh; __u64 offset; __u32 size; __u32 write_flags; __u64 lock_owner; __u32 flags; __u32 padding; }; */ printf("[+] write in:\n"); printf("\tfh:\t%lld\n", inarg.fh); printf("\toffset:\t%lld\n", inarg.offset); printf("\tsize:\t%d\n", inarg.size); printf("\twrite_flags:\t%d\n", inarg.write_flags); printf("\tlock_owner:\t%llx\n", inarg.lock_owner); printf("\tflags:\t%d\n", inarg.flags); printf("\tpadding:\t%d\n", inarg.padding); ret = read(pfd[0], &bufv, sizeof(bufv)); //客户端write结束以后再读取page printf("bufv:\t%s\n", (char *)&bufv); puts("[+] end do_write"); close(pfd[0]); close(pfd[1]); } int main(int argc, char const *argv[]) { int fd, pid; char buf[0x1000]; create_ns(); fd = fuse_dev_open(DEVNAME); mount_pfuse(fd); // 挂载fuse文件系统 fuse_do_init(fd); pid = fork(); if (pid == 0) { char *path[0x100]; sprintf(path, "%s/file", MNT); puts(path); int fd = open(path, O_RDWR); // o只是阻塞了flash的刷新 if (fd < 0) fatal("fuse open"); puts("[++] start mmap"); char *ptr = (char *)mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); fflush(stdout); if (ptr == 0) fatal("mmap failed"); printf("[++] write msg : %s\n", ptr); memset(ptr, 'A', getpagesize()); int ret = write(fd, ptr, 0x100); // 调用fuse_read fflush(stdout); if (ret < 0) // fatal("fuse write"); puts("[--] write error"); puts("[++] start munmap"); memset(ptr, 'B', 0x10); ret = munmap(ptr, getpagesize()); if (ret < 0) fatal("munmap error"); // puts("[++] close hello"); // close(hfd); puts("[++] child finish"); return 0; } fuse_do_lookup(fd); fuse_do_open(fd); fuse_do_write(fd); fuse_receive_req(fd); // fuse_do_getattr(fd); kill(pid, SIGINT); waitpid(pid, NULL, 0); clear(fd); // 清理程序残留 return 0; }