From 27b5ac666e64fa214f345f212fa95ac777a56ae7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 21 Sep 2016 14:20:56 +0200 Subject: [PATCH] Implemented "command must be followed by argument" protection suggested by @terrelln (#375) --- programs/zstdcli.c | 19 ++++++++++++++----- tests/playTests.sh | 22 +++++++++++++++++++--- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 7c93fdaad..95267aa89 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -208,7 +208,8 @@ int main(int argCount, const char* argv[]) nextArgumentIsMaxDict=0, nextArgumentIsDictID=0, nextArgumentIsFile=0, - ultra=0; + ultra=0, + lastCommand = 0; int cLevel = ZSTDCLI_CLEVEL_DEFAULT; int cLevelLast = 1; unsigned recursive = 0; @@ -268,8 +269,8 @@ int main(int argCount, const char* argv[]) if (!strcmp(argument, "--no-sparse")) { FIO_setSparseWrite(0); continue; } if (!strcmp(argument, "--test")) { testmode=1; decode=1; continue; } if (!strcmp(argument, "--train")) { dictBuild=1; outFileName=g_defaultDictName; continue; } - if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; continue; } - if (!strcmp(argument, "--dictID")) { nextArgumentIsDictID=1; continue; } + if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; lastCommand=1; continue; } + if (!strcmp(argument, "--dictID")) { nextArgumentIsDictID=1; lastCommand=1; continue; } if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; } if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; } @@ -287,6 +288,10 @@ int main(int argCount, const char* argv[]) argument++; while (argument[0]!=0) { + if (lastCommand) { + DISPLAY("error : command must be followed by argument \n"); + return 1; + } #ifndef ZSTD_NOCOMPRESS /* compression Level */ if ((*argument>='0') && (*argument<='9')) { @@ -309,7 +314,7 @@ int main(int argCount, const char* argv[]) case 'c': forceStdout=1; outFileName=stdoutmark; argument++; break; /* Use file content as dictionary */ - case 'D': nextEntryIsDictionary = 1; argument++; break; + case 'D': nextEntryIsDictionary = 1; lastCommand = 1; argument++; break; /* Overwrite */ case 'f': FIO_overwriteMode(); forceStdout=1; argument++; break; @@ -330,7 +335,7 @@ int main(int argCount, const char* argv[]) case 't': testmode=1; decode=1; argument++; break; /* destination file name */ - case 'o': nextArgumentIsOutFileName=1; argument++; break; + case 'o': nextArgumentIsOutFileName=1; lastCommand=1; argument++; break; #ifdef UTIL_HAS_CREATEFILELIST /* recursive */ @@ -394,6 +399,7 @@ int main(int argCount, const char* argv[]) if (nextArgumentIsMaxDict) { nextArgumentIsMaxDict = 0; + lastCommand = 0; maxDictSize = readU32FromChar(&argument); if (toupper(*argument)=='K') maxDictSize <<= 10; if (toupper(*argument)=='M') maxDictSize <<= 20; @@ -402,6 +408,7 @@ int main(int argCount, const char* argv[]) if (nextArgumentIsDictID) { nextArgumentIsDictID = 0; + lastCommand = 0; dictID = readU32FromChar(&argument); continue; } @@ -410,12 +417,14 @@ int main(int argCount, const char* argv[]) if (nextEntryIsDictionary) { nextEntryIsDictionary = 0; + lastCommand = 0; dictFileName = argument; continue; } if (nextArgumentIsOutFileName) { nextArgumentIsOutFileName = 0; + lastCommand = 0; outFileName = argument; if (!strcmp(outFileName, "-")) outFileName = stdoutmark; continue; diff --git a/tests/playTests.sh b/tests/playTests.sh index 042197c2d..233f0775a 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -54,6 +54,14 @@ $ZSTD -99 -f tmp # too large compression level, automatic sized down $ECHO "test : compress to stdout" $ZSTD tmp -c > tmpCompressed $ZSTD tmp --stdout > tmpCompressed # long command format +$ECHO "test : compress to named file" +rm tmpCompressed +$ZSTD tmp -o tmpCompressed +ls tmpCompressed # must work +$ECHO "test : -o must be followed by filename (must fail)" +$ZSTD tmp -of tmpCompressed && die "-o must be followed by filename" +$ECHO "test : force write, correct order" +$ZSTD tmp -fo tmpCompressed $ECHO "test : implied stdout when input is stdin" $ECHO bob | $ZSTD | $ZSTD -d $ECHO "test : null-length file roundtrip" @@ -183,18 +191,26 @@ $ECHO "- Create first dictionary" $ZSTD --train *.c ../programs/*.c -o tmpDict cp $TESTFILE tmp $ZSTD -f tmp -D tmpDict -$ZSTD -d tmp.zst -D tmpDict -of result +$ZSTD -d tmp.zst -D tmpDict -fo result diff $TESTFILE result $ECHO "- Create second (different) dictionary" $ZSTD --train *.c ../programs/*.c ../programs/*.h -o tmpDictC -$ZSTD -d tmp.zst -D tmpDictC -of result && die "wrong dictionary not detected!" +$ZSTD -d tmp.zst -D tmpDictC -fo result && die "wrong dictionary not detected!" $ECHO "- Create dictionary with short dictID" $ZSTD --train *.c ../programs/*.c --dictID 1 -o tmpDict1 cmp tmpDict tmpDict1 && die "dictionaries should have different ID !" +$ECHO "- Create dictionary with wrong dictID parameter order (must fail)" +$ZSTD --train *.c ../programs/*.c --dictID -o 1 tmpDict1 && die "wrong order : --dictID must be followed by argument " +$ECHO "- Create dictionary with size limit" +$ZSTD --train *.c ../programs/*.c -o tmpDict2 --maxdict 4K -v +$ECHO "- Create dictionary with wrong parameter order (must fail)" +$ZSTD --train *.c ../programs/*.c -o tmpDict2 --maxdict -v 4K && die "wrong order : --maxdict must be followed by argument " $ECHO "- Compress without dictID" $ZSTD -f tmp -D tmpDict1 --no-dictID -$ZSTD -d tmp.zst -D tmpDict -of result +$ZSTD -d tmp.zst -D tmpDict -fo result diff $TESTFILE result +$ECHO "- Compress with wrong argument order (must fail)" +$ZSTD tmp -Df tmpDict1 -c > /dev/null && die "-D must be followed by dictionary name " $ECHO "- Compress multiple files with dictionary" rm -rf dirTestDict mkdir dirTestDict