From babc8feb2bd829f3f7500e8d2ab10f9fe57e13f4 Mon Sep 17 00:00:00 2001 From: bbedward Date: Fri, 20 Feb 2026 11:39:41 -0500 Subject: [PATCH] clipboard: fix memory leak from unbounded offer maps and unguarded file reads --- core/internal/server/clipboard/manager.go | 30 ++++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/core/internal/server/clipboard/manager.go b/core/internal/server/clipboard/manager.go index 8d4603dc..f5f528b8 100644 --- a/core/internal/server/clipboard/manager.go +++ b/core/internal/server/clipboard/manager.go @@ -232,8 +232,15 @@ func (m *Manager) setupDataDeviceSync() { return } + prevOffer := m.currentOffer m.currentOffer = offer + if prevOffer != nil && prevOffer != offer { + m.offerMutex.Lock() + delete(m.offerMimeTypes, prevOffer) + m.offerMutex.Unlock() + } + m.offerMutex.RLock() mimes := m.offerMimeTypes[offer] m.offerMutex.RUnlock() @@ -587,20 +594,26 @@ func (m *Manager) uriListPreview(data []byte) (string, bool) { uris = strings.Split(text, "\n") } + if len(uris) > 1 { + return fmt.Sprintf("[[ %d files ]]", len(uris)), false + } + if len(uris) == 1 && strings.HasPrefix(uris[0], "file://") { filePath := strings.TrimPrefix(uris[0], "file://") - if info, err := os.Stat(filePath); err == nil && !info.IsDir() { + info, err := os.Stat(filePath) + if err != nil || info.IsDir() { + return m.textPreview(data), false + } + + cfg := m.getConfig() + if info.Size() <= cfg.MaxEntrySize { if imgData, err := os.ReadFile(filePath); err == nil { if config, imgFmt, err := image.DecodeConfig(bytes.NewReader(imgData)); err == nil { return fmt.Sprintf("[[ file %s %s %dx%d ]]", filepath.Base(filePath), imgFmt, config.Width, config.Height), true } } - return fmt.Sprintf("[[ file %s ]]", filepath.Base(filePath)), false } - } - - if len(uris) > 1 { - return fmt.Sprintf("[[ %d files ]]", len(uris)), false + return fmt.Sprintf("[[ file %s ]]", filepath.Base(filePath)), false } return m.textPreview(data), false @@ -623,6 +636,11 @@ func (m *Manager) tryReadImageFromURI(data []byte) ([]byte, string, bool) { return nil, "", false } + cfg := m.getConfig() + if info.Size() > cfg.MaxEntrySize { + return nil, "", false + } + imgData, err := os.ReadFile(filePath) if err != nil { return nil, "", false