golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.48k stars 17.59k forks source link

encoding/base64: imprecise error for the base64-decoding input with an invalid length #38045

Open yaojingguo opened 4 years ago

yaojingguo commented 4 years ago

What version of Go are you using (go version)?

$ go version
go version go1.14 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/jing/Library/Caches/go-build"
GOENV="/Users/jing/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/jing/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/opt/go/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/opt/go/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/qd/wj_djys9219cyj4l9c2qw6g80000gn/T/go-build600458213=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Run the following test case:

func TestBug(t *testing.T) {
    if s, err := base64.URLEncoding.DecodeString("f"); err == nil {
        t.Logf("base64 encoded string: %s", string(s))
    } else {
        t.Fatal(err)
    }
}

What did you expect to see?

An error message says that the length of the input data is not a multiple of 4 bytes.

What did you see instead?

Error message: illegal base64 data at input byte 0

f is a valid base64-encode byte. The failure of the decoding is due to the fact that the length of the input data is not a multiple of 4 bytes.

andybons commented 4 years ago

@rsc

jltorresm commented 4 years ago

I think this is related to the fact that the base64.DecodedLen(n) when n is 1 turns out to be 0 due to the integer truncation going on.

The encoded string ends up in the decodeQuantum function. Where the "f" is correctly decoded using the decodeMap. Then the resulting char is added to the dbuf where it is hold until it is time to set it in the destination buffer, but that time never comes, because the for loop is continued and that make the loop variable j to become 1 which is out of bounds for the source string (which is only 1 character long).

So in this second iteration inside the decodeQuantum function, the loop index becomes equals to the si flag and since the base64.URLEncoding assumes padded strings, it flags the source to be corrupt. You can see the relevant code here.

Now the interesting part is that, when repeating the test with base64.RawURLEncoding, which should accept unpadded sources, it still results in a corruption error. The code which triggers this errors is the following: case j == 1, enc.padChar != NoPadding:.

Which makes me second guess whether the single "f" is a valid base64 encoded string.

In any case, these are the details of the error. This was all tested in a go version go1.14.6 linux/amd64 environment. Hope this helps better understand the origin of the issue report.