TalAloni / SMBLibrary

Free, Open Source, User-Mode SMB 1.0/CIFS, SMB 2.0, SMB 2.1 and SMB 3.0 server and client library
GNU Lesser General Public License v3.0
712 stars 182 forks source link

Issue not receiving ReadResponse when reading a file #239

Closed kra5alllez closed 6 months ago

kra5alllez commented 8 months ago

Hello

Thank you very much for your work on this library.

I faced a problem with the library when working with a file larger than 131075.

I'm working with port 445. I added additional logging to understand what was wrong and this is what socket data I have: Socket.SendBufferSize: 131072, Socket.ReceiveBufferSize: 131072

And the data that I receive in NegotiateResponse: MaxTransactSize: 65536, MaxReadSize: 1048576, MaxWriteSize: 1048576, SecurityBuffer: 114 Capabilities: DFS, Leasing, LargeMTU, MultiChannel, PersistentHandles, Encryption

When executing clientSocket.BeginReceive, the following data is transferred there: buffer.Buffer: 131075; buffer.WriteOffset: 0; buffer.AvailableLength: 131075.

When reading a file larger than 131075 I have this order of calls:

The second response arrives in the OnClientSocketReceive method:

And then an error occurs because the command was not added to the queue.

Is there a problem with the share settings I’m working with or is the hardcoded number 131075 in the library larger than the MaxTransactSize that the share gives? Or is the problem something else?

TalAloni commented 8 months ago

Hi, Which version of the library? Did you make any modifications to the source code? Could you provide a WireShark packet capture please?

TalAloni commented 8 months ago

(MaxTransactSize is related to named pipe operations BTW - not to file operations)

kra5alllez commented 8 months ago

There were no changes to the source code. Library version 1.5.0.3 I'll provide WireShark packet capture a little later.

As far as I can see, the MaxTransactSize value sets the receiveBuffer.

But since the library sets the default value to 131075, the response value of 65536 cannot become the buffer size since it is less than the default. image

TalAloni commented 8 months ago

Sorry, my confusion regarding MaxTransactSize. Having a buffer larger than the necessary size is not an issue.

(BTW Visual Studio should show you the original variable names - as the PDB is embedded in the DLL - not sure why the code is decompiled at your print-screen)

Waiting for packet capture.

kra5alllez commented 8 months ago

I apologize, but I am unable to provide the WireShark packet capture. Could you please let me know what exact information from the packet you need to identify the issue? I can provide specific details upon your request.

I didn't cut the lines, nothing happens after the last read response. image_2024-01-12_18-24-47

TalAloni commented 8 months ago

I'm sorry - but I cannot learn anything significant from the print-screen you provided. Without a packet-capture demonstrating the entire communication from the negotiation process there isn't much I can go on. If you're concerned about data leakage (username & etc.) - you can always set up a dummy account for the purposes of demonstrating the issue.

kra5alllez commented 8 months ago

Sorry for the long reply, I was investigating the library code and debugging it. And I think I found a problem in the library.

First of all, I am wondering why you use MaxTransactSize to set the ReceiveBuffer value?

image

I think that you need to use the maximum value from these two values MaxTransactSize, and MaxReadSize.

Here's how I came to these conclusions:

on NegotiateResponse I get this data image

since MaxTransact Size = 65536, the condition is not met

if (4 + 65536  + 256 > 131075)
{
     state.ReceiveBuffer.IncreaseBufferSize(maxPacketSize);
}

Because of this, for all subsequent requests to the file share, the buffer is limited to 131075.

When it comes to the read request, we use MaxReadSize to specify the length

image

As a result, we get more data than the buffer can process, because the buffer is equal to the default number 131075 and this is less than the size of the read requested data 1048576.

I added this fix to the code, and after that everything worked fine.

image

TalAloni commented 8 months ago

Thanks for the update Oleksandr.

I based this logic on the following statement in MS-SMB2: 3.2.5.1 "If the message size received exceeds Connection.MaxTransactSize, the client MUST disconnect the connection"

I've seen there is the following remark in the specs: <22> "Windows clients do not enforce the MaxTransactSize value"

Can you please provide details on the Server you are using? Also, if you can find backing in the specification for the suggested change - that would be helpful. Thanks!

kra5alllez commented 8 months ago

I'm using Windows Server 2019

I have read the documentation and as far as I understand from this quote:

MaxTransactSize (4 bytes): The maximum size, in bytes, of the buffer that can be used for QUERY_INFO, QUERY_DIRECTORY, SET_INFO and CHANGE_NOTIFY operations. This field is applicable only for buffers sent by the client in SET_INFO requests, or returned from the server in QUERY_INFO, QUERY_DIRECTORY, and CHANGE_NOTIFY responses.

that MaxTransactSize only affects QUERY_INFO, QUERY_DIRECTORY, SET_INFO and CHANGE_NOTIFY operations. In my case, there are no problems with this type of operation, the buffer size for them does not exceed the MaxTransactSize value and no errors occur.

I still think the issue is in the method: Socket.BeginReceive (byte[] buffer, int offset, int size...

Because the buffer and size values must be large enough for the received data. Data size for ReadRequest = MaxReadSize = 1048576, which is larger than the default buffer size SessionPacket.MaxSessionPacketLength = 131075.

I don’t see any contradictions between those parts of the documentation that you indicated and what I described.

TalAloni commented 8 months ago

Thanks, I requested a clarification from Microsoft

Edit: Reposted at the right forum: https://learn.microsoft.com/en-us/answers/questions/1522049/(ms-smb2)-clarification-regarding-the-relationship

TalAloni commented 7 months ago

I have installed Windows Server 2019 and My NegotiateResponse is as follows: Max Transaction Size: 8388608 Max Read Size: 8388608 Max Write Size: 8388608

Please provide a packet capture demonstrating that you get different values.

kra5alllez commented 7 months ago

I apologize for my mistake. I mistakenly thought that the file share was on Windows Server 2019, but it's actually on Linux.

I requested a clarification from Microsoft.

Their response was that:

There is no requirement that MaxTransactSize and MaxReadSize be the same. The number chosen is based on the internal details of the platform and file system on which SMB server is implemented. Your server can choose its own numbers. Please consult MS-SMB2 for any limitation of maximum or minimum values to interoperate with Windows.

TalAloni commented 6 months ago

Waiting clarifications from Microsoft, sorry for the delay.

TalAloni commented 6 months ago

Sorry for the delay, so according to Microsoft:

the next updated spec is expected to read as following (change of MUST to SHOULD) 3.2.5.1 Receiving Any Message: "If the message size received exceeds Connection.MaxTransactSize, the client SHOULD disconnect the connection Our investigation did not show that Windows server using MaxReadSize smaller than MaxTransactSize.

So to me the issue seems to be with the Linux server, however it seems that Windows clients are more forgiving and the updated specifications will allow to be more forgiving without violating the specifications.

Given the above, I intend to make the requested change soon.

kra5alllez commented 6 months ago

Thanks for your assistance and cooperation! I believe it is important that we have figured out Microsoft specification.

When do you think it is possible to expect a new .nuget package version?

TalAloni commented 6 months ago

I've released 1.5.1.3 including this change.