1 Patch for CVE-2009-1759.
2 Source: Upstream SVN, rev 302 from the dtorrent-3 branch.
5 ===================================================================
6 --- a/bencode.h (revision 300)
7 +++ b/bencode.h (revision 302)
9 size_t decode_list(const char *b,size_t len,const char *keylist);
10 size_t decode_rev(const char *b,size_t len,const char *keylist);
11 size_t decode_query(const char *b,size_t len,const char *keylist,const char **ps,size_t *pi,int64_t *pl,int method);
12 -size_t decode_list2path(const char *b, size_t n, char *pathname);
13 +size_t decode_list2path(const char *b, size_t n, char *pathname, size_t maxlen);
14 size_t bencode_buf(const char *str,size_t len,FILE *fp);
15 size_t bencode_str(const char *str, FILE *fp);
16 size_t bencode_int(const uint64_t integer, FILE *fp);
18 ===================================================================
19 --- a/bencode.cpp (revision 300)
20 +++ b/bencode.cpp (revision 302)
22 return bencode_end_dict_list(fp);
25 -size_t decode_list2path(const char *b, size_t n, char *pathname)
26 +size_t decode_list2path(const char *b, size_t n, char *pathname, size_t maxlen)
29 const char *s = (char *) 0;
30 + const char *endmax = pathname + maxlen - 1;
33 if( 'l' != *pb ) return 0;
38 + while( n && pathname < endmax ){
39 if(!(r = buf_str(pb, n, &s, &q)) ) return 0;
40 + if( q >= maxlen ) return 0;
41 memcpy(pathname, s, q);
44 - if( 'e' != *pb ){*pathname = PATH_SP, pathname++;} else break;
48 + if( 'e' == *pb ) break;
49 + if( pathname >= endmax ) return 0;
50 + *pathname++ = PATH_SP;
55 ===================================================================
56 --- a/btfiles.cpp (revision 300)
57 +++ b/btfiles.cpp (revision 302)
62 -int btFiles::BuildFromMI(const char *metabuf, const size_t metabuf_len, const char *saveas)
63 +int btFiles::BuildFromMI(const char *metabuf, const size_t metabuf_len,
64 + const char *saveas, unsigned char exam_only)
66 char path[MAXPATHLEN];
71 if( !decode_query(metabuf, metabuf_len, "info|name", &s, &q, (int64_t*)0,
72 - QUERY_STR) || MAXPATHLEN <= q )
73 + QUERY_STR) || MAXPATHLEN <= q ){
81 + (PATH_SP == path[0] || '/' == path[0] || 0==strncmp("..", path, 2)) ){
82 + CONSOLE.Warning(1, "error, unsafe path \"%s\" in torrent data", path);
87 r = decode_query(metabuf, metabuf_len, "info|files", (const char**)0, &q,
88 (int64_t*)0, QUERY_POS);
90 BTFILE *pbf_last = (BTFILE*) 0;
91 BTFILE *pbf = (BTFILE*) 0;
93 + unsigned long nfiles = 0;
95 if( decode_query(metabuf,metabuf_len,"info|length",
96 - (const char**) 0,(size_t*) 0,(int64_t*) 0,QUERY_LONG) )
97 + (const char**) 0,(size_t*) 0,(int64_t*) 0,QUERY_LONG) ){
103 m_directory = new char[strlen(saveas) + 1];
105 - if(!m_directory) return -1;
106 + if( !m_directory ){
111 strcpy(m_directory,saveas);
114 char *tmpfn = new char[strlen(path)*2+5];
116 - if( !tmpfn ) return -1;
122 if( f_conv = ConvertFilename(tmpfn, path, strlen(path)*2+5) ){
123 if( arg_flg_convert_filenames ){
133 if( !f_conv || !arg_flg_convert_filenames ){
134 m_directory = new char[strlen(path) + 1];
136 - if( !m_directory ) return -1;
137 + if( !m_directory ){
142 strcpy(m_directory,path);
144 @@ -517,24 +540,50 @@
147 for(; q && 'e' != *p; p += dl, q -= dl){
148 - if(!(dl = decode_dict(p, q, (const char*) 0)) ) return -1;
149 - if( !decode_query(p, dl, "length", (const char**) 0,
150 - (size_t*) 0,&t,QUERY_LONG) ) return -1;
151 + if( !(dl = decode_dict(p, q, (const char*) 0)) ||
152 + !decode_query(p, dl, "length", (const char**) 0, (size_t*) 0, &t,
159 - if( !pbf ) return -1;
167 m_total_files_length += t;
168 r = decode_query(p, dl, "path", (const char **)0, &n, (int64_t*)0,
170 - if( !r ) return -1;
171 - if(!decode_list2path(p + r, n, path)) return -1;
172 + if( !r || !decode_list2path(p + r, n, path, sizeof(path)) ){
174 + "error, invalid path in torrent data for file %lu at offset %llu",
175 + nfiles, m_total_files_length - t);
181 + (PATH_SP == path[0] || '/' == path[0] || 0==strncmp("..", path, 2)) ){
183 + "error, unsafe path \"%s\" in torrent data for file %lu",
192 char *tmpfn = new char[strlen(path)*2+5];
194 - if( !tmpfn ) return -1;
200 if( f_conv = ConvertFilename(tmpfn, path, strlen(path)*2+5) ){
201 if( arg_flg_convert_filenames ){
204 if( !pbf->bf_filename ){
211 if( !f_conv || !arg_flg_convert_filenames ){
212 pbf->bf_filename = new char[strlen(path) + 1];
214 - if( !pbf->bf_filename ) return -1;
215 + if( !pbf->bf_filename ){
220 strcpy(pbf->bf_filename, path);
222 @@ -564,30 +617,42 @@
226 - if( !decode_query(metabuf,metabuf_len,"info|length",
227 - (const char**) 0,(size_t*) 0,&t,QUERY_LONG) )
228 + if( !decode_query(metabuf,metabuf_len, "info|length",
229 + (const char**)0, (size_t*) 0, &t, QUERY_LONG) ){
233 m_btfhead = _new_bfnode();
235 - if( !m_btfhead) return -1;
241 m_btfhead->bf_length = m_total_files_length = t;
243 m_btfhead->bf_filename = new char[strlen(saveas) + 1];
245 - if(!m_btfhead->bf_filename ) return -1;
246 + if( !m_btfhead->bf_filename ){
251 strcpy(m_btfhead->bf_filename, saveas);
252 }else if( arg_flg_convert_filenames ){
253 char *tmpfn = new char[strlen(path)*2+5];
255 - if( !tmpfn ) return -1;
261 ConvertFilename(tmpfn, path, strlen(path)*2+5);
262 m_btfhead->bf_filename = new char[strlen(tmpfn) + 1];
264 if( !m_btfhead->bf_filename ){
272 m_btfhead->bf_filename = new char[strlen(path) + 1];
274 - if(!m_btfhead->bf_filename ) return -1;
275 + if( !m_btfhead->bf_filename ){
280 strcpy(m_btfhead->bf_filename, path);
283 size_t btFiles::FillMetaInfo(FILE* fp)
286 + const char *refname, *s;
287 + char path[MAXPATHLEN];
289 + refname = m_directory ? m_directory : m_btfhead->bf_filename;
290 + while( (s = strchr(refname, PATH_SP)) && *(s + 1) ){
293 + if( m_directory && '.' == *refname ){
294 + char dir[MAXPATHLEN];
295 + if( getcwd(dir, sizeof(dir)) && 0==chdir(m_directory) ){
296 + if( getcwd(path, sizeof(path)) ){
298 + while( (s = strchr(refname, PATH_SP)) && *(s + 1) ){
305 + if( '/' == *refname || '\0' == *refname || '.' == *refname ){
306 + CONSOLE.Warning(1, "error, inappropriate file or directory name \"%s\"",
307 + m_directory ? m_directory : m_btfhead->bf_filename);
314 if( bencode_str("files", fp) != 1 ) return 0;
315 @@ -715,16 +809,15 @@
316 if(bencode_end_dict_list(fp) != 1 ) return 0;
318 if(bencode_str("name", fp) != 1) return 0;
319 - return bencode_str(m_directory, fp);
321 + return bencode_str(refname, fp);
323 if( bencode_str("length", fp) != 1 ) return 0;
324 if( bencode_int(m_btfhead->bf_length, fp) != 1) return 0;
326 if( bencode_str("name", fp) != 1 ) return 0;
327 - return bencode_str(m_btfhead->bf_filename, fp);
328 + return bencode_str(refname, fp);
335 Index: a/btcontent.cpp
336 ===================================================================
337 --- a/btcontent.cpp (revision 300)
338 +++ b/btcontent.cpp (revision 302)
341 cfg_req_queue_length = (m_piece_length / cfg_req_slice_size) * 2 - 1;
343 - if( m_btfiles.BuildFromMI(b, flen, saveas) < 0 ) ERR_RETURN();
344 + if( m_btfiles.BuildFromMI(b, flen, saveas, arg_flg_exam_only) < 0 ){
345 + if( EINVAL == errno )
346 + CONSOLE.Warning(1, "Torrent metainfo file data is invalid or unusable.");
353 ===================================================================
354 --- a/btfiles.h (revision 300)
355 +++ b/btfiles.h (revision 302)
358 int BuildFromFS(const char *pathname);
359 int BuildFromMI(const char *metabuf, const size_t metabuf_len,
360 - const char *saveas);
361 + const char *saveas, unsigned char exam_only);
363 char *GetDataName() const;
364 uint64_t GetTotalLength() const { return m_total_files_length; }