branch Attitude Adjustment packages
[12.09/packages.git] / net / ctorrent / patches / 100-CVE-2009-1759.patch
1 Patch for CVE-2009-1759.
2 Source: Upstream SVN, rev 302 from the dtorrent-3 branch.
3
4 Index: a/bencode.h
5 ===================================================================
6 --- a/bencode.h (revision 300)
7 +++ b/bencode.h (revision 302)
8 @@ -25,7 +25,7 @@
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);
17 Index: a/bencode.cpp
18 ===================================================================
19 --- a/bencode.cpp       (revision 300)
20 +++ b/bencode.cpp       (revision 302)
21 @@ -233,22 +233,28 @@
22    return bencode_end_dict_list(fp);
23  }
24  
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)
27  {
28    const char *pb = b;
29    const char *s = (char *) 0;
30 +  const char *endmax = pathname + maxlen - 1;
31    size_t r,q;
32  
33    if( 'l' != *pb ) return 0;
34    pb++;
35    n--;
36    if( !n ) return 0;
37 -  for(; n;){
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);
42      pathname += q;
43 -    pb += r; n -= r; 
44 -    if( 'e' != *pb ){*pathname = PATH_SP, pathname++;} else break;
45 +    maxlen -= q;
46 +    pb += r;
47 +    n -= r; 
48 +    if( 'e' == *pb ) break;
49 +    if( pathname >= endmax ) return 0;
50 +    *pathname++ = PATH_SP;
51    }
52    *pathname = '\0';
53    return (pb - b + 1);
54 Index: a/btfiles.cpp
55 ===================================================================
56 --- a/btfiles.cpp       (revision 300)
57 +++ b/btfiles.cpp       (revision 302)
58 @@ -449,7 +449,8 @@
59    return 0;
60  }
61  
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)
65  {
66    char path[MAXPATHLEN];
67    const char *s, *p;
68 @@ -458,11 +459,19 @@
69    int f_warned = 0;
70  
71    if( !decode_query(metabuf, metabuf_len, "info|name", &s, &q, (int64_t*)0,
72 -      QUERY_STR) || MAXPATHLEN <= q )
73 +        QUERY_STR) || MAXPATHLEN <= q ){
74 +    errno = EINVAL;
75      return -1;
76 +  }
77  
78    memcpy(path, s, q);
79    path[q] = '\0';
80 +  if( !exam_only &&
81 +      (PATH_SP == path[0] || '/' == path[0] || 0==strncmp("..", path, 2)) ){
82 +    CONSOLE.Warning(1, "error, unsafe path \"%s\" in torrent data", path);
83 +    errno = EINVAL;
84 +    return -1;
85 +  }
86  
87    r = decode_query(metabuf, metabuf_len, "info|files", (const char**)0, &q,
88                     (int64_t*)0, QUERY_POS);
89 @@ -471,21 +480,31 @@
90      BTFILE *pbf_last = (BTFILE*) 0; 
91      BTFILE *pbf = (BTFILE*) 0;
92      size_t dl;
93 +    unsigned long nfiles = 0;
94 +
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) ){
98 +      errno = EINVAL;
99        return -1;
100 +    }
101  
102      if( saveas ){
103        m_directory = new char[strlen(saveas) + 1];
104  #ifndef WINDOWS
105 -      if(!m_directory) return -1;
106 +      if( !m_directory ){
107 +        errno = ENOMEM;
108 +        return -1;
109 +      }
110  #endif
111        strcpy(m_directory,saveas);
112      }else{
113        int f_conv;
114        char *tmpfn = new char[strlen(path)*2+5];
115  #ifndef WINDOWS
116 -      if( !tmpfn ) return -1;
117 +      if( !tmpfn ){
118 +        errno = ENOMEM;
119 +        return -1;
120 +      }
121  #endif
122        if( f_conv = ConvertFilename(tmpfn, path, strlen(path)*2+5) ){
123          if( arg_flg_convert_filenames ){
124 @@ -493,6 +512,7 @@
125  #ifndef WINDOWS
126            if( !m_directory ){
127              delete []tmpfn;
128 +            errno = ENOMEM;
129              return -1;
130            }
131  #endif
132 @@ -507,7 +527,10 @@
133        if( !f_conv || !arg_flg_convert_filenames ){
134          m_directory = new char[strlen(path) + 1];
135  #ifndef WINDOWS
136 -        if( !m_directory ) return -1;
137 +        if( !m_directory ){
138 +          errno = ENOMEM;
139 +          return -1;
140 +        }
141  #endif
142          strcpy(m_directory,path);
143        }
144 @@ -517,24 +540,50 @@
145      p = metabuf + r + 1; 
146      q--;
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,
153 +                        QUERY_LONG) ){
154 +        errno = EINVAL;
155 +        return -1;
156 +      }
157        pbf = _new_bfnode();
158  #ifndef WINDOWS
159 -      if( !pbf ) return -1;
160 +      if( !pbf ){
161 +        errno = ENOMEM;
162 +        return -1;
163 +      }
164  #endif
165 +      nfiles++;
166        pbf->bf_length = t;
167        m_total_files_length += t;
168        r = decode_query(p, dl, "path", (const char **)0, &n, (int64_t*)0,
169                         QUERY_POS);
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)) ){
173 +        CONSOLE.Warning(1,
174 +          "error, invalid path in torrent data for file %lu at offset %llu",
175 +          nfiles, m_total_files_length - t);
176 +        delete pbf;
177 +        errno = EINVAL;
178 +        return -1;
179 +      }
180 +      if( !exam_only &&
181 +          (PATH_SP == path[0] || '/' == path[0] || 0==strncmp("..", path, 2)) ){
182 +        CONSOLE.Warning(1,
183 +          "error, unsafe path \"%s\" in torrent data for file %lu",
184 +          path, nfiles);
185 +        delete pbf;
186 +        errno = EINVAL;
187 +        return -1;
188 +      }
189  
190 +
191        int f_conv;
192        char *tmpfn = new char[strlen(path)*2+5];
193  #ifndef WINDOWS
194 -      if( !tmpfn ) return -1;
195 +      if( !tmpfn ){
196 +        errno = ENOMEM;
197 +        return -1;
198 +      }
199  #endif
200        if( f_conv = ConvertFilename(tmpfn, path, strlen(path)*2+5) ){
201          if( arg_flg_convert_filenames ){
202 @@ -542,6 +591,7 @@
203  #ifndef WINDOWS
204            if( !pbf->bf_filename ){
205              delete []tmpfn;
206 +            errno = ENOMEM;
207              return -1;
208            }
209  #endif
210 @@ -556,7 +606,10 @@
211        if( !f_conv || !arg_flg_convert_filenames ){
212          pbf->bf_filename = new char[strlen(path) + 1];
213  #ifndef WINDOWS
214 -        if( !pbf->bf_filename ) return -1;
215 +        if( !pbf->bf_filename ){
216 +          errno = ENOMEM;
217 +          return -1;
218 +        }
219  #endif
220          strcpy(pbf->bf_filename, path);
221        }
222 @@ -564,30 +617,42 @@
223        pbf_last = pbf;
224      }
225    }else{
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) ){
230 +      errno = EINVAL;
231        return -1;
232 +    }
233      m_btfhead = _new_bfnode();
234  #ifndef WINDOWS
235 -    if( !m_btfhead) return -1;
236 +    if( !m_btfhead ){
237 +      errno = ENOMEM;
238 +      return -1;
239 +    }
240  #endif
241      m_btfhead->bf_length = m_total_files_length = t;
242      if( saveas ){
243        m_btfhead->bf_filename = new char[strlen(saveas) + 1];
244  #ifndef WINDOWS
245 -      if(!m_btfhead->bf_filename ) return -1;
246 +      if( !m_btfhead->bf_filename ){
247 +        errno = ENOMEM;
248 +        return -1;
249 +      }
250  #endif
251        strcpy(m_btfhead->bf_filename, saveas);
252      }else if( arg_flg_convert_filenames ){
253        char *tmpfn = new char[strlen(path)*2+5];
254  #ifndef WINDOWS
255 -      if( !tmpfn ) return -1;
256 +      if( !tmpfn ){
257 +        errno = ENOMEM;
258 +        return -1;
259 +      }
260  #endif
261        ConvertFilename(tmpfn, path, strlen(path)*2+5);
262        m_btfhead->bf_filename = new char[strlen(tmpfn) + 1];
263  #ifndef WINDOWS
264        if( !m_btfhead->bf_filename ){
265          delete []tmpfn;
266 +        errno = ENOMEM;
267          return -1;
268        }
269  #endif
270 @@ -596,7 +661,10 @@
271      }else{
272        m_btfhead->bf_filename = new char[strlen(path) + 1];
273  #ifndef WINDOWS
274 -      if(!m_btfhead->bf_filename ) return -1;
275 +      if( !m_btfhead->bf_filename ){
276 +        errno = ENOMEM;
277 +        return -1;
278 +      }
279  #endif
280        strcpy(m_btfhead->bf_filename, path);
281      }
282 @@ -694,6 +762,32 @@
283  size_t btFiles::FillMetaInfo(FILE* fp)
284  {
285    BTFILE *p;
286 +  const char *refname, *s;
287 +  char path[MAXPATHLEN];
288 +
289 +  refname = m_directory ? m_directory : m_btfhead->bf_filename;
290 +  while( (s = strchr(refname, PATH_SP)) && *(s + 1) ){
291 +    refname = s + 1;
292 +  }
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)) ){
297 +        refname = path;
298 +        while( (s = strchr(refname, PATH_SP)) && *(s + 1) ){
299 +          refname = s + 1;
300 +        }
301 +      }
302 +      chdir(dir);
303 +    }
304 +  }
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);
308 +    errno = EINVAL;
309 +    return 0;
310 +  }
311 +
312    if( m_directory ){
313      // multi files
314      if( bencode_str("files", fp) != 1 ) return 0;
315 @@ -715,16 +809,15 @@
316      if(bencode_end_dict_list(fp) != 1 ) return 0;
317      
318      if(bencode_str("name", fp) != 1) return 0;
319 -    return bencode_str(m_directory, fp);
320 -    
321 +    return bencode_str(refname, fp);
322    }else{
323      if( bencode_str("length", fp) != 1 ) return 0;
324      if( bencode_int(m_btfhead->bf_length, fp) != 1) return 0;
325      
326      if( bencode_str("name", fp) != 1 ) return 0;
327 -    return bencode_str(m_btfhead->bf_filename, fp);
328 +    return bencode_str(refname, fp);
329    }
330 -  return 1;
331 +  return 0;
332  }
333  
334  
335 Index: a/btcontent.cpp
336 ===================================================================
337 --- a/btcontent.cpp     (revision 300)
338 +++ b/btcontent.cpp     (revision 302)
339 @@ -357,7 +357,11 @@
340  
341    cfg_req_queue_length = (m_piece_length / cfg_req_slice_size) * 2 - 1;
342  
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.");
347 +    ERR_RETURN();
348 +  }
349  
350    delete []b;
351    b = (char *)0;
352 Index: a/btfiles.h
353 ===================================================================
354 --- a/btfiles.h (revision 300)
355 +++ b/btfiles.h (revision 302)
356 @@ -61,7 +61,7 @@
357    
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);
362  
363    char *GetDataName() const;
364    uint64_t GetTotalLength() const { return m_total_files_length; }