Hi, I ported the patch to our ctorrent version. Could someone please test it so updates don't break things?
Cheers Nico -- Nico Golde - http://www.ngolde.de - [email protected] - GPG: 0xA0A0AAAA For security reasons, all text in this mail is double-rot13 encrypted.
diff -Nurad /tmp/ctorrent-1.3.4-dnh3.2/bencode.cpp ctorrent-1.3.4-dnh3.2/bencode.cpp
--- /tmp/ctorrent-1.3.4-dnh3.2/bencode.cpp 2009-06-15 19:08:31.000000000 +0200
+++ ctorrent-1.3.4-dnh3.2/bencode.cpp 2009-06-15 19:12:51.000000000 +0200
@@ -237,22 +237,28 @@
return bencode_end_dict_list(fp);
}
-size_t decode_list2path(const char *b, size_t n, char *pathname)
+size_t decode_list2path(const char *b, size_t n, char *pathname, size_t maxlen)
{
const char *pb = b;
- const char *s = (char *) 0;
- size_t r,q;
+ const char *s = (char *)0;
+ const char *endmax = pathname + maxlen - 1;
+ size_t r, q;
if( 'l' != *pb ) return 0;
pb++;
n--;
if( !n ) return 0;
- for(; n;){
- if(!(r = buf_str(pb, n, &s, &q)) ) return 0;
+ while( n && pathname < endmax ){
+ if( !(r = buf_str(pb, n, &s, &q)) ) return 0;
+ if( q >= maxlen ) return 0;
memcpy(pathname, s, q);
pathname += q;
- pb += r; n -= r;
- if( 'e' != *pb ){*pathname = PATH_SP, pathname++;} else break;
+ maxlen -= q;
+ pb += r;
+ n -= r;
+ if( 'e' == *pb ) break;
+ if( pathname >= endmax ) return 0;
+ *pathname++ = PATH_SP;
}
*pathname = '\0';
return (pb - b + 1);
diff -Nurad /tmp/ctorrent-1.3.4-dnh3.2/bencode.h ctorrent-1.3.4-dnh3.2/bencode.h
--- /tmp/ctorrent-1.3.4-dnh3.2/bencode.h 2007-08-02 20:42:13.000000000 +0200
+++ ctorrent-1.3.4-dnh3.2/bencode.h 2009-06-15 19:13:05.000000000 +0200
@@ -25,7 +25,7 @@
size_t decode_list(const char *b,size_t len,const char *keylist);
size_t decode_rev(const char *b,size_t len,const char *keylist);
size_t decode_query(const char *b,size_t len,const char *keylist,const char **ps,size_t *pi,int64_t *pl,int method);
-size_t decode_list2path(const char *b, size_t n, char *pathname);
+size_t decode_list2path(const char *b, size_t n, char *pathname, size_t maxlen);
size_t bencode_buf(const char *str,size_t len,FILE *fp);
size_t bencode_str(const char *str, FILE *fp);
size_t bencode_int(const int integer, FILE *fp);
diff -Nurad /tmp/ctorrent-1.3.4-dnh3.2/btcontent.cpp ctorrent-1.3.4-dnh3.2/btcontent.cpp
--- /tmp/ctorrent-1.3.4-dnh3.2/btcontent.cpp 2007-08-02 20:42:13.000000000 +0200
+++ ctorrent-1.3.4-dnh3.2/btcontent.cpp 2009-06-15 19:31:04.000000000 +0200
@@ -261,7 +261,7 @@
cfg_req_queue_length = (m_piece_length / cfg_req_slice_size) * 2 - 1;
- if( m_btfiles.BuildFromMI(b, flen, saveas) < 0 ) ERR_RETURN();
+ if( m_btfiles.BuildFromMI(b, flen, saveas, false) < 0 ) ERR_RETURN();
delete []b;
b = (char *)0;
diff -Nurad /tmp/ctorrent-1.3.4-dnh3.2/btfiles.cpp ctorrent-1.3.4-dnh3.2/btfiles.cpp
--- /tmp/ctorrent-1.3.4-dnh3.2/btfiles.cpp 2007-08-02 20:42:13.000000000 +0200
+++ ctorrent-1.3.4-dnh3.2/btfiles.cpp 2009-06-15 19:28:52.000000000 +0200
@@ -336,6 +336,7 @@
CONSOLE.Warning(1, "error, \"%s\" is not a directory or regular file.",
fn);
closedir(dp);
+ errno = EINVAL;
return -1;
}
} // end while
@@ -426,12 +427,13 @@
}else{
CONSOLE.Warning(1, "error, \"%s\" is not a directory or regular file.",
pathname);
+ errno = EINVAL;
return -1;
}
return 0;
}
-int btFiles::BuildFromMI(const char *metabuf, const size_t metabuf_len, const char *saveas)
+int btFiles::BuildFromMI(const char *metabuf, const size_t metabuf_len, const char *saveas, bool exam_only)
{
char path[MAXPATHLEN];
const char *s, *p;
@@ -446,6 +448,13 @@
memcpy(path, s, q);
path[q] = '\0';
+ if( !exam_only &&
+ (PATH_SP == path[0] || '/' == path[0] || 0==strncmp("..", path, 2)) ){
+ CONSOLE.Warning(1, "error, unsafe path \"%s\" in torrent data", path);
+ errno = EINVAL;
+ return -1;
+ }
+
r = decode_query(metabuf, metabuf_len, "info|files", (const char**)0, &q,
(int64_t*)0, QUERY_POS);
@@ -511,7 +520,20 @@
r = decode_query(p, dl, "path", (const char **)0, &n, (int64_t*)0,
QUERY_POS);
if( !r ) return -1;
- if(!decode_list2path(p + r, n, path)) return -1;
+ if(!decode_list2path(p + r, n, path, sizeof(path))){
+ CONSOLE.Warning(1, "error, invalid path in torrent data for file %lu",
+ (unsigned long)m_nfiles);
+ delete pbf;
+ errno = EINVAL;
+ return -1;
+ }
+ if( !exam_only && (PATH_SP == path[0] || '/' == path[0] || 0==strncmp("..", path, 2)) ){
+ CONSOLE.Warning(1, "error, unsafe path \"%s\" in torrent data for file %lu",
+ path, (unsigned long)m_nfiles);
+ delete pbf;
+ errno = EINVAL;
+ return -1;
+ }
int f_conv;
char *tmpfn = new char[strlen(path)*2+5];
@@ -613,22 +635,26 @@
}
if( !_btf_creat_by_path(fn,pbt->bf_length)){
CONSOLE.Warning(1, "error, create file \"%s\" failed.",fn);
+ errno = EINVAL;
return -1;
}
}else{
CONSOLE.Warning(1, "error, couldn't create file \"%s\": %s", fn,
strerror(errno));
+ errno = EINVAL;
return -1;
}
}else{
if( !check_exist) check_exist = 1;
if( !(S_IFREG & sb.st_mode) ){
CONSOLE.Warning(1, "error, file \"%s\" is not a regular file.", fn);
+ errno = EINVAL;
return -1;
}
if(sb.st_size != pbt->bf_length){
CONSOLE.Warning(1,"error, file \"%s\" size doesn't match; must be %llu",
fn, (unsigned long long)(pbt->bf_length));
+ errno = EINVAL;
return -1;
}
}
@@ -637,6 +663,7 @@
m_file = new BTFILE *[m_nfiles];
if( !m_file ){
CONSOLE.Warning(1, "error, failed to allocate memory for files list");
+ errno = ENOMEM;
return -1;
}
for( pbt = m_btfhead; pbt; pbt = pbt->bf_next ){
@@ -675,6 +702,31 @@
size_t btFiles::FillMetaInfo(FILE* fp)
{
BTFILE *p;
+ const char *refname, *s;
+ char path[MAXPATHLEN];
+
+ refname = m_directory ? m_directory : m_btfhead->bf_filename;
+ while( (s = strchr(refname, PATH_SP)) && *(s + 1) ){
+ refname = s + 1;
+ }
+ if( m_directory && '.' == *refname ){
+ char dir[MAXPATHLEN];
+ if( getcwd(dir, sizeof(dir)) && 0==chdir(m_directory) ){
+ if( getcwd(path, sizeof(path)) ){
+ refname = path;
+ while( (s = strchr(refname, PATH_SP)) && *(s + 1) ){
+ refname = s + 1;
+ }
+ }
+ chdir(dir);
+ }
+ }
+ if( '/' == *refname || '\0' == *refname || '.' == *refname ){
+ CONSOLE.Warning(1, "error, inappropriate file or directory name \"%s\"",
+ m_directory ? m_directory : m_btfhead->bf_filename);
+ errno = EINVAL;
+ return 0;
+ }
if( m_directory ){
// multi files
if( bencode_str("files", fp) != 1 ) return 0;
@@ -696,16 +748,16 @@
if(bencode_end_dict_list(fp) != 1 ) return 0;
if(bencode_str("name", fp) != 1) return 0;
- return bencode_str(m_directory, fp);
+ return bencode_str(refname, fp);
}else{
if( bencode_str("length", fp) != 1 ) return 0;
if( bencode_int(m_btfhead->bf_length, fp) != 1) return 0;
if( bencode_str("name", fp) != 1 ) return 0;
- return bencode_str(m_btfhead->bf_filename, fp);
+ return bencode_str(refname, fp);
}
- return 1;
+ return 0;
}
diff -Nurad /tmp/ctorrent-1.3.4-dnh3.2/btfiles.h ctorrent-1.3.4-dnh3.2/btfiles.h
--- /tmp/ctorrent-1.3.4-dnh3.2/btfiles.h 2007-08-02 20:42:13.000000000 +0200
+++ ctorrent-1.3.4-dnh3.2/btfiles.h 2009-06-15 19:25:03.000000000 +0200
@@ -61,7 +61,7 @@
int BuildFromFS(const char *pathname);
int BuildFromMI(const char *metabuf, const size_t metabuf_len,
- const char *saveas);
+ const char *saveas, bool exam_only);
char *GetDataName() const;
uint64_t GetTotalLength() const { return m_total_files_length; }
pgp4XXqkVPWhW.pgp
Description: PGP signature

