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; }
pgp37ON7JvLH9.pgp
Description: PGP signature