diff mbox series

[1/1] net: nfs: fix file handle length in NFSv3

Message ID 20240326093431.23962-1-sebastien.szymanski@armadeus.com
State Accepted
Commit d2986567b27dae764b19886bcda1d24b7c41d075
Delegated to: Tom Rini
Headers show
Series [1/1] net: nfs: fix file handle length in NFSv3 | expand

Commit Message

Sébastien Szymanski March 26, 2024, 9:34 a.m. UTC
The NFS protocol uses file handles to refer to file or directory.
In NFSv2 file handles have a fixed size of 32 bytes.
In NFSv3 file handles have a variable length up to 64 bytes. This is
also true for the MOUNT protocol. [1]
When the NFSv3 server replies with a file handle length > 32 bytes, U-Boot
only copies 32 bytes of that file handle and the next LOOKUP Call fails:

BIOS> nfs ${loadaddr} 192.168.1.51:/nfsroot/opos93dev-br/boot/Image
Using ethernet@428a0000 device
File transfer via NFS from server 192.168.1.51; our IP address is 192.168.1.133
Filename '/nfsroot/opos93dev-br/boot/Image'.
Load address: 0x80400000
Loading: *** ERROR: File lookup fail

done
BIOS>

Looking at this transfer in Wireshark, we can see that the server
replies with the following file handle:

    length: 36
    [hash (CRC-32): 0x230ac67b]
    FileHandle: 0100070101005e000000000091763911f87c449fa73c298552db19ba0c9f60002980cfd2

and U-Boot sends the following file handle in the next LOOKUP Call:

    length: 32
    [hash (CRC-32): 0x6314131b]
    FileHandle: 000000240100070101005e000000000091763911f87c449fa73c298552db19ba

Fix this by using a variable length file handle for dirfh.

[1] https://www.rfc-editor.org/rfc/rfc1813.html#page-106

Fixes: b0baca982048 ("net: NFS: Add NFSv3 support")
Signed-off-by: Sébastien Szymanski <sebastien.szymanski@armadeus.com>
---
 net/nfs.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

Comments

Andrew Davis April 4, 2024, 6:22 p.m. UTC | #1
On 3/26/24 4:34 AM, Sébastien Szymanski wrote:
> The NFS protocol uses file handles to refer to file or directory.
> In NFSv2 file handles have a fixed size of 32 bytes.
> In NFSv3 file handles have a variable length up to 64 bytes. This is
> also true for the MOUNT protocol. [1]
> When the NFSv3 server replies with a file handle length > 32 bytes, U-Boot
> only copies 32 bytes of that file handle and the next LOOKUP Call fails:
> 
> BIOS> nfs ${loadaddr} 192.168.1.51:/nfsroot/opos93dev-br/boot/Image
> Using ethernet@428a0000 device
> File transfer via NFS from server 192.168.1.51; our IP address is 192.168.1.133
> Filename '/nfsroot/opos93dev-br/boot/Image'.
> Load address: 0x80400000
> Loading: *** ERROR: File lookup fail
> 
> done
> BIOS>
> 
> Looking at this transfer in Wireshark, we can see that the server
> replies with the following file handle:
> 
>      length: 36
>      [hash (CRC-32): 0x230ac67b]
>      FileHandle: 0100070101005e000000000091763911f87c449fa73c298552db19ba0c9f60002980cfd2
> 
> and U-Boot sends the following file handle in the next LOOKUP Call:
> 
>      length: 32
>      [hash (CRC-32): 0x6314131b]
>      FileHandle: 000000240100070101005e000000000091763911f87c449fa73c298552db19ba
> 
> Fix this by using a variable length file handle for dirfh.
> 
> [1] https://www.rfc-editor.org/rfc/rfc1813.html#page-106
> 
> Fixes: b0baca982048 ("net: NFS: Add NFSv3 support")
> Signed-off-by: Sébastien Szymanski <sebastien.szymanski@armadeus.com>
> ---

Fixes NFS boot for me, thanks!

Tested-by: Andrew Davis <afd@ti.com>

>   net/nfs.c | 18 +++++++++++++-----
>   1 file changed, 13 insertions(+), 5 deletions(-)
> 
> diff --git a/net/nfs.c b/net/nfs.c
> index 7a8887ef2368..c18282448ccd 100644
> --- a/net/nfs.c
> +++ b/net/nfs.c
> @@ -57,7 +57,8 @@ static int nfs_offset = -1;
>   static int nfs_len;
>   static const ulong nfs_timeout = CONFIG_NFS_TIMEOUT;
>   
> -static char dirfh[NFS_FHSIZE];	/* NFSv2 / NFSv3 file handle of directory */
> +static char dirfh[NFS3_FHSIZE]; /* NFSv2 / NFSv3 file handle of directory */
> +static unsigned int dirfh3_length; /* (variable) length of dirfh when NFSv3 */
>   static char filefh[NFS3_FHSIZE]; /* NFSv2 / NFSv3 file handle */
>   static unsigned int filefh3_length;	/* (variable) length of filefh when NFSv3 */
>   
> @@ -377,9 +378,9 @@ static void nfs_lookup_req(char *fname)
>   
>   		rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
>   	} else {  /* NFS_V3 */
> -		*p++ = htonl(NFS_FHSIZE);	/* Dir handle length */
> -		memcpy(p, dirfh, NFS_FHSIZE);
> -		p += (NFS_FHSIZE / 4);
> +		*p++ = htonl(dirfh3_length);	/* Dir handle length */
> +		memcpy(p, dirfh, dirfh3_length);
> +		p += (dirfh3_length / 4);
>   		*p++ = htonl(fnamelen);
>   		if (fnamelen & 3)
>   			*(p + fnamelen / 4) = 0;
> @@ -565,7 +566,14 @@ static int nfs_mount_reply(uchar *pkt, unsigned len)
>   
>   	fs_mounted = 1;
>   	/*  NFSv2 and NFSv3 use same structure */
> -	memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
> +	if (choosen_nfs_version != NFS_V3) {
> +		memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
> +	} else {
> +		dirfh3_length = ntohl(rpc_pkt.u.reply.data[1]);
> +		if (dirfh3_length > NFS3_FHSIZE)
> +			dirfh3_length  = NFS3_FHSIZE;
> +		memcpy(dirfh, rpc_pkt.u.reply.data + 2, dirfh3_length);
> +	}
>   
>   	return 0;
>   }
Tom Rini April 10, 2024, 5:43 p.m. UTC | #2
On Tue, 26 Mar 2024 10:34:31 +0100, Sébastien Szymanski wrote:

> The NFS protocol uses file handles to refer to file or directory.
> In NFSv2 file handles have a fixed size of 32 bytes.
> In NFSv3 file handles have a variable length up to 64 bytes. This is
> also true for the MOUNT protocol. [1]
> When the NFSv3 server replies with a file handle length > 32 bytes, U-Boot
> only copies 32 bytes of that file handle and the next LOOKUP Call fails:
> 
> [...]

Applied to u-boot/master, thanks!
diff mbox series

Patch

diff --git a/net/nfs.c b/net/nfs.c
index 7a8887ef2368..c18282448ccd 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -57,7 +57,8 @@  static int nfs_offset = -1;
 static int nfs_len;
 static const ulong nfs_timeout = CONFIG_NFS_TIMEOUT;
 
-static char dirfh[NFS_FHSIZE];	/* NFSv2 / NFSv3 file handle of directory */
+static char dirfh[NFS3_FHSIZE]; /* NFSv2 / NFSv3 file handle of directory */
+static unsigned int dirfh3_length; /* (variable) length of dirfh when NFSv3 */
 static char filefh[NFS3_FHSIZE]; /* NFSv2 / NFSv3 file handle */
 static unsigned int filefh3_length;	/* (variable) length of filefh when NFSv3 */
 
@@ -377,9 +378,9 @@  static void nfs_lookup_req(char *fname)
 
 		rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
 	} else {  /* NFS_V3 */
-		*p++ = htonl(NFS_FHSIZE);	/* Dir handle length */
-		memcpy(p, dirfh, NFS_FHSIZE);
-		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(dirfh3_length);	/* Dir handle length */
+		memcpy(p, dirfh, dirfh3_length);
+		p += (dirfh3_length / 4);
 		*p++ = htonl(fnamelen);
 		if (fnamelen & 3)
 			*(p + fnamelen / 4) = 0;
@@ -565,7 +566,14 @@  static int nfs_mount_reply(uchar *pkt, unsigned len)
 
 	fs_mounted = 1;
 	/*  NFSv2 and NFSv3 use same structure */
-	memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+	if (choosen_nfs_version != NFS_V3) {
+		memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+	} else {
+		dirfh3_length = ntohl(rpc_pkt.u.reply.data[1]);
+		if (dirfh3_length > NFS3_FHSIZE)
+			dirfh3_length  = NFS3_FHSIZE;
+		memcpy(dirfh, rpc_pkt.u.reply.data + 2, dirfh3_length);
+	}
 
 	return 0;
 }