commit e68ab9154e73f2fde78ffaf556f39670e4a807f5
Author: Yawning Angel <[email protected]>
Date:   Wed Dec 7 01:05:28 2016 +0000

    Bug #20899: Dunlib/PulseAudio fixes.
    
     * Try even harder to avoid sticking libraries with the wrong architecture
       in the container.
    
     * If libpulsecore can't be found, don't bindmount libpulse.so, since it
       will abort() in the stub.  No audio, but it beats crashing.
---
 .../sandboxed-tor-browser/internal/dynlib/cache.go |  4 +-
 .../sandboxed-tor-browser/internal/dynlib/ldso.go  | 30 +++++++-
 .../internal/sandbox/application.go                | 70 ++++++------------
 .../internal/sandbox/pulse.go                      | 85 +++++++++++++++++++++-
 4 files changed, 135 insertions(+), 54 deletions(-)

diff --git a/src/cmd/sandboxed-tor-browser/internal/dynlib/cache.go 
b/src/cmd/sandboxed-tor-browser/internal/dynlib/cache.go
index 4bcc60d..11f1ee3 100644
--- a/src/cmd/sandboxed-tor-browser/internal/dynlib/cache.go
+++ b/src/cmd/sandboxed-tor-browser/internal/dynlib/cache.go
@@ -94,7 +94,7 @@ func (c *Cache) ResolveLibraries(binaries []string, extraLibs 
[]string, ldLibrar
                        break
                }
                for _, fn := range toCheck {
-                       impLibs, err := GetLibraries(fn)
+                       impLibs, err := getLibraries(fn)
                        if err != nil {
                                return nil, err
                        }
@@ -373,6 +373,8 @@ func LoadCache() (*Cache, error) {
                // osVersion, or hwcap.
                if ourOsVersion < e.osVersion {
                        Debugf("dynlib: ignoring library: %v (osVersion: %x)", 
e.key, e.osVersion)
+               } else if err = ValidateLibraryClass(e.value); err != nil {
+                       Debugf("dynlib: ignoring library %v (%v)", e.key, err)
                } else if flagCheckFn(e.flags) && capCheckFn(e.hwcap) {
                        vec := c.store[e.key]
                        vec = append(vec, e)
diff --git a/src/cmd/sandboxed-tor-browser/internal/dynlib/ldso.go 
b/src/cmd/sandboxed-tor-browser/internal/dynlib/ldso.go
index 812a5a6..92e16c1 100644
--- a/src/cmd/sandboxed-tor-browser/internal/dynlib/ldso.go
+++ b/src/cmd/sandboxed-tor-browser/internal/dynlib/ldso.go
@@ -19,6 +19,7 @@ package dynlib
 import (
        "debug/elf"
        "errors"
+       "fmt"
        "os"
        "path/filepath"
        "runtime"
@@ -26,9 +27,7 @@ import (
 
 var errUnsupported = errors.New("dynlib: unsupported os/architecture")
 
-// GetLibraries returns the dynamic libraries imported by the given file at
-// dynamic link time.
-func GetLibraries(fn string) ([]string, error) {
+func getLibraries(fn string) ([]string, error) {
        f, err := elf.Open(fn)
        if err != nil {
                return nil, err
@@ -38,6 +37,31 @@ func GetLibraries(fn string) ([]string, error) {
        return f.ImportedLibraries()
 }
 
+// ValidateLibraryClass ensures that the library matches the current
+// architecture.
+func ValidateLibraryClass(fn string) error {
+       f, err := elf.Open(fn)
+       if err != nil {
+               return err
+       }
+       defer f.Close()
+
+       var expectedClass elf.Class
+       switch runtime.GOARCH {
+       case "amd64":
+               expectedClass = elf.ELFCLASS64
+       case "386":
+               expectedClass = elf.ELFCLASS32
+       default:
+               return errUnsupported
+       }
+
+       if f.Class != expectedClass {
+               return fmt.Errorf("unsupported class: %v", fn, f.Class)
+       }
+       return nil
+}
+
 // FindLdSo returns the path to the `ld.so` dynamic linker for the current
 // architecture, which is usually a symlink
 func FindLdSo(cache *Cache) (string, string, error) {
diff --git a/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go 
b/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
index 939d805..4cd4ca0 100644
--- a/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
+++ b/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
@@ -28,7 +28,6 @@ import (
        "path/filepath"
        "runtime"
        "sort"
-       "strings"
        "syscall"
 
        "cmd/sandboxed-tor-browser/internal/dynlib"
@@ -220,54 +219,13 @@ func RunTorBrowser(cfg *config.Config, manif 
*config.Manifest, tor *tor.Tor) (cm
                ldLibraryPath = ldLibraryPath + glLibPaths
 
                if cfg.Sandbox.EnablePulseAudio && pulseAudioWorks {
-                       const libPulse = "libpulse.so.0"
-
-                       paLibsPath := findDistributionDependentLibs(nil, "", 
"pulseaudio")
-                       if paLibsPath != "" && cache.GetLibraryPath(libPulse) 
!= "" {
-                               const restrictedPulseDir = "/usr/lib/pulseaudio"
-
-                               // The library search path 
("/usr/lib/pulseaudio"), is
-                               // hardcoded into libpulse.so.0, because you 
suck, and we hate
-                               // you.
-                               extraLibs = append(extraLibs, libPulse)
-                               ldLibraryPath = ldLibraryPath + ":" + paLibsPath
-                               h.dir(restrictedPulseDir)
-                               extraLdLibraryPath = extraLdLibraryPath + ":" + 
restrictedPulseDir
-
-                               boundPulseCore := false
-                               matches, err := filepath.Glob(paLibsPath + 
"/*.so")
-                               if err != nil {
-                                       return nil, err
-                               }
-                               for _, v := range matches {
-                                       _, f := filepath.Split(v)
-                                       if strings.HasPrefix(f, "libpulsecore") 
{
-                                               boundPulseCore = true
-                                       }
-                                       h.roBind(v, 
filepath.Join(restrictedPulseDir, f), false)
-                                       extraLibs = append(extraLibs, f)
-                               }
-
-                               if !boundPulseCore {
-                                       // Debian sticks libpulsecore-blah.so 
in /usr/lib, unlike
-                                       // everyone else who sticks it in 
/usr/lib/pulseaudo,
-                                       // because fuck you.
-                                       matches, err = 
filepath.Glob("/usr/lib/libpulsecore-*.so")
-                                       if err != nil {
-                                               return nil, err
-                                       }
-                                       if len(matches) == 0 {
-                                               log.Printf("sandbox: Failed to 
find `libpulsecore-<version>.so`, audio will crash the browser.")
-                                       } else {
-                                               for _, v := range matches {
-                                                       _, f := 
filepath.Split(v)
-                                                       h.roBind(v, 
filepath.Join(restrictedPulseDir, f), false)
-                                                       extraLibs = 
append(extraLibs, f)
-                                               }
-                                       }
-                               }
+                       paLibs, paPath, paExtraPath, err := 
h.appendRestrictedPulseAudio(cache)
+                       if err != nil {
+                               log.Printf("sandbox: Failed to find PulseAudio 
libraries: %v", err)
                        } else {
-                               log.Printf("sandbox: Failed to find pulse audio 
libraries.")
+                               extraLibs = append(extraLibs, paLibs...)
+                               ldLibraryPath = ldLibraryPath + paPath
+                               extraLdLibraryPath = extraLdLibraryPath + 
paExtraPath
                        }
                }
                if codec := findBestCodec(cache); codec != "" {
@@ -588,7 +546,21 @@ func findDistributionDependentLibs(extraSearch []string, 
subDir, fn string) stri
 
        for _, base := range searchPaths {
                candidate := filepath.Join(base, subDir, fn)
-               if FileExists(candidate) {
+               if FileExists(candidate) && 
dynlib.ValidateLibraryClass(candidate) == nil {
+                       return candidate
+               }
+       }
+       return ""
+}
+
+func findDistributionDependentDir(extraSearch []string, subDir, fn string) 
string {
+       var searchPaths []string
+       searchPaths = append(searchPaths, extraSearch...)
+       searchPaths = append(searchPaths, distributionDependentLibSearchPath...)
+
+       for _, base := range searchPaths {
+               candidate := filepath.Join(base, subDir, fn)
+               if DirExists(candidate) {
                        return candidate
                }
        }
diff --git a/src/cmd/sandboxed-tor-browser/internal/sandbox/pulse.go 
b/src/cmd/sandboxed-tor-browser/internal/sandbox/pulse.go
index 0b2fd6d..c58843b 100644
--- a/src/cmd/sandboxed-tor-browser/internal/sandbox/pulse.go
+++ b/src/cmd/sandboxed-tor-browser/internal/sandbox/pulse.go
@@ -24,6 +24,9 @@ import (
        "strings"
 
        xdg "github.com/cep21/xdgbasedir"
+
+       "cmd/sandboxed-tor-browser/internal/dynlib"
+       . "cmd/sandboxed-tor-browser/internal/utils"
 )
 
 func (h *hugbox) enablePulseAudio() error {
@@ -48,7 +51,7 @@ func (h *hugbox) enablePulseAudio() error {
        }
 
        if fi, err := os.Stat(sockPath); err != nil {
-               // No pulse Audio socket.
+               // No PulseAudio socket.
                return fmt.Errorf("sandbox: no PulseAudio socket")
        } else if fi.Mode()&os.ModeSocket == 0 {
                // Not an AF_LOCAL socket.
@@ -93,3 +96,83 @@ func (h *hugbox) enablePulseAudio() error {
 
        return nil
 }
+
+func (h *hugbox) appendRestrictedPulseAudio(cache *dynlib.Cache) ([]string, 
string, string, error) {
+       const libPulse = "libpulse.so.0"
+
+       type roBindEnt struct {
+               src, dst string
+       }
+       toRoBind := []roBindEnt{}
+
+       extraLibs := []string{}
+       ldLibraryPath := ""
+       extraLdLibraryPath := ""
+
+       paLibsPath := findDistributionDependentDir(nil, "", "pulseaudio")
+       if paLibsPath != "" && cache.GetLibraryPath(libPulse) != "" {
+               const restrictedPulseDir = "/usr/lib/pulseaudio"
+
+               // The library search path ("/usr/lib/pulseaudio"), is
+               // hardcoded into libpulse.so.0, because you suck, and we hate
+               // you.
+
+               extraLibs = append(extraLibs, libPulse)
+               ldLibraryPath = ldLibraryPath + ":" + paLibsPath
+               extraLdLibraryPath = extraLdLibraryPath + ":" + 
restrictedPulseDir
+
+               // The special handling for libpulsecore is because, we need to 
dlopen
+               // it in our stub.
+
+               boundPulseCore := false
+               matches, err := filepath.Glob(paLibsPath + "/*.so")
+               if err != nil {
+                       return nil, "", "", err
+               }
+               for _, v := range matches {
+                       if dynlib.ValidateLibraryClass(v) != nil {
+                               Debugf("sandbox: Unsuitable PulseAudio so: %v", 
v)
+                               continue
+                       }
+                       _, f := filepath.Split(v)
+                       if strings.HasPrefix(f, "libpulsecore") {
+                               boundPulseCore = true
+                       }
+                       toRoBind = append(toRoBind, roBindEnt{v, 
filepath.Join(restrictedPulseDir, f)})
+                       extraLibs = append(extraLibs, f)
+               }
+
+               // Debian sticks libpulsecore-blah.so in /usr/lib, unlike
+               // everyone else who sticks it in /usr/lib/pulseaudo,
+               // because fuck you.
+               if !boundPulseCore {
+                       matches, err = 
filepath.Glob("/usr/lib/libpulsecore-*.so")
+                       if err != nil {
+                               return nil, "", "", err
+                       }
+                       for _, v := range matches {
+                               if dynlib.ValidateLibraryClass(v) != nil {
+                                       Debugf("sandbox: Unsuitable pulsecore: 
%v", v)
+                                       continue
+                               }
+                               _, f := filepath.Split(v)
+                               toRoBind = append(toRoBind, roBindEnt{v, 
filepath.Join(restrictedPulseDir, f)})
+                               extraLibs = append(extraLibs, f)
+                               boundPulseCore = true
+                               break
+                       }
+               }
+
+               // Now that we're done trying to find all the PulseAudio bits,
+               // actually bindmount everything into the sandbox.
+               if boundPulseCore {
+                       h.dir(restrictedPulseDir)
+                       for _, ent := range toRoBind {
+                               h.roBind(ent.src, ent.dst, false)
+                       }
+                       return extraLibs, ldLibraryPath, extraLdLibraryPath, nil
+               }
+       }
+
+       return nil, "", "", fmt.Errorf("failed to find PulseAudio libraries")
+}

_______________________________________________
tor-commits mailing list
[email protected]
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits

Reply via email to