From 2a3916ce192d73bdd6f621cc3842782814351227 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 15 Sep 2026 18:09:26 +0200 Subject: fix(notify): cap image dimensions and rank icon_data last A notification is untrusted input. RawImage.PNG computed stride*(Height-1)+Width*Channels in int, so Width=Height=2^31-1 with RowStride=0 wrapped the length expression negative, slipped past the guard, and reached image.NewRGBA, which panics. The D-Bus call path has no recover, so one malformed Notify killed the daemon. Cap Width/Height at 1<<16 before any multiplication and compute the required byte count in int64. image-data, image-path and the deprecated icon_data were read as one tier, with icon_data ahead of image-path, inverting the spec's order. Split the deprecated key into IconDataFromHints and apply tier 1 (image-data/image_data), then image-path, then icon_data. Raw handling is unchanged: encode, hold pendingImage, WriteImage after Add, SetImage. --- internal/notify/service.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'internal/notify/service.go') diff --git a/internal/notify/service.go b/internal/notify/service.go index a8f0728..86918d4 100644 --- a/internal/notify/service.go +++ b/internal/notify/service.go @@ -103,8 +103,9 @@ func (s *Service) Notify(appName string, replacesID uint32, appIcon, summary, bo tag := StackTagFromHints(hints) now := time.Now().UnixMilli() ms := EffectiveTimeoutMS(expireTimeout, u) - // image-data wins over image-path, and its blob cannot be written until - // Add has assigned the id the filename is derived from. + // Spec priority is image-data > image-path > the deprecated icon_data. A + // raw blob cannot be written until Add has assigned the id the filename is + // derived from, so any raw tier is held in pendingImage. var pendingImage []byte n := &Popup{ App: appName, @@ -115,14 +116,20 @@ func (s *Service) Notify(appName string, replacesID uint32, appIcon, summary, bo Actions: ParseActions(actions), Created: now, } - if raw, ok := ImageDataFromHints(hints); ok { + var raw *RawImage + if r, ok := ImageDataFromHints(hints); ok { + raw = r + } else if path, ok := ImagePathFromHints(hints); ok { + n.Image = ResolveIcon(path) + } else if r, ok := IconDataFromHints(hints); ok { + raw = r + } + if raw != nil { if data, err := raw.PNG(); err == nil { pendingImage = data } else { log.Printf("notifyd: encode image: %v", err) } - } else if path, ok := ImagePathFromHints(hints); ok { - n.Image = ResolveIcon(path) } if ms > 0 { n.Expires = now + ms -- cgit v1.2.3