What happened:
karmadactl init reads Karmada component certificate and key files into memory using a single file.Read call and discards the number of bytes returned.
pkg/karmadactl/cmdinit/utils/format.go:
func FileToBytes(path, name string) ([]byte, error) {
filename := filepath.Join(path, name)
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
stats, err := file.Stat()
if err != nil {
return nil, err
}
data := make([]byte, stats.Size())
_, err = file.Read(data) // returned byte count is ignored
if err != nil {
return nil, err
}
return data, nil
}
io.Reader.Read is not guaranteed to fill the whole buffer in one call. It may return fewer bytes than len(data) with err == nil. Because the count is ignored, the returned slice can contain trailing zero bytes (truncated content) without any error being reported.
This function is used to read the component .crt and .key files in pkg/karmadactl/cmdinit/kubernetes/deploy.go:
certs, err := utils.FileToBytes(i.KarmadaPkiPath, fmt.Sprintf("%s.crt", v))
...
key, err := utils.FileToBytes(i.KarmadaPkiPath, fmt.Sprintf("%s.key", v))
The returned bytes are then stored and written into Karmada secrets.
What you expected to happen:
The full file contents should be read reliably. A short read should either be completed or reported as an error, never silently produce truncated cert/key bytes.
How to reproduce it (as minimally and precisely as possible):
This is a latent correctness bug rather than something that reproduces on every run: os.File.Read usually returns small files in a single call, but the code relies on that undefined behavior instead of the io.Reader contract. When Read returns fewer bytes than the file size (which the contract allows), FileToBytes returns a truncated buffer with no error, and that truncated cert/key gets written into the secret.
Anything else we need to know?:
The fix is small: replace the manual Open/Stat/Read with os.ReadFile(filepath.Join(path, name)), or use io.ReadFull. os.ReadFile is the idiomatic, correct replacement and also simplifies the function. I'd like to work on this.
Environment:
- Karmada version: master
- kubectl-karmada or karmadactl version (the result of
kubectl-karmada version or karmadactl version): built from master
- Others: affects
karmadactl init (reads component cert/key files)
What happened:
karmadactl initreads Karmada component certificate and key files into memory using a singlefile.Readcall and discards the number of bytes returned.pkg/karmadactl/cmdinit/utils/format.go:
io.Reader.Readis not guaranteed to fill the whole buffer in one call. It may return fewer bytes thanlen(data)witherr == nil. Because the count is ignored, the returned slice can contain trailing zero bytes (truncated content) without any error being reported.This function is used to read the component
.crtand.keyfiles in pkg/karmadactl/cmdinit/kubernetes/deploy.go:The returned bytes are then stored and written into Karmada secrets.
What you expected to happen:
The full file contents should be read reliably. A short read should either be completed or reported as an error, never silently produce truncated cert/key bytes.
How to reproduce it (as minimally and precisely as possible):
This is a latent correctness bug rather than something that reproduces on every run:
os.File.Readusually returns small files in a single call, but the code relies on that undefined behavior instead of theio.Readercontract. WhenReadreturns fewer bytes than the file size (which the contract allows),FileToBytesreturns a truncated buffer with no error, and that truncated cert/key gets written into the secret.Anything else we need to know?:
The fix is small: replace the manual
Open/Stat/Readwithos.ReadFile(filepath.Join(path, name)), or useio.ReadFull.os.ReadFileis the idiomatic, correct replacement and also simplifies the function. I'd like to work on this.Environment:
kubectl-karmada versionorkarmadactl version): built from masterkarmadactl init(reads component cert/key files)