You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
11 KiB

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