summaryrefslogtreecommitdiff
path: root/internal/media/ffmpeg.go
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2024-08-30 14:03:59 +0200
committerLibravatar GitHub <noreply@github.com>2024-08-30 14:03:59 +0200
commitcd93a5baf35f9879a3a354ed4d196235af692142 (patch)
tree09f06685a62b41994e9479fec52eafec2b25a2aa /internal/media/ffmpeg.go
parent[chore] Only call `imaging.Resize when necessary`, use even tinier blurhashes... (diff)
downloadgotosocial-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.go88
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 {