mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-26 22:19:40 -08:00
storage: Check for negative values from varint decoding
Sadly, we have a number of places where we use varint encoding for numbers that cannot be negative. We could have saved a bit by using uvarint encoding. On the bright side, we now have a 50% chance to detect data corruption. :-/ Fixes #1800 and #2492.
This commit is contained in:
parent
5f3327f620
commit
ae286385fd
|
@ -123,6 +123,8 @@ func DecodeUint64(r io.Reader) (uint64, error) {
|
||||||
// encodeString writes the varint encoded length followed by the bytes of s to
|
// encodeString writes the varint encoded length followed by the bytes of s to
|
||||||
// b.
|
// b.
|
||||||
func encodeString(b *bytes.Buffer, s string) error {
|
func encodeString(b *bytes.Buffer, s string) error {
|
||||||
|
// Note that this should have used EncodeUvarint but a glitch happened
|
||||||
|
// while designing the checkpoint format.
|
||||||
if _, err := EncodeVarint(b, int64(len(s))); err != nil {
|
if _, err := EncodeVarint(b, int64(len(s))); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -135,6 +137,9 @@ func encodeString(b *bytes.Buffer, s string) error {
|
||||||
// decodeString decodes a string encoded by encodeString.
|
// decodeString decodes a string encoded by encodeString.
|
||||||
func decodeString(b byteReader) (string, error) {
|
func decodeString(b byteReader) (string, error) {
|
||||||
length, err := binary.ReadVarint(b)
|
length, err := binary.ReadVarint(b)
|
||||||
|
if length < 0 {
|
||||||
|
err = fmt.Errorf("found negative string length during decoding: %d", length)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -155,6 +160,8 @@ type Metric model.Metric
|
||||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||||
func (m Metric) MarshalBinary() ([]byte, error) {
|
func (m Metric) MarshalBinary() ([]byte, error) {
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
|
// Note that this should have used EncodeUvarint but a glitch happened
|
||||||
|
// while designing the checkpoint format.
|
||||||
if _, err := EncodeVarint(buf, int64(len(m))); err != nil {
|
if _, err := EncodeVarint(buf, int64(len(m))); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -180,6 +187,9 @@ func (m *Metric) UnmarshalBinary(buf []byte) error {
|
||||||
// Metric.
|
// Metric.
|
||||||
func (m *Metric) UnmarshalFromReader(r byteReader) error {
|
func (m *Metric) UnmarshalFromReader(r byteReader) error {
|
||||||
numLabelPairs, err := binary.ReadVarint(r)
|
numLabelPairs, err := binary.ReadVarint(r)
|
||||||
|
if numLabelPairs < 0 {
|
||||||
|
err = fmt.Errorf("found negative numLabelPairs during unmarshaling: %d", numLabelPairs)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -344,6 +354,8 @@ type LabelValueSet map[model.LabelValue]struct{}
|
||||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||||
func (vs LabelValueSet) MarshalBinary() ([]byte, error) {
|
func (vs LabelValueSet) MarshalBinary() ([]byte, error) {
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
|
// Note that this should have used EncodeUvarint but a glitch happened
|
||||||
|
// while designing the checkpoint format.
|
||||||
if _, err := EncodeVarint(buf, int64(len(vs))); err != nil {
|
if _, err := EncodeVarint(buf, int64(len(vs))); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -359,6 +371,9 @@ func (vs LabelValueSet) MarshalBinary() ([]byte, error) {
|
||||||
func (vs *LabelValueSet) UnmarshalBinary(buf []byte) error {
|
func (vs *LabelValueSet) UnmarshalBinary(buf []byte) error {
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
numValues, err := binary.ReadVarint(r)
|
numValues, err := binary.ReadVarint(r)
|
||||||
|
if numValues < 0 {
|
||||||
|
err = fmt.Errorf("found negative number of values during unmarshaling: %d", numValues)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -382,6 +397,8 @@ type LabelValues model.LabelValues
|
||||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||||
func (vs LabelValues) MarshalBinary() ([]byte, error) {
|
func (vs LabelValues) MarshalBinary() ([]byte, error) {
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
|
// Note that this should have used EncodeUvarint but a glitch happened
|
||||||
|
// while designing the checkpoint format.
|
||||||
if _, err := EncodeVarint(buf, int64(len(vs))); err != nil {
|
if _, err := EncodeVarint(buf, int64(len(vs))); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -397,6 +414,9 @@ func (vs LabelValues) MarshalBinary() ([]byte, error) {
|
||||||
func (vs *LabelValues) UnmarshalBinary(buf []byte) error {
|
func (vs *LabelValues) UnmarshalBinary(buf []byte) error {
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
numValues, err := binary.ReadVarint(r)
|
numValues, err := binary.ReadVarint(r)
|
||||||
|
if numValues < 0 {
|
||||||
|
err = fmt.Errorf("found negative number of values during unmarshaling: %d", numValues)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,9 @@ func (hs *headsScanner) scan() bool {
|
||||||
if hs.version != headsFormatLegacyVersion {
|
if hs.version != headsFormatLegacyVersion {
|
||||||
// persistWatermark only present in v2.
|
// persistWatermark only present in v2.
|
||||||
persistWatermark, hs.err = binary.ReadVarint(hs.r)
|
persistWatermark, hs.err = binary.ReadVarint(hs.r)
|
||||||
|
if persistWatermark < 0 {
|
||||||
|
hs.err = fmt.Errorf("found negative persist watermark in checkpoint: %d", persistWatermark)
|
||||||
|
}
|
||||||
if hs.err != nil {
|
if hs.err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -147,6 +150,11 @@ func (hs *headsScanner) scan() bool {
|
||||||
if numChunkDescs, hs.err = binary.ReadVarint(hs.r); hs.err != nil {
|
if numChunkDescs, hs.err = binary.ReadVarint(hs.r); hs.err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if numChunkDescs < 0 {
|
||||||
|
hs.err = fmt.Errorf("found negative number of chunk descriptors in checkpoint: %d", numChunkDescs)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
chunkDescs := make([]*chunk.Desc, numChunkDescs)
|
chunkDescs := make([]*chunk.Desc, numChunkDescs)
|
||||||
if hs.version == headsFormatLegacyVersion {
|
if hs.version == headsFormatLegacyVersion {
|
||||||
if headChunkPersisted {
|
if headChunkPersisted {
|
||||||
|
|
|
@ -609,6 +609,9 @@ func (p *persistence) loadChunkDescs(fp model.Fingerprint, offsetFromEnd int) ([
|
||||||
// (4.8.2.1) A byte defining the chunk type.
|
// (4.8.2.1) A byte defining the chunk type.
|
||||||
// (4.8.2.2) The chunk itself, marshaled with the Marshal() method.
|
// (4.8.2.2) The chunk itself, marshaled with the Marshal() method.
|
||||||
//
|
//
|
||||||
|
// NOTE: Above, varint encoding is used consistently although uvarint would have
|
||||||
|
// made more sense in many cases. This was simply a glitch while designing the
|
||||||
|
// format.
|
||||||
func (p *persistence) checkpointSeriesMapAndHeads(fingerprintToSeries *seriesMap, fpLocker *fingerprintLocker) (err error) {
|
func (p *persistence) checkpointSeriesMapAndHeads(fingerprintToSeries *seriesMap, fpLocker *fingerprintLocker) (err error) {
|
||||||
log.Info("Checkpointing in-memory metrics and chunks...")
|
log.Info("Checkpointing in-memory metrics and chunks...")
|
||||||
p.checkpointing.Set(1)
|
p.checkpointing.Set(1)
|
||||||
|
|
Loading…
Reference in a new issue