Fossil SCM
ASAN caught a misuse of memcmp when matching the subcommand for "fossil uv". Changed it to strncmp, as used in several other Fossil CLI subcommand matching bits. Since the left-side arg is user-supplied text and we were using its strlen() for the third argument to memcmp(), it allowed arbitrary amounts of overrun.
Commit
182cfa1b1d62b80f5a2b036356aaab84635b8a781712db0a681e66c313bbf07f
Parent
b1dc17a0aa7d3bc…
1 file changed
+11
-11
+11
-11
| --- src/unversioned.c | ||
| +++ src/unversioned.c | ||
| @@ -308,11 +308,11 @@ | ||
| 308 | 308 | mtime = time(0); |
| 309 | 309 | }else{ |
| 310 | 310 | mtime = db_int(0, "SELECT strftime('%%s',%Q)", zMtime); |
| 311 | 311 | if( mtime<=0 ) fossil_fatal("bad timestamp: %Q", zMtime); |
| 312 | 312 | } |
| 313 | - if( memcmp(zCmd, "add", nCmd)==0 ){ | |
| 313 | + if( strncmp(zCmd, "add", nCmd)==0 ){ | |
| 314 | 314 | const char *zError = 0; |
| 315 | 315 | const char *zIn; |
| 316 | 316 | const char *zAs; |
| 317 | 317 | Blob file; |
| 318 | 318 | int i; |
| @@ -340,11 +340,11 @@ | ||
| 340 | 340 | blob_read_from_file(&file, g.argv[i], ExtFILE); |
| 341 | 341 | unversioned_write(zIn, &file, mtime); |
| 342 | 342 | blob_reset(&file); |
| 343 | 343 | } |
| 344 | 344 | db_end_transaction(0); |
| 345 | - }else if( memcmp(zCmd, "cat", nCmd)==0 ){ | |
| 345 | + }else if( strncmp(zCmd, "cat", nCmd)==0 ){ | |
| 346 | 346 | int i; |
| 347 | 347 | verify_all_options(); |
| 348 | 348 | db_begin_transaction(); |
| 349 | 349 | for(i=3; i<g.argc; i++){ |
| 350 | 350 | Blob content; |
| @@ -352,11 +352,11 @@ | ||
| 352 | 352 | blob_write_to_file(&content, "-"); |
| 353 | 353 | } |
| 354 | 354 | blob_reset(&content); |
| 355 | 355 | } |
| 356 | 356 | db_end_transaction(0); |
| 357 | - }else if( memcmp(zCmd, "edit", nCmd)==0 ){ | |
| 357 | + }else if( strncmp(zCmd, "edit", nCmd)==0 ){ | |
| 358 | 358 | const char *zEditor; /* Name of the text-editor command */ |
| 359 | 359 | const char *zTFile; /* Temporary file */ |
| 360 | 360 | const char *zUVFile; /* Name of the unversioned file */ |
| 361 | 361 | char *zCmd; /* Command to run the text editor */ |
| 362 | 362 | Blob content; /* Content of the unversioned file */ |
| @@ -395,24 +395,24 @@ | ||
| 395 | 395 | file_delete(zTFile); |
| 396 | 396 | if( zMtime==0 ) mtime = time(0); |
| 397 | 397 | unversioned_write(zUVFile, &content, mtime); |
| 398 | 398 | db_end_transaction(0); |
| 399 | 399 | blob_reset(&content); |
| 400 | - }else if( memcmp(zCmd, "export", nCmd)==0 ){ | |
| 400 | + }else if( strncmp(zCmd, "export", nCmd)==0 ){ | |
| 401 | 401 | Blob content; |
| 402 | 402 | verify_all_options(); |
| 403 | 403 | if( g.argc!=5 ) usage("export UVFILE OUTPUT"); |
| 404 | 404 | if( unversioned_content(g.argv[3], &content)==0 ){ |
| 405 | 405 | fossil_fatal("no such uv-file: %Q", g.argv[3]); |
| 406 | 406 | } |
| 407 | 407 | blob_write_to_file(&content, g.argv[4]); |
| 408 | 408 | blob_reset(&content); |
| 409 | - }else if( memcmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */ | |
| 409 | + }else if( strncmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */ | |
| 410 | 410 | /* Show the hash value used during uv sync */ |
| 411 | 411 | int debugFlag = find_option("debug",0,0)!=0; |
| 412 | 412 | fossil_print("%s\n", unversioned_content_hash(debugFlag)); |
| 413 | - }else if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){ | |
| 413 | + }else if( strncmp(zCmd, "list", nCmd)==0 || strncmp(zCmd, "ls", nCmd)==0 ){ | |
| 414 | 414 | Stmt q; |
| 415 | 415 | int allFlag = find_option("all","a",0)!=0; |
| 416 | 416 | int longFlag = find_option("l",0,0)!=0 || (nCmd>1 && zCmd[1]=='i'); |
| 417 | 417 | char *zPattern = sqlite3_mprintf("true"); |
| 418 | 418 | const char *zGlob; |
| @@ -464,18 +464,18 @@ | ||
| 464 | 464 | ); |
| 465 | 465 | } |
| 466 | 466 | } |
| 467 | 467 | db_finalize(&q); |
| 468 | 468 | sqlite3_free(zPattern); |
| 469 | - }else if( memcmp(zCmd, "revert", nCmd)==0 ){ | |
| 469 | + }else if( strncmp(zCmd, "revert", nCmd)==0 ){ | |
| 470 | 470 | unsigned syncFlags = |
| 471 | 471 | unversioned_sync_flags(SYNC_UNVERSIONED|SYNC_UV_REVERT); |
| 472 | 472 | g.argv[1] = "sync"; |
| 473 | 473 | g.argv[2] = "--uv-noop"; |
| 474 | 474 | sync_unversioned(syncFlags); |
| 475 | - }else if( memcmp(zCmd, "remove", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 | |
| 476 | - || memcmp(zCmd, "delete", nCmd)==0 ){ | |
| 475 | + }else if( strncmp(zCmd, "remove", nCmd)==0 || strncmp(zCmd, "rm", nCmd)==0 | |
| 476 | + || strncmp(zCmd, "delete", nCmd)==0 ){ | |
| 477 | 477 | int i; |
| 478 | 478 | const char *zGlob; |
| 479 | 479 | db_begin_transaction(); |
| 480 | 480 | while( (zGlob = find_option("glob",0,1))!=0 ){ |
| 481 | 481 | db_multi_exec( |
| @@ -499,16 +499,16 @@ | ||
| 499 | 499 | mtime, g.argv[i] |
| 500 | 500 | ); |
| 501 | 501 | } |
| 502 | 502 | db_unset("uv-hash", 0); |
| 503 | 503 | db_end_transaction(0); |
| 504 | - }else if( memcmp(zCmd,"sync",nCmd)==0 ){ | |
| 504 | + }else if( strncmp(zCmd,"sync",nCmd)==0 ){ | |
| 505 | 505 | unsigned syncFlags = unversioned_sync_flags(SYNC_UNVERSIONED); |
| 506 | 506 | g.argv[1] = "sync"; |
| 507 | 507 | g.argv[2] = "--uv-noop"; |
| 508 | 508 | sync_unversioned(syncFlags); |
| 509 | - }else if( memcmp(zCmd, "touch", nCmd)==0 ){ | |
| 509 | + }else if( strncmp(zCmd, "touch", nCmd)==0 ){ | |
| 510 | 510 | int i; |
| 511 | 511 | verify_all_options(); |
| 512 | 512 | db_begin_transaction(); |
| 513 | 513 | for(i=3; i<g.argc; i++){ |
| 514 | 514 | db_multi_exec( |
| 515 | 515 |
| --- src/unversioned.c | |
| +++ src/unversioned.c | |
| @@ -308,11 +308,11 @@ | |
| 308 | mtime = time(0); |
| 309 | }else{ |
| 310 | mtime = db_int(0, "SELECT strftime('%%s',%Q)", zMtime); |
| 311 | if( mtime<=0 ) fossil_fatal("bad timestamp: %Q", zMtime); |
| 312 | } |
| 313 | if( memcmp(zCmd, "add", nCmd)==0 ){ |
| 314 | const char *zError = 0; |
| 315 | const char *zIn; |
| 316 | const char *zAs; |
| 317 | Blob file; |
| 318 | int i; |
| @@ -340,11 +340,11 @@ | |
| 340 | blob_read_from_file(&file, g.argv[i], ExtFILE); |
| 341 | unversioned_write(zIn, &file, mtime); |
| 342 | blob_reset(&file); |
| 343 | } |
| 344 | db_end_transaction(0); |
| 345 | }else if( memcmp(zCmd, "cat", nCmd)==0 ){ |
| 346 | int i; |
| 347 | verify_all_options(); |
| 348 | db_begin_transaction(); |
| 349 | for(i=3; i<g.argc; i++){ |
| 350 | Blob content; |
| @@ -352,11 +352,11 @@ | |
| 352 | blob_write_to_file(&content, "-"); |
| 353 | } |
| 354 | blob_reset(&content); |
| 355 | } |
| 356 | db_end_transaction(0); |
| 357 | }else if( memcmp(zCmd, "edit", nCmd)==0 ){ |
| 358 | const char *zEditor; /* Name of the text-editor command */ |
| 359 | const char *zTFile; /* Temporary file */ |
| 360 | const char *zUVFile; /* Name of the unversioned file */ |
| 361 | char *zCmd; /* Command to run the text editor */ |
| 362 | Blob content; /* Content of the unversioned file */ |
| @@ -395,24 +395,24 @@ | |
| 395 | file_delete(zTFile); |
| 396 | if( zMtime==0 ) mtime = time(0); |
| 397 | unversioned_write(zUVFile, &content, mtime); |
| 398 | db_end_transaction(0); |
| 399 | blob_reset(&content); |
| 400 | }else if( memcmp(zCmd, "export", nCmd)==0 ){ |
| 401 | Blob content; |
| 402 | verify_all_options(); |
| 403 | if( g.argc!=5 ) usage("export UVFILE OUTPUT"); |
| 404 | if( unversioned_content(g.argv[3], &content)==0 ){ |
| 405 | fossil_fatal("no such uv-file: %Q", g.argv[3]); |
| 406 | } |
| 407 | blob_write_to_file(&content, g.argv[4]); |
| 408 | blob_reset(&content); |
| 409 | }else if( memcmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */ |
| 410 | /* Show the hash value used during uv sync */ |
| 411 | int debugFlag = find_option("debug",0,0)!=0; |
| 412 | fossil_print("%s\n", unversioned_content_hash(debugFlag)); |
| 413 | }else if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){ |
| 414 | Stmt q; |
| 415 | int allFlag = find_option("all","a",0)!=0; |
| 416 | int longFlag = find_option("l",0,0)!=0 || (nCmd>1 && zCmd[1]=='i'); |
| 417 | char *zPattern = sqlite3_mprintf("true"); |
| 418 | const char *zGlob; |
| @@ -464,18 +464,18 @@ | |
| 464 | ); |
| 465 | } |
| 466 | } |
| 467 | db_finalize(&q); |
| 468 | sqlite3_free(zPattern); |
| 469 | }else if( memcmp(zCmd, "revert", nCmd)==0 ){ |
| 470 | unsigned syncFlags = |
| 471 | unversioned_sync_flags(SYNC_UNVERSIONED|SYNC_UV_REVERT); |
| 472 | g.argv[1] = "sync"; |
| 473 | g.argv[2] = "--uv-noop"; |
| 474 | sync_unversioned(syncFlags); |
| 475 | }else if( memcmp(zCmd, "remove", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 |
| 476 | || memcmp(zCmd, "delete", nCmd)==0 ){ |
| 477 | int i; |
| 478 | const char *zGlob; |
| 479 | db_begin_transaction(); |
| 480 | while( (zGlob = find_option("glob",0,1))!=0 ){ |
| 481 | db_multi_exec( |
| @@ -499,16 +499,16 @@ | |
| 499 | mtime, g.argv[i] |
| 500 | ); |
| 501 | } |
| 502 | db_unset("uv-hash", 0); |
| 503 | db_end_transaction(0); |
| 504 | }else if( memcmp(zCmd,"sync",nCmd)==0 ){ |
| 505 | unsigned syncFlags = unversioned_sync_flags(SYNC_UNVERSIONED); |
| 506 | g.argv[1] = "sync"; |
| 507 | g.argv[2] = "--uv-noop"; |
| 508 | sync_unversioned(syncFlags); |
| 509 | }else if( memcmp(zCmd, "touch", nCmd)==0 ){ |
| 510 | int i; |
| 511 | verify_all_options(); |
| 512 | db_begin_transaction(); |
| 513 | for(i=3; i<g.argc; i++){ |
| 514 | db_multi_exec( |
| 515 |
| --- src/unversioned.c | |
| +++ src/unversioned.c | |
| @@ -308,11 +308,11 @@ | |
| 308 | mtime = time(0); |
| 309 | }else{ |
| 310 | mtime = db_int(0, "SELECT strftime('%%s',%Q)", zMtime); |
| 311 | if( mtime<=0 ) fossil_fatal("bad timestamp: %Q", zMtime); |
| 312 | } |
| 313 | if( strncmp(zCmd, "add", nCmd)==0 ){ |
| 314 | const char *zError = 0; |
| 315 | const char *zIn; |
| 316 | const char *zAs; |
| 317 | Blob file; |
| 318 | int i; |
| @@ -340,11 +340,11 @@ | |
| 340 | blob_read_from_file(&file, g.argv[i], ExtFILE); |
| 341 | unversioned_write(zIn, &file, mtime); |
| 342 | blob_reset(&file); |
| 343 | } |
| 344 | db_end_transaction(0); |
| 345 | }else if( strncmp(zCmd, "cat", nCmd)==0 ){ |
| 346 | int i; |
| 347 | verify_all_options(); |
| 348 | db_begin_transaction(); |
| 349 | for(i=3; i<g.argc; i++){ |
| 350 | Blob content; |
| @@ -352,11 +352,11 @@ | |
| 352 | blob_write_to_file(&content, "-"); |
| 353 | } |
| 354 | blob_reset(&content); |
| 355 | } |
| 356 | db_end_transaction(0); |
| 357 | }else if( strncmp(zCmd, "edit", nCmd)==0 ){ |
| 358 | const char *zEditor; /* Name of the text-editor command */ |
| 359 | const char *zTFile; /* Temporary file */ |
| 360 | const char *zUVFile; /* Name of the unversioned file */ |
| 361 | char *zCmd; /* Command to run the text editor */ |
| 362 | Blob content; /* Content of the unversioned file */ |
| @@ -395,24 +395,24 @@ | |
| 395 | file_delete(zTFile); |
| 396 | if( zMtime==0 ) mtime = time(0); |
| 397 | unversioned_write(zUVFile, &content, mtime); |
| 398 | db_end_transaction(0); |
| 399 | blob_reset(&content); |
| 400 | }else if( strncmp(zCmd, "export", nCmd)==0 ){ |
| 401 | Blob content; |
| 402 | verify_all_options(); |
| 403 | if( g.argc!=5 ) usage("export UVFILE OUTPUT"); |
| 404 | if( unversioned_content(g.argv[3], &content)==0 ){ |
| 405 | fossil_fatal("no such uv-file: %Q", g.argv[3]); |
| 406 | } |
| 407 | blob_write_to_file(&content, g.argv[4]); |
| 408 | blob_reset(&content); |
| 409 | }else if( strncmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */ |
| 410 | /* Show the hash value used during uv sync */ |
| 411 | int debugFlag = find_option("debug",0,0)!=0; |
| 412 | fossil_print("%s\n", unversioned_content_hash(debugFlag)); |
| 413 | }else if( strncmp(zCmd, "list", nCmd)==0 || strncmp(zCmd, "ls", nCmd)==0 ){ |
| 414 | Stmt q; |
| 415 | int allFlag = find_option("all","a",0)!=0; |
| 416 | int longFlag = find_option("l",0,0)!=0 || (nCmd>1 && zCmd[1]=='i'); |
| 417 | char *zPattern = sqlite3_mprintf("true"); |
| 418 | const char *zGlob; |
| @@ -464,18 +464,18 @@ | |
| 464 | ); |
| 465 | } |
| 466 | } |
| 467 | db_finalize(&q); |
| 468 | sqlite3_free(zPattern); |
| 469 | }else if( strncmp(zCmd, "revert", nCmd)==0 ){ |
| 470 | unsigned syncFlags = |
| 471 | unversioned_sync_flags(SYNC_UNVERSIONED|SYNC_UV_REVERT); |
| 472 | g.argv[1] = "sync"; |
| 473 | g.argv[2] = "--uv-noop"; |
| 474 | sync_unversioned(syncFlags); |
| 475 | }else if( strncmp(zCmd, "remove", nCmd)==0 || strncmp(zCmd, "rm", nCmd)==0 |
| 476 | || strncmp(zCmd, "delete", nCmd)==0 ){ |
| 477 | int i; |
| 478 | const char *zGlob; |
| 479 | db_begin_transaction(); |
| 480 | while( (zGlob = find_option("glob",0,1))!=0 ){ |
| 481 | db_multi_exec( |
| @@ -499,16 +499,16 @@ | |
| 499 | mtime, g.argv[i] |
| 500 | ); |
| 501 | } |
| 502 | db_unset("uv-hash", 0); |
| 503 | db_end_transaction(0); |
| 504 | }else if( strncmp(zCmd,"sync",nCmd)==0 ){ |
| 505 | unsigned syncFlags = unversioned_sync_flags(SYNC_UNVERSIONED); |
| 506 | g.argv[1] = "sync"; |
| 507 | g.argv[2] = "--uv-noop"; |
| 508 | sync_unversioned(syncFlags); |
| 509 | }else if( strncmp(zCmd, "touch", nCmd)==0 ){ |
| 510 | int i; |
| 511 | verify_all_options(); |
| 512 | db_begin_transaction(); |
| 513 | for(i=3; i<g.argc; i++){ |
| 514 | db_multi_exec( |
| 515 |