From 62c119f0a4612cf38490207c72ccf204e8d7d14e Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Mon, 3 Aug 2026 18:23:08 +0200 Subject: [PATCH] hls: prevent some CodeQL warnings (#6024) --- internal/servers/hls/muxer_instance.go | 34 ++++++++++++++++++++++++-- internal/servers/hls/server_test.go | 14 +++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/internal/servers/hls/muxer_instance.go b/internal/servers/hls/muxer_instance.go index 9823a204..ca516b81 100644 --- a/internal/servers/hls/muxer_instance.go +++ b/internal/servers/hls/muxer_instance.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "sync" "sync/atomic" "time" @@ -25,6 +26,26 @@ const ( sessionCleanupPeriod = sessionCloseAfter / 3 ) +// this prevents directory traversal. +// functionally it's useless since there's already conf.IsPathName, but it's needed by CodeQL. +func safeSubDirectory(base string, pathName string) (string, error) { + baseAbs, err := filepath.Abs(filepath.Clean(base)) + if err != nil { + return "", err + } + + candidateAbs, err := filepath.Abs(filepath.Join(baseAbs, pathName)) + if err != nil { + return "", err + } + + if !strings.HasPrefix(candidateAbs, baseAbs) { + return "", fmt.Errorf("path escapes base directory") + } + + return candidateAbs, nil +} + type instanceParent interface { logger.Writer closeInstance(*muxerInstance, error) @@ -54,9 +75,18 @@ func (mi *muxerInstance) initialize() error { mi.Log(logger.Debug, "instance created") var muxerDirectory string + if mi.directory != "" { - muxerDirectory = filepath.Join(mi.directory, mi.pathName) - os.MkdirAll(muxerDirectory, 0o755) + var err error + muxerDirectory, err = safeSubDirectory(mi.directory, mi.pathName) + if err != nil { + return err + } + + err = os.MkdirAll(muxerDirectory, 0o755) + if err != nil { + return err + } } mi.hmuxer = &gohlslib.Muxer{ diff --git a/internal/servers/hls/server_test.go b/internal/servers/hls/server_test.go index 781eee0f..75a3d818 100644 --- a/internal/servers/hls/server_test.go +++ b/internal/servers/hls/server_test.go @@ -538,6 +538,20 @@ func TestServerDirectory(t *testing.T) { require.NoError(t, err) } +func TestSafeSubDirectory(t *testing.T) { + base := t.TempDir() + + path, err := safeSubDirectory(base, "group/cam1") + require.NoError(t, err) + require.Equal(t, filepath.Join(base, "group", "cam1"), path) + + _, err = safeSubDirectory(base, "../cam1") + require.Error(t, err) + + _, err = safeSubDirectory(base, "group/../../cam1") + require.Error(t, err) +} + func TestServerDynamicAlwaysRemux(t *testing.T) { desc := &description.Session{Medias: []*description.Media{test.MediaH264}}