@ -135,3 +135,44 @@ func newTestProgram(t *testing.T, environVar string) (cmd *exec.Cmd, stdout *byt
return
}
// Ensure that using CopyFile does not truncate the destination file before
// the origin is positively a non-directory and that it is ready for copying.
// See https://github.com/tendermint/tendermint/issues/6427
func TestTrickedTruncation ( t * testing . T ) {
tmpDir , err := ioutil . TempDir ( os . TempDir ( ) , "pwn_truncate" )
if err != nil {
t . Fatal ( err )
}
defer os . Remove ( tmpDir )
originalWALPath := filepath . Join ( tmpDir , "wal" )
originalWALContent := [ ] byte ( "I AM BECOME DEATH, DESTROYER OF ALL WORLDS!" )
if err := ioutil . WriteFile ( originalWALPath , originalWALContent , 0755 ) ; err != nil {
t . Fatal ( err )
}
// 1. Sanity check.
readWAL , err := ioutil . ReadFile ( originalWALPath )
if err != nil {
t . Fatal ( err )
}
if ! bytes . Equal ( readWAL , originalWALContent ) {
t . Fatalf ( "Cannot proceed as the content does not match\nGot: %q\nWant: %q" , readWAL , originalWALContent )
}
// 2. Now cause the truncation of the original file.
// It is absolutely legal to invoke os.Open on a directory.
if err := tmos . CopyFile ( tmpDir , originalWALPath ) ; err == nil {
t . Fatal ( "Expected an error" )
}
// 3. Check the WAL's content
reReadWAL , err := ioutil . ReadFile ( originalWALPath )
if err != nil {
t . Fatal ( err )
}
if ! bytes . Equal ( reReadWAL , originalWALContent ) {
t . Fatalf ( "Oops, the WAL's content was changed :(\nGot: %q\nWant: %q" , reReadWAL , originalWALContent )
}
}