[SECURITY] NFS symlink chain buffer overflow → remote code execution (net/nfs-common.c)

manizzle alexandria manizzle.msf at gmail.com
Fri Apr 3 20:44:49 CEST 2026


  Hi Tom,

  I'm reporting a remotely exploitable buffer overflow in U-Boot's NFS
  client that I've confirmed leads to arbitrary code execution.

  SUMMARY

  A rogue NFS server can chain two READLINK (symlink) responses to
  overflow the global nfs_path_buff[2048] in net/nfs-common.c by ~141
  bytes. This corrupts the nfs_path pointer and adjacent globals,
  allowing the attacker to hijack the NFS state machine and deliver
  shellcode to a known memory address. I have a working end-to-end
  exploit with code execution confirmed on QEMU ARM (Cortex-A15).

  No authentication is required. The overflow triggers during normal
  NFS boot before any OS is loaded.

  AFFECTED

  - All U-Boot versions with CONFIG_CMD_NFS=y (NFS boot support)
  - Tested on: 2026.04-rc5, commit c704af3c8b0
  - File: net/nfs-common.c, function nfs_readlink_reply(), lines 667-686

  ROOT CAUSE

  nfs_readlink_reply() reads the symlink target length (rlen) from
  the RPC reply and validates it against the packet size, but NOT
  against the destination buffer (nfs_path_buff[2048]):

    rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]);

    // Checks rlen fits in packet — CORRECT
    if (((uchar *)&rpc_pkt.u.reply.data[0] - (uchar *)&rpc_pkt + rlen) >
len)
        return -NFS_RPC_DROP;

    // Copies rlen bytes into nfs_path — NO CHECK against buffer size
    memcpy(nfs_path + pathlen, ..., rlen);

  A single response can't overflow because rlen maxes at ~1128 (packet
  size limit). But two chained relative symlinks accumulate path length:

    1st READLINK: 1100-byte relative target → nfs_path grows to ~1060B
    2nd READLINK: 1128-byte relative target → writes to offset 2189
                  → overflows nfs_path_buff[2048] by ~141 bytes

  EXPLOIT CHAIN

    1. Portmap lookup  → attacker returns fake mountd/nfsd ports
    2. Mount           → attacker returns fake file handle
    3. Lookup          → attacker returns file handle
    4. Read            → attacker returns NFSERR_ISDIR (triggers symlink)
    5. Readlink #1     → 1100-byte relative symlink (grows path)
    6. Readlink #2     → OVERFLOW — overwrites nfs_path pointer to
                         attacker-planted "/x" string, state machine
survives
    7. Mount/Lookup    → re-enters NFS flow with controlled path
    8. Read            → attacker serves ARM shellcode as file content
                         → written to image_load_addr (0x42000000)
    9. Code execution  → shellcode runs, writes "PWNED!" to UART

  PROOF

  GDB output after exploit:

    === SHELLCODE AT 0x42000000 ===
       0x42000000:  mov   r0, #9
       0x42000004:  lsl   r0, r0, #24      @ r0 = 0x09000000 (UART)
       0x42000008:  mov   r1, #0x50        @ 'P'
       0x4200000c:  str   r1, [r0]         @ write to UART
       ...

    === AFTER EXECUTION ===
       pc = 0x42000040   (completed, infinite loop)
       r0 = 0x09000000   (UART base)
       r1 = 0x0a         (newline)

    === QEMU UART ===
       Loading: *T #PWNED!

  SUGGESTED FIX

  Add a bounds check before the memcpy in nfs_readlink_reply():

    --- a/net/nfs-common.c
    +++ b/net/nfs-common.c
    @@ -670,6 +670,10 @@
         if (((uchar *)&rpc_pkt.u.reply.data[0] - (uchar *)&rpc_pkt + rlen)
> len)
             return -NFS_RPC_DROP;

    +    int current_len = strlen(nfs_path) + 1;
    +    if (current_len + rlen >= sizeof(nfs_path_buff))
    +        return -NFS_RPC_ERR;
    +
         if (*((char *)&rpc_pkt.u.reply.data[2 + nfsv3_data_offset]) !=
'/') {

  I have a full advisory document and working PoC (Python script, ~300
  lines) attached. The PoC runs as a rogue NFS server and was tested
  against QEMU ARM virt with qemu_arm_defconfig.

  I'm requesting a CVE for this issue. I plan to follow standard 90-day
  coordinated disclosure. Please let me know if you need anything else
  or would like to discuss the fix.

  Thanks,
  Murtaza Munaim
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ADVISORY.md
Type: text/markdown
Size: 7899 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20260403/dd729a29/attachment.md>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: nfs_rce.py
Type: text/x-python-script
Size: 11713 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20260403/dd729a29/attachment.bin>


More information about the U-Boot mailing list