[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Bug in FTP/FTPD [PATCH supplied]



Hi!

I found that both ftp and ftpd in kth-krb4 had a problem when
transferring a large file (larger than 0x1000000 bytes on my FreeBSD
system. The size of the file was truncated to a 32 bit quantity.

It turned out that it tried to mmap the file but the mmap only takes a
32 bit argument as the size but the file was larger than that. The
attaced patches correct this and if the file is larger than 0xffffffff
bytes the ordinary read/write loop is used.

I believe it is the same ftp/ftpd program in Heimdal and KTH-KRB
therefore cc: to heimdal list.

/thn

-- 
---------------------------------------------------------------
Svensk Aktuell Elektronik AB                     Thomas Nyström
Box 10                                    Phone: +46 8 35 92 85
S-191 21  Sollentuna                     Fax: +46 8 59 47 45 36
Sweden                                      Email: thn@saeab.se
---------------------------------------------------------------
--- org/ftpd/ftpd.c	Thu Sep 13 11:17:14 2001
+++ ftpd/ftpd.c	Thu Oct  3 10:12:41 2002
@@ -1399,8 +1399,13 @@
 		char *chunk;
 		int in = fileno(instr);
 		if(fstat(in, &st) == 0 && S_ISREG(st.st_mode) 
-		   && st.st_size > 0) {
+		   && st.st_size > 0 && st.st_size <= 0xffffffffL) {
 		    /*
+		     * On some systems st.st_size is 64 bits and mmap size
+		     * (second argument is 32 bits. If a large file is to
+		     * be transmitted the size of the file would be truncated.
+		     * Use ordinary read/write for such a file.
+		     *
 		     * mmap zero bytes has potential of loosing, don't do it.
 		     */
 		    chunk = mmap(0, st.st_size, PROT_READ,
--- org/ftp/ftp.c	Fri Sep  7 22:28:10 2001
+++ ftp/ftp.c	Thu Oct  3 11:51:45 2002
@@ -575,15 +575,23 @@
 	 */
 	if (st.st_size == 0)
 	    return 0;
-	chunk = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fileno (from), 0);
-	if (chunk != (void *) MAP_FAILED) {
-	    int res;
+	/*
+	 * On some systems st.st_size is 64 bits and mmap size (second
+	 * argument) is 32 bits. If a large file is to be transmitted
+	 * the size of the file would be truncated.
+	 * Use ordinary read/write for such a file.
+	 */
+	if (st.st_size <= 0xffffffffL) {
+	    chunk = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fileno (from), 0);
+	    if (chunk != (void *) MAP_FAILED) {
+	        int res;
 
-	    res = sec_write (fileno (to), chunk, st.st_size);
-	    if (munmap (chunk, st.st_size) < 0)
-		warn ("munmap");
-	    sec_fflush (to);
-	    return res;
+		res = sec_write (fileno (to), chunk, st.st_size);
+		if (munmap (chunk, st.st_size) < 0)
+		    warn ("munmap");
+		sec_fflush (to);
+		return res;
+	    }
 	}
     }
 #endif