diff options
Diffstat (limited to 'internal/notify/image.go')
| -rw-r--r-- | internal/notify/image.go | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/internal/notify/image.go b/internal/notify/image.go index 4a0f6df..9dd750e 100644 --- a/internal/notify/image.go +++ b/internal/notify/image.go @@ -34,10 +34,10 @@ type RawImage struct { Data []byte } -// ImageDataFromHints reads the raw image struct, preferring the spec key then -// the deprecated icon_data, then the underscore alias older libnotify sent. +// ImageDataFromHints reads the spec's top-priority raw image key, image-data, +// or the underscore alias older libnotify sent. func ImageDataFromHints(hints map[string]dbus.Variant) (*RawImage, bool) { - for _, key := range []string{"image-data", "icon_data", "image_data"} { + for _, key := range []string{"image-data", "image_data"} { v, ok := hints[key] if !ok { continue @@ -49,6 +49,16 @@ func ImageDataFromHints(hints map[string]dbus.Variant) (*RawImage, bool) { return nil, false } +// IconDataFromHints reads the deprecated icon_data raw image, the lowest +// priority source, below image-data and the image-path URI. +func IconDataFromHints(hints map[string]dbus.Variant) (*RawImage, bool) { + v, ok := hints["icon_data"] + if !ok { + return nil, false + } + return rawImageFromVariant(v) +} + // ImagePathFromHints reads image-path, a URI, a path, or a theme icon name. func ImagePathFromHints(hints map[string]dbus.Variant) (string, bool) { v, ok := hints["image-path"] @@ -98,11 +108,19 @@ func asInt(v any) (int, bool) { return 0, false } +// maxImageDimension caps a client-supplied width or height. A notification +// icon is small, and the cap keeps every later width*channels and y*stride +// product far from overflow. +const maxImageDimension = 1 << 16 + // PNG encodes the raw pixels as a PNG the renderer can load. func (r *RawImage) PNG() ([]byte, error) { if r.Width <= 0 || r.Height <= 0 { return nil, fmt.Errorf("notifyd: image %dx%d", r.Width, r.Height) } + if r.Width > maxImageDimension || r.Height > maxImageDimension { + return nil, fmt.Errorf("notifyd: image %dx%d larger than %d", r.Width, r.Height, maxImageDimension) + } if r.BitsPerSample != 8 || (r.Channels != 3 && r.Channels != 4) { return nil, fmt.Errorf("notifyd: image bits=%d channels=%d", r.BitsPerSample, r.Channels) } @@ -110,7 +128,10 @@ func (r *RawImage) PNG() ([]byte, error) { if stride < r.Width*r.Channels { stride = r.Width * r.Channels } - if len(r.Data) < stride*(r.Height-1)+r.Width*r.Channels { + // int64 keeps a hostile RowStride from wrapping the length comparison + // negative and passing the guard. + need := int64(stride)*int64(r.Height-1) + int64(r.Width)*int64(r.Channels) + if int64(len(r.Data)) < need { return nil, fmt.Errorf("notifyd: image data short: %d bytes", len(r.Data)) } img := image.NewRGBA(image.Rect(0, 0, r.Width, r.Height)) |
