diff options
author | 2024-08-30 14:03:59 +0200 | |
---|---|---|
committer | 2024-08-30 14:03:59 +0200 | |
commit | cd93a5baf35f9879a3a354ed4d196235af692142 (patch) | |
tree | 09f06685a62b41994e9479fec52eafec2b25a2aa /internal/media/ffmpeg.go | |
parent | [chore] Only call `imaging.Resize when necessary`, use even tinier blurhashes... (diff) | |
download | gotosocial-cd93a5baf35f9879a3a354ed4d196235af692142.tar.xz |
[security] Implement `allowFiles` fs for better isolation of ffmpeg / ffprobe (#3251)
* [chore] Implement readOneFile fs
* further isolation
* remove fmt call
* tweaks
Diffstat (limited to 'internal/media/ffmpeg.go')
-rw-r--r-- | internal/media/ffmpeg.go | 88 |
1 files changed, 57 insertions, 31 deletions
diff --git a/internal/media/ffmpeg.go b/internal/media/ffmpeg.go index 0443f95b8..58c2f9503 100644 --- a/internal/media/ffmpeg.go +++ b/internal/media/ffmpeg.go @@ -21,6 +21,7 @@ import ( "context" "encoding/json" "errors" + "os" "path" "strconv" "strings" @@ -39,10 +40,7 @@ import ( // any metadata encoded into the media stream itself will not be cleared. This is the best we // can do without absolutely tanking performance by requiring transcodes :( func ffmpegClearMetadata(ctx context.Context, outpath, inpath string) error { - // Get directory from filepath. - dirpath := path.Dir(inpath) - - return ffmpeg(ctx, dirpath, + return ffmpeg(ctx, inpath, outpath, // Only log errors. "-loglevel", "error", @@ -66,18 +64,15 @@ func ffmpegClearMetadata(ctx context.Context, outpath, inpath string) error { } // ffmpegGenerateWebpThumb generates a thumbnail webp from input media of any type, useful for any media. -func ffmpegGenerateWebpThumb(ctx context.Context, filepath, outpath string, width, height int, pixfmt string) error { - // Get directory from filepath. - dirpath := path.Dir(filepath) - +func ffmpegGenerateWebpThumb(ctx context.Context, inpath, outpath string, width, height int, pixfmt string) error { // Generate thumb with ffmpeg. - return ffmpeg(ctx, dirpath, + return ffmpeg(ctx, inpath, outpath, // Only log errors. "-loglevel", "error", // Input file. - "-i", filepath, + "-i", inpath, // Encode using libwebp. // (NOT as libwebp_anim). @@ -116,27 +111,24 @@ func ffmpegGenerateWebpThumb(ctx context.Context, filepath, outpath string, widt } // ffmpegGenerateStatic generates a static png from input image of any type, useful for emoji. -func ffmpegGenerateStatic(ctx context.Context, filepath string) (string, error) { +func ffmpegGenerateStatic(ctx context.Context, inpath string) (string, error) { var outpath string // Generate thumb output path REPLACING extension. - if i := strings.IndexByte(filepath, '.'); i != -1 { - outpath = filepath[:i] + "_static.png" + if i := strings.IndexByte(inpath, '.'); i != -1 { + outpath = inpath[:i] + "_static.png" } else { return "", gtserror.New("input file missing extension") } - // Get directory from filepath. - dirpath := path.Dir(filepath) - // Generate static with ffmpeg. - if err := ffmpeg(ctx, dirpath, + if err := ffmpeg(ctx, inpath, outpath, // Only log errors. "-loglevel", "error", // Input file. - "-i", filepath, + "-i", inpath, // Only first frame. "-frames:v", "1", @@ -157,18 +149,45 @@ func ffmpegGenerateStatic(ctx context.Context, filepath string) (string, error) return outpath, nil } -// ffmpeg calls `ffmpeg [args...]` (WASM) with directory path mounted in runtime. -func ffmpeg(ctx context.Context, dirpath string, args ...string) error { +// ffmpeg calls `ffmpeg [args...]` (WASM) with in + out paths mounted in runtime. +func ffmpeg(ctx context.Context, inpath string, outpath string, args ...string) error { var stderr byteutil.Buffer rc, err := _ffmpeg.Ffmpeg(ctx, _ffmpeg.Args{ Stderr: &stderr, Args: args, Config: func(modcfg wazero.ModuleConfig) wazero.ModuleConfig { - fscfg := wazero.NewFSConfig() // needs /dev/urandom - fscfg = fscfg.WithReadOnlyDirMount("/dev", "/dev") - fscfg = fscfg.WithDirMount(dirpath, dirpath) - modcfg = modcfg.WithFSConfig(fscfg) - return modcfg + fscfg := wazero.NewFSConfig() + + // Needs read-only access to + // /dev/urandom for some types. + urandom := &allowFiles{ + { + abs: "/dev/urandom", + flag: os.O_RDONLY, + perm: 0, + }, + } + fscfg = fscfg.WithFSMount(urandom, "/dev") + + // In+out dirs are always the same (tmp), + // so we can share one file system for + // both + grant different perms to inpath + // (read only) and outpath (read+write). + shared := &allowFiles{ + { + abs: inpath, + flag: os.O_RDONLY, + perm: 0, + }, + { + abs: outpath, + flag: os.O_RDWR | os.O_CREATE | os.O_TRUNC, + perm: 0666, + }, + } + fscfg = fscfg.WithFSMount(shared, path.Dir(inpath)) + + return modcfg.WithFSConfig(fscfg) }, }) if err != nil { @@ -183,9 +202,6 @@ func ffmpeg(ctx context.Context, dirpath string, args ...string) error { func ffprobe(ctx context.Context, filepath string) (*result, error) { var stdout byteutil.Buffer - // Get directory from filepath. - dirpath := path.Dir(filepath) - // Run ffprobe on our given file at path. _, err := _ffmpeg.Ffprobe(ctx, _ffmpeg.Args{ Stdout: &stdout, @@ -222,9 +238,19 @@ func ffprobe(ctx context.Context, filepath string) (*result, error) { Config: func(modcfg wazero.ModuleConfig) wazero.ModuleConfig { fscfg := wazero.NewFSConfig() - fscfg = fscfg.WithReadOnlyDirMount(dirpath, dirpath) - modcfg = modcfg.WithFSConfig(fscfg) - return modcfg + + // Needs read-only access + // to file being probed. + in := &allowFiles{ + { + abs: filepath, + flag: os.O_RDONLY, + perm: 0, + }, + } + fscfg = fscfg.WithFSMount(in, path.Dir(filepath)) + + return modcfg.WithFSConfig(fscfg) }, }) if err != nil { |