internal/pipewire: slice at POD boundary
All checks were successful
Test / Create distribution (push) Successful in 36s
Test / Sandbox (push) Successful in 2m20s
Test / Hakurei (push) Successful in 47s
Test / Sandbox (race detector) (push) Successful in 2m16s
Test / Hakurei (race detector) (push) Successful in 3m5s
Test / Hpkg (push) Successful in 3m18s
Test / Flake checks (push) Successful in 1m34s

This prevents incorrectly reading trailing data as part of the current POD.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-11-25 14:58:56 +09:00
parent 2d7b896a8c
commit 26009fd3f7
Signed by: cat
SSH Key Fingerprint: SHA256:wr6yH7sDDbUFi81k/GsIGwpM3O2QrwqYlLF26CcJa4w

View File

@ -190,7 +190,7 @@ func (e *InvalidUnmarshalError) Error() string {
return "attempting to unmarshal to nil " + e.Type.String() return "attempting to unmarshal to nil " + e.Type.String()
} }
// Unmarshal parses the JSON-encoded data and stores the result // Unmarshal parses the PipeWire POD encoded data and stores the result
// in the value pointed to by v. If v is nil or not a pointer, // in the value pointed to by v. If v is nil or not a pointer,
// Unmarshal returns an [InvalidUnmarshalError]. // Unmarshal returns an [InvalidUnmarshalError].
func Unmarshal(data []byte, v any) (size Word, err error) { func Unmarshal(data []byte, v any) (size Word, err error) {
@ -199,10 +199,8 @@ func Unmarshal(data []byte, v any) (size Word, err error) {
return 0, &InvalidUnmarshalError{reflect.TypeOf(v)} return 0, &InvalidUnmarshalError{reflect.TypeOf(v)}
} }
err = unmarshalValue(data, rv.Elem(), &size) err = unmarshalValue(data, rv.Elem(), &size)
// size and type prefix // prefix and padding size
size += 8 size += 8 + (8-(size)%8)%8
// padding
size += (8 - (size)%8) % 8
return return
} }
@ -231,8 +229,8 @@ func (e StringTerminationError) Error() string {
return "got byte " + strconv.Itoa(int(e.Value)) + " instead of NUL" return "got byte " + strconv.Itoa(int(e.Value)) + " instead of NUL"
} }
// unmarshalValue implements [Unmarshal] on [reflect.Value]. // unmarshalValue implements [Unmarshal] on [reflect.Value] without compensating for prefix and padding size.
func unmarshalValue(data []byte, v reflect.Value, sizeP *Word) error { func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
if !v.CanSet() { if !v.CanSet() {
return &UnmarshalSetError{v.Type()} return &UnmarshalSetError{v.Type()}
} }
@ -244,7 +242,7 @@ func unmarshalValue(data []byte, v reflect.Value, sizeP *Word) error {
if u, ok := v.Interface().(PODUnmarshaler); ok { if u, ok := v.Interface().(PODUnmarshaler); ok {
var err error var err error
*sizeP, err = u.UnmarshalPOD(data) *wireSizeP, err = u.UnmarshalPOD(data)
return err return err
} }
} }
@ -252,16 +250,16 @@ func unmarshalValue(data []byte, v reflect.Value, sizeP *Word) error {
switch v.Kind() { switch v.Kind() {
case reflect.Int32: case reflect.Int32:
*sizeP = 4 *wireSizeP = 4
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Int, sizeP); err != nil { if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Int, wireSizeP); err != nil {
return err return err
} }
v.SetInt(int64(binary.NativeEndian.Uint32(data))) v.SetInt(int64(binary.NativeEndian.Uint32(data)))
return nil return nil
case reflect.Struct: case reflect.Struct:
*sizeP = 0 *wireSizeP = 0
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Struct, sizeP); err != nil { if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Struct, wireSizeP); err != nil {
return err return err
} }
@ -291,17 +289,17 @@ func unmarshalValue(data []byte, v reflect.Value, sizeP *Word) error {
default: default:
v.Set(reflect.New(v.Type().Elem())) v.Set(reflect.New(v.Type().Elem()))
return unmarshalValue(data, v.Elem(), sizeP) return unmarshalValue(data, v.Elem(), wireSizeP)
} }
case reflect.String: case reflect.String:
*sizeP = 0 *wireSizeP = 0
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_String, sizeP); err != nil { if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_String, wireSizeP); err != nil {
return err return err
} }
// string size, one extra NUL byte // string size, one extra NUL byte
size := int(*sizeP) size := int(*wireSizeP)
if len(data) < size { if len(data) < size {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
} }
@ -358,7 +356,7 @@ func unmarshalCheckTypeBounds(data *[]byte, t Word, sizeP *Word) error {
return &UnexpectedTypeError{gotType, t} return &UnexpectedTypeError{gotType, t}
} }
*data = (*data)[8:] *data = (*data)[8 : gotSize+8]
return nil return nil
} }