Browse Source

Merge pull request from GHSA-wg4c-c9g9-rxhx

Fix issues 1 through 5 from GHSL-2021-050
Joshua M. Boniface 4 years ago
parent
commit
fe8cf29cad

+ 20 - 3
Jellyfin.Api/Controllers/HlsSegmentController.cs

@@ -61,7 +61,13 @@ namespace Jellyfin.Api.Controllers
         {
             // TODO: Deprecate with new iOS app
             var file = segmentId + Path.GetExtension(Request.Path);
-            file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file);
+            var transcodePath = _serverConfigurationManager.GetTranscodePath();
+            file = Path.GetFullPath(Path.Combine(transcodePath, file));
+            var fileDir = Path.GetDirectoryName(file);
+            if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodePath))
+            {
+                return BadRequest("Invalid segment.");
+            }
 
             return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file)!, false, HttpContext);
         }
@@ -81,7 +87,13 @@ namespace Jellyfin.Api.Controllers
         public ActionResult GetHlsPlaylistLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string playlistId)
         {
             var file = playlistId + Path.GetExtension(Request.Path);
-            file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file);
+            var transcodePath = _serverConfigurationManager.GetTranscodePath();
+            file = Path.GetFullPath(Path.Combine(transcodePath, file));
+            var fileDir = Path.GetDirectoryName(file);
+            if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodePath) || Path.GetExtension(file) != ".m3u8")
+            {
+                return BadRequest("Invalid segment.");
+            }
 
             return GetFileResult(file, file);
         }
@@ -130,7 +142,12 @@ namespace Jellyfin.Api.Controllers
             var file = segmentId + Path.GetExtension(Request.Path);
             var transcodeFolderPath = _serverConfigurationManager.GetTranscodePath();
 
-            file = Path.Combine(transcodeFolderPath, file);
+            file = Path.GetFullPath(Path.Combine(transcodeFolderPath, file));
+            var fileDir = Path.GetDirectoryName(file);
+            if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodeFolderPath))
+            {
+                return BadRequest("Invalid segment.");
+            }
 
             var normalizedPlaylistId = playlistId;
 

+ 20 - 3
Jellyfin.Api/Controllers/ImageByNameController.cs

@@ -74,7 +74,7 @@ namespace Jellyfin.Api.Controllers
                 : type;
 
             var path = BaseItem.SupportedImageExtensions
-                .Select(i => Path.Combine(_applicationPaths.GeneralPath, name, filename + i))
+                .Select(i => Path.GetFullPath(Path.Combine(_applicationPaths.GeneralPath, name, filename + i)))
                 .FirstOrDefault(System.IO.File.Exists);
 
             if (path == null)
@@ -82,6 +82,11 @@ namespace Jellyfin.Api.Controllers
                 return NotFound();
             }
 
+            if (!path.StartsWith(_applicationPaths.GeneralPath))
+            {
+                return BadRequest("Invalid image path.");
+            }
+
             var contentType = MimeTypes.GetMimeType(path);
             return File(System.IO.File.OpenRead(path), contentType);
         }
@@ -163,7 +168,8 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
         private ActionResult GetImageFile(string basePath, string theme, string? name)
         {
-            var themeFolder = Path.Combine(basePath, theme);
+            var themeFolder = Path.GetFullPath(Path.Combine(basePath, theme));
+
             if (Directory.Exists(themeFolder))
             {
                 var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(themeFolder, name + i))
@@ -171,12 +177,18 @@ namespace Jellyfin.Api.Controllers
 
                 if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
                 {
+                    if (!path.StartsWith(basePath))
+                    {
+                        return BadRequest("Invalid image path.");
+                    }
+
                     var contentType = MimeTypes.GetMimeType(path);
+
                     return PhysicalFile(path, contentType);
                 }
             }
 
-            var allFolder = Path.Combine(basePath, "all");
+            var allFolder = Path.GetFullPath(Path.Combine(basePath, "all"));
             if (Directory.Exists(allFolder))
             {
                 var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(allFolder, name + i))
@@ -184,6 +196,11 @@ namespace Jellyfin.Api.Controllers
 
                 if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
                 {
+                    if (!path.StartsWith(basePath))
+                    {
+                        return BadRequest("Invalid image path.");
+                    }
+
                     var contentType = MimeTypes.GetMimeType(path);
                     return PhysicalFile(path, contentType);
                 }

+ 21 - 3
MediaBrowser.Providers/Subtitles/SubtitleManager.cs

@@ -205,12 +205,30 @@ namespace MediaBrowser.Providers.Subtitles
 
                 if (saveInMediaFolder)
                 {
-                    savePaths.Add(Path.Combine(video.ContainingFolderPath, saveFileName));
+                    var mediaFolderPath = Path.GetFullPath(Path.Combine(video.ContainingFolderPath, saveFileName));
+                    // TODO: Add some error handling to the API user: return BadRequest("Could not save subtitle, bad path.");
+                    if (mediaFolderPath.StartsWith(video.ContainingFolderPath))
+                    {
+                        savePaths.Add(mediaFolderPath);
+                    }
                 }
 
-                savePaths.Add(Path.Combine(video.GetInternalMetadataPath(), saveFileName));
+                var internalPath = Path.GetFullPath(Path.Combine(video.GetInternalMetadataPath(), saveFileName));
+
+                // TODO: Add some error to the user: return BadRequest("Could not save subtitle, bad path.");
+                if (internalPath.StartsWith(video.GetInternalMetadataPath()))
+                {
+                    savePaths.Add(internalPath);
+                }
 
-                await TrySaveToFiles(memoryStream, savePaths).ConfigureAwait(false);
+                if (savePaths.Count > 0)
+                {
+                    await TrySaveToFiles(memoryStream, savePaths).ConfigureAwait(false);
+                }
+                else
+                {
+                    _logger.LogError("An uploaded subtitle could not be saved because the resulting paths were invalid.");
+                }
             }
         }