** Description changed:

  [ Impact ]
  
  Users running VMs with `virtiofs` mounts where there is a page-size
  mismatch between the host and guest kernels (e.g., a 4K page-size host
  and a 64K page-size guest) experience "Cannot allocate memory"
  (`ENOMEM`) errors when attempting to read directories.
  
  This occurs because `virtiofsd` computes `max_pages` based on the host's
  page size, but the guest converts `max_pages` back to bytes using its
  own (larger) page size. As a result, the guest sends a `READDIR` request
  that exceeds `virtiofsd`'s `MAX_BUFFER_SIZE`, causing the daemon to
  reject the request.
  
  The fix resolves this by capping the amount of directory data generated
  locally to `MAX_BUFFER_SIZE` instead of rejecting the oversized request,
  as `READDIR` is permitted to return fewer bytes than requested.
  
  [ Test Plan ]
  
  # Set up repos and download packages
  0. Grab a fresh arm64 machine
  1. add deb-src to ubuntu.sources
  2. sudo apt build-dep linux
- 3. sudo apt install virtme-ng qemu-system-arm
+ 3. sudo apt install virtme-ng qemu-system-arm libncurses-dev
  4. sudo apt install virtiofsd # the package in question
  
  # Set up vng and build kernel
  5. sudo usermod -aG kvm ubuntu && newgrp kvm # replace `ubuntu` with your user
  6. git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
  7. wait 10000 years; cd linux
  8. set up kernel config:
      a. vng --kconfig
      b. make menuconfig
      c. kernel features -> page size -> set to 64k -> save -> exit
  9. vng --build
  
  # Run the reproducer (from upstream merge request)
  10. getconf PAGE_SIZE # should print 4096 on host
- 11. vng --run arch/arm64/boot/Image \
-   --memory 16G --cpus 4 --overlay-rwdir /tmp \
-   --exec 'uname -r; getconf PAGE_SIZE; ls /tmp; echo "ls rc=$?"; python3 -c 
"import os; print(len(os.listdir(\"/tmp\")))"'
+ 11. bash -c 'vng --run arch/arm64/boot/Image --memory 16G --cpus 4 
--overlay-rwdir /tmp --exec 'uname -r; getconf PAGE_SIZE; ls /tmp; echo "ls 
rc=$?"; python3 -c "import os; print(len(os.listdir("/tmp")))"''
  12. There should be no errors in the output of 11.
  
  12a. Unpatched package output (fail):
  ubuntu@kamek:~/linux$ vng --run arch/arm64/boot/Image   --memory 16G --cpus 4 
--overlay-rwdir /tmp   --exec 'uname -r; getconf PAGE_SIZE; ls /tmp; echo "ls 
rc=$?"; python3 -c "import os; print(len(os.listdir(\"/tmp\")))"'
  7.1.0-rc7-virtme
  65536
  ls: general io error: Cannot allocate memory (os error 12)
  ls rc=1
  Traceback (most recent call last):
    File "<string>", line 1, in <module>
      import os; print(len(os.listdir("/tmp")))
                           ~~~~~~~~~~^^^^^^^^
  OSError: [Errno 12] Cannot allocate memory: '/tmp'
  
  12b. Patched package output (success):
  ubuntu@kamek:~/linux$ vng --run arch/arm64/boot/Image   --memory 16G --cpus 4 
--overlay-rwdir /tmp   --exec 'uname -r; getconf PAGE_SIZE; ls /tmp; echo "ls 
rc=$?"; python3 -c "import os; print(len(os.listdir(\"/tmp\")))"'
  7.1.0-rc7-virtme
  65536
  hsperfdata_root
  snap-private-tmp
  systemd-private-119639c5e17c430ca33b233f937d2924-ModemManager.service-EmreAg
  systemd-private-119639c5e17c430ca33b233f937d2924-chrony.service-DJCwIj
  systemd-private-119639c5e17c430ca33b233f937d2924-fwupd.service-DSIi3M
  systemd-private-119639c5e17c430ca33b233f937d2924-polkit.service-w28tHD
  systemd-private-119639c5e17c430ca33b233f937d2924-systemd-logind.service-bWi2S2
  virtme_retvjz9uo9n
  ls rc=0
  12
  
  [ Other Info ]
  
  Extra info from upstream MR:
  ---
  The virtiofsd-side failure is easiest to reproduce after applying the
  kernel patch that backs uncached readdir output with pages: 
https://lore.kernel.org/all/[email protected]/
  Without that kernel patch, the guest may fail earlier in the kernel before
  the oversized READDIR request reaches virtiofsd.
  ...
  (omitted for brevity)
  ...
  The page-size mismatch is what exposes the issue. virtiofsd computes
  max_pages from the host page size, while the guest converts max_pages back
  to bytes using the guest page size. With a 4K host and 64K guest, the guest
  can send a READDIR size larger than virtiofsd's MAX_BUFFER_SIZE.
  READDIR can return less than requested, so this patch caps the amount of
  directory data generated locally instead of rejecting the request.
  ---
  
  Target Releases: Ubuntu 24.04 and 26.04.
  
  Upstream Commit: d24cda8a325d server: do not reject oversized readdir requests
  Upstream Link: 
https://gitlab.com/virtio-fs/virtiofsd/-/commit/d24cda8a325d2a9ae1adc5acda57515ed2e8e1d2
  Upstream Merge Request: 
https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/316

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2155048

Title:
  [SRU] Backport request - server: do not reject oversized readdir
  requests

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/rust-virtiofsd/+bug/2155048/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to