add CVE-2009-1759 patch to ctorrent
authorPeter Wagner <​tripolar@gmx.at>
Mon, 11 Oct 2010 18:46:43 +0000 (18:46 +0000)
committerPeter Wagner <​tripolar@gmx.at>
Mon, 11 Oct 2010 18:46:43 +0000 (18:46 +0000)
for more info see
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-1759

SVN-Revision: 23403

net/ctorrent/patches/100-CVE-2009-1759.patch [new file with mode: 0644]

diff --git a/net/ctorrent/patches/100-CVE-2009-1759.patch b/net/ctorrent/patches/100-CVE-2009-1759.patch
new file mode 100644 (file)
index 0000000..f74bec8
--- /dev/null
@@ -0,0 +1,364 @@
+Patch for CVE-2009-1759.
+Source: Upstream SVN, rev 302 from the drorrent-3 branch.
+
+Index: a/bencode.h
+===================================================================
+--- a/bencode.h        (revision 300)
++++ b/bencode.h        (revision 302)
+@@ -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 uint64_t integer, FILE *fp);
+Index: a/bencode.cpp
+===================================================================
+--- a/bencode.cpp      (revision 300)
++++ b/bencode.cpp      (revision 302)
+@@ -233,22 +233,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;
++  const char *endmax = pathname + maxlen - 1;
+   size_t r,q;
+   if( 'l' != *pb ) return 0;
+   pb++;
+   n--;
+   if( !n ) return 0;
+-  for(; n;){
++  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);
+Index: a/btfiles.cpp
+===================================================================
+--- a/btfiles.cpp      (revision 300)
++++ b/btfiles.cpp      (revision 302)
+@@ -449,7 +449,8 @@
+   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, unsigned char exam_only)
+ {
+   char path[MAXPATHLEN];
+   const char *s, *p;
+@@ -458,11 +459,19 @@
+   int f_warned = 0;
+   if( !decode_query(metabuf, metabuf_len, "info|name", &s, &q, (int64_t*)0,
+-      QUERY_STR) || MAXPATHLEN <= q )
++        QUERY_STR) || MAXPATHLEN <= q ){
++    errno = EINVAL;
+     return -1;
++  }
+   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);
+@@ -471,21 +480,31 @@
+     BTFILE *pbf_last = (BTFILE*) 0; 
+     BTFILE *pbf = (BTFILE*) 0;
+     size_t dl;
++    unsigned long nfiles = 0;
++
+     if( decode_query(metabuf,metabuf_len,"info|length",
+-                    (const char**) 0,(size_t*) 0,(int64_t*) 0,QUERY_LONG) )
++                    (const char**) 0,(size_t*) 0,(int64_t*) 0,QUERY_LONG) ){
++      errno = EINVAL;
+       return -1;
++    }
+     if( saveas ){
+       m_directory = new char[strlen(saveas) + 1];
+ #ifndef WINDOWS
+-      if(!m_directory) return -1;
++      if( !m_directory ){
++        errno = ENOMEM;
++        return -1;
++      }
+ #endif
+       strcpy(m_directory,saveas);
+     }else{
+       int f_conv;
+       char *tmpfn = new char[strlen(path)*2+5];
+ #ifndef WINDOWS
+-      if( !tmpfn ) return -1;
++      if( !tmpfn ){
++        errno = ENOMEM;
++        return -1;
++      }
+ #endif
+       if( f_conv = ConvertFilename(tmpfn, path, strlen(path)*2+5) ){
+         if( arg_flg_convert_filenames ){
+@@ -493,6 +512,7 @@
+ #ifndef WINDOWS
+           if( !m_directory ){
+             delete []tmpfn;
++            errno = ENOMEM;
+             return -1;
+           }
+ #endif
+@@ -507,7 +527,10 @@
+       if( !f_conv || !arg_flg_convert_filenames ){
+         m_directory = new char[strlen(path) + 1];
+ #ifndef WINDOWS
+-        if( !m_directory ) return -1;
++        if( !m_directory ){
++          errno = ENOMEM;
++          return -1;
++        }
+ #endif
+         strcpy(m_directory,path);
+       }
+@@ -517,24 +540,50 @@
+     p = metabuf + r + 1; 
+     q--;
+     for(; q && 'e' != *p; p += dl, q -= dl){
+-      if(!(dl = decode_dict(p, q, (const char*) 0)) ) return -1;
+-      if( !decode_query(p, dl, "length", (const char**) 0,
+-                       (size_t*) 0,&t,QUERY_LONG) ) return -1;
++      if( !(dl = decode_dict(p, q, (const char*) 0)) ||
++          !decode_query(p, dl, "length", (const char**) 0, (size_t*) 0, &t,
++                        QUERY_LONG) ){
++        errno = EINVAL;
++        return -1;
++      }
+       pbf = _new_bfnode();
+ #ifndef WINDOWS
+-      if( !pbf ) return -1;
++      if( !pbf ){
++        errno = ENOMEM;
++        return -1;
++      }
+ #endif
++      nfiles++;
+       pbf->bf_length = t;
+       m_total_files_length += t;
+       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( !r || !decode_list2path(p + r, n, path, sizeof(path)) ){
++        CONSOLE.Warning(1,
++          "error, invalid path in torrent data for file %lu at offset %llu",
++          nfiles, m_total_files_length - t);
++        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, nfiles);
++        delete pbf;
++        errno = EINVAL;
++        return -1;
++      }
++
+       int f_conv;
+       char *tmpfn = new char[strlen(path)*2+5];
+ #ifndef WINDOWS
+-      if( !tmpfn ) return -1;
++      if( !tmpfn ){
++        errno = ENOMEM;
++        return -1;
++      }
+ #endif
+       if( f_conv = ConvertFilename(tmpfn, path, strlen(path)*2+5) ){
+         if( arg_flg_convert_filenames ){
+@@ -542,6 +591,7 @@
+ #ifndef WINDOWS
+           if( !pbf->bf_filename ){
+             delete []tmpfn;
++            errno = ENOMEM;
+             return -1;
+           }
+ #endif
+@@ -556,7 +606,10 @@
+       if( !f_conv || !arg_flg_convert_filenames ){
+         pbf->bf_filename = new char[strlen(path) + 1];
+ #ifndef WINDOWS
+-        if( !pbf->bf_filename ) return -1;
++        if( !pbf->bf_filename ){
++          errno = ENOMEM;
++          return -1;
++        }
+ #endif
+         strcpy(pbf->bf_filename, path);
+       }
+@@ -564,30 +617,42 @@
+       pbf_last = pbf;
+     }
+   }else{
+-    if( !decode_query(metabuf,metabuf_len,"info|length",
+-                     (const char**) 0,(size_t*) 0,&t,QUERY_LONG) )
++    if( !decode_query(metabuf,metabuf_len, "info|length",
++                      (const char**)0, (size_t*) 0, &t, QUERY_LONG) ){
++      errno = EINVAL;
+       return -1;
++    }
+     m_btfhead = _new_bfnode();
+ #ifndef WINDOWS
+-    if( !m_btfhead) return -1;
++    if( !m_btfhead ){
++      errno = ENOMEM;
++      return -1;
++    }
+ #endif
+     m_btfhead->bf_length = m_total_files_length = t;
+     if( saveas ){
+       m_btfhead->bf_filename = new char[strlen(saveas) + 1];
+ #ifndef WINDOWS
+-      if(!m_btfhead->bf_filename ) return -1;
++      if( !m_btfhead->bf_filename ){
++        errno = ENOMEM;
++        return -1;
++      }
+ #endif
+       strcpy(m_btfhead->bf_filename, saveas);
+     }else if( arg_flg_convert_filenames ){
+       char *tmpfn = new char[strlen(path)*2+5];
+ #ifndef WINDOWS
+-      if( !tmpfn ) return -1;
++      if( !tmpfn ){
++        errno = ENOMEM;
++        return -1;
++      }
+ #endif
+       ConvertFilename(tmpfn, path, strlen(path)*2+5);
+       m_btfhead->bf_filename = new char[strlen(tmpfn) + 1];
+ #ifndef WINDOWS
+       if( !m_btfhead->bf_filename ){
+         delete []tmpfn;
++        errno = ENOMEM;
+         return -1;
+       }
+ #endif
+@@ -596,7 +661,10 @@
+     }else{
+       m_btfhead->bf_filename = new char[strlen(path) + 1];
+ #ifndef WINDOWS
+-      if(!m_btfhead->bf_filename ) return -1;
++      if( !m_btfhead->bf_filename ){
++        errno = ENOMEM;
++        return -1;
++      }
+ #endif
+       strcpy(m_btfhead->bf_filename, path);
+     }
+@@ -694,6 +762,32 @@
+ 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;
+@@ -715,16 +809,15 @@
+     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;
+ }
+Index: a/btcontent.cpp
+===================================================================
+--- a/btcontent.cpp    (revision 300)
++++ b/btcontent.cpp    (revision 302)
+@@ -357,7 +357,11 @@
+   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, arg_flg_exam_only) < 0 ){
++    if( EINVAL == errno )
++      CONSOLE.Warning(1, "Torrent metainfo file data is invalid or unusable.");
++    ERR_RETURN();
++  }
+   delete []b;
+   b = (char *)0;
+Index: a/btfiles.h
+===================================================================
+--- a/btfiles.h        (revision 300)
++++ b/btfiles.h        (revision 302)
+@@ -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, unsigned char exam_only);
+   char *GetDataName() const;
+   uint64_t GetTotalLength() const { return m_total_files_length; }