fclairamb / ftpserverlib

golang ftp server library
MIT License
424 stars 98 forks source link

Server gets stuck in a read loop when trying to upload a file named `testmgr.c` #495

Open Fornax96 opened 1 week ago

Fornax96 commented 1 week ago

Hi, I have a very weird problem. I noticed that sometimes my server would get stuck in a tight loop, burning 100% CPU. I finally found out what causes it.

I was uploading the linux kernel sources for testing and one particular file would cause the loop to happen: testmgr.c. I tried renaming the file, that fixes the issue. I also tried naming a different file to testmgr.c, that also causes the loop to happen. It doesn't matter what the contents of the file are, it also doesn't matter in which directory the file is stored. The problem triggers for all files with the name testmgr.c. There are probably other names which cause the issue to happen as well.

Here is exactly what I've observed:

Here is the code I'm using to break the loop:

var nn int
for n < len(buf) && err == nil {
    nn, err = r.Read(buf[n:])
    n += nn

    if nn == 0 && err == nil {
        loops++
        if loops >= 100 {
            log.Warn("readFull: Nothing was read, but there was no error either. Returning ErrUnexpectedEOF break the loop")
            return n, io.ErrUnexpectedEOF
        }
    } else {
        loops = 0
    }
}

Thank you.

EDIT: It also happens with files called maple.c, nls_cp949.c

drakkan commented 1 week ago

Hi,

thanks for reporting this issue. Can you please try to replicate the same with some established software that uses this library like ftpserver or SFTPGo? Thank you

Fornax96 commented 1 week ago

Your FTP server does not seem to have this issue.

A thought occurred to me: It could be a bug in the ReadFrom() usage. I disabled ReadFrom on my implementation and the transfer worked just fine. I'm going to look for the place where ftpserverlib uses ReadFrom to see if I can spot any problems.

Fornax96 commented 1 week ago

I can't figure out what the file name has to do with anything.. But when I try it the bug only occurs for those specific file names. Crazy. It's not a problem with my filesystem either, because when I try to upload the same file with HTTP it works fine, and that uses the same interface on the backend.

I installed logging to see what the reader returns, and it's only a few bytes per read. Usually between 10 and 50 bytes. My writer interface needs chunks of exactly 512 kiB to work. So I think the problem here is that both the reader and writer are not willing to let go of their alignment. I'll have to install some buffering inbetween.