Hi,
attached is a patch for a 0-day NMU.

Cheers
Nico

-- 
Nico Golde - http://www.ngolde.de - n...@jabber.ccc.de - GPG: 0xA0A0AAAA
For security reasons, all text in this mail is double-rot13 encrypted.
diff -u ctorrent-1.3.4-dnh3.2/debian/changelog ctorrent-1.3.4-dnh3.2/debian/changelog
--- ctorrent-1.3.4-dnh3.2/debian/changelog
+++ ctorrent-1.3.4-dnh3.2/debian/changelog
@@ -1,3 +1,11 @@
+ctorrent (1.3.4-dnh3.2-1.1) unstable; urgency=high
+
+  * Non-maintainer upload by the Security Team.
+  * Fix stack-based buffer overflow via crafted path names
+    in torrent files (CVE-2009-1759; Closes: #530255).
+
+ -- Nico Golde <n...@debian.org>  Wed, 17 Jun 2009 00:59:49 +0200
+
 ctorrent (1.3.4-dnh3.2-1) unstable; urgency=low
 
   * New upstream release.
only in patch2:
unchanged:
--- ctorrent-1.3.4-dnh3.2.orig/btcontent.cpp
+++ ctorrent-1.3.4-dnh3.2/btcontent.cpp
@@ -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;
only in patch2:
unchanged:
--- ctorrent-1.3.4-dnh3.2.orig/bencode.cpp
+++ ctorrent-1.3.4-dnh3.2/bencode.cpp
@@ -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);
only in patch2:
unchanged:
--- ctorrent-1.3.4-dnh3.2.orig/btfiles.cpp
+++ ctorrent-1.3.4-dnh3.2/btfiles.cpp
@@ -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;
 }
 
 
only in patch2:
unchanged:
--- ctorrent-1.3.4-dnh3.2.orig/bencode.h
+++ ctorrent-1.3.4-dnh3.2/bencode.h
@@ -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);
only in patch2:
unchanged:
--- ctorrent-1.3.4-dnh3.2.orig/btfiles.h
+++ ctorrent-1.3.4-dnh3.2/btfiles.h
@@ -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; }

Attachment: pgp37ON7JvLH9.pgp
Description: PGP signature

Reply via email to