commit 27241df5207a293b8452e92bd0b030dad233547b Author: Yawning Angel yawning@schwanenlied.me Date: Thu Dec 1 01:39:59 2016 +0000
Bundle version handling improvements.
* Add the ability to compare string formatted versions vs the installed version in the manifest. * On update, check to ensure that it will actually be an update, and not a sidegrade/downgrade.
The code banks on alpha versioning starting at 1, eg: "7.0a1". --- .../internal/sandbox/application.go | 2 +- .../internal/ui/config/manifest.go | 84 +++++++++++++++++----- .../sandboxed-tor-browser/internal/ui/install.go | 11 ++- 3 files changed, 75 insertions(+), 22 deletions(-)
diff --git a/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go b/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go index a431dac..7620802 100644 --- a/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go +++ b/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go @@ -287,7 +287,7 @@ func applyPaXAttributes(manif *config.Manifest, f string) error { // Strip off the attribute if this is a non-grsec kernel, or the bundle is // sufficiently recent to the point where the required W^X fixes are present // in the JIT. - if !IsGrsecKernel() || manif.BundleVersionAtLeast(7, 0) { + if !IsGrsecKernel() || manif.BundleVersionAtLeast("7.0a1") { if sz > 0 { log.Printf("sandbox: Removing Tor Browser PaX attributes.") syscall.Removexattr(f, paxAttr) diff --git a/src/cmd/sandboxed-tor-browser/internal/ui/config/manifest.go b/src/cmd/sandboxed-tor-browser/internal/ui/config/manifest.go index 4891d37..393a31e 100644 --- a/src/cmd/sandboxed-tor-browser/internal/ui/config/manifest.go +++ b/src/cmd/sandboxed-tor-browser/internal/ui/config/manifest.go @@ -71,38 +71,84 @@ func (m *Manifest) Sync() error {
// BundleVersionAtLeast returns true if the bundle version is greater than or // equal to the specified version. -func (m *Manifest) BundleVersionAtLeast(major, minor int) bool { - vStr := strings.TrimSuffix(m.Version, "-hardened") - if m.Version == "" { +func (m *Manifest) BundleVersionAtLeast(vStr string) bool { + cmp, err := bundleVersionCompare(m.Version, vStr) + if err != nil { return false } - if m.Channel == "alpha" || m.Channel == "hardened" { - vStr = strings.Replace(vStr, "a", ".", 1) - } + return cmp >= 0 +}
- // Split into major/minor/pl. - v := strings.Split(vStr, ".") - if len(v) < 2 { // Need at least a major/minor. +// BundleUpdateVersionValid returns true if the proposed update version is +// actually an update. +func (m *Manifest) BundleUpdateVersionValid(vStr string) bool { + cmp, err := bundleVersionCompare(m.Version, vStr) + if err != nil { return false } + return cmp < 0 +} + +func bundleVersionParse(vStr string) (*[4]int, error) { + vStr = strings.TrimSuffix(vStr, "-hardened") + vStr = strings.Replace(vStr, "a", ".0.", 1) + + var out [4]int + for idx, s := range strings.Split(vStr, ".") { + i, err := strconv.Atoi(s) + if err != nil { + return nil, err + } + out[idx] = i + } + out[3] = -out[3] // XXX: I hope there never is "7.0a" or "7.0a0" + + return &out, nil +} + +func bundleVersionCompare(a, b string) (int, error) { + a = strings.ToLower(strings.TrimSpace(a)) + b = strings.ToLower(strings.TrimSpace(b)) + + if a == b { + return 0, nil // Equal. + }
- iMaj, err := strconv.Atoi(v[0]) + aVer, err := bundleVersionParse(a) if err != nil { - return false + return 0, err } - iMin, err := strconv.Atoi(v[1]) + bVer, err := bundleVersionParse(b) if err != nil { - return false + return 0, err + } + + for i := 0; i < 3; i++ { + if aVer[i] > bVer[i] { + return 1, nil + } + if aVer[i] < bVer[i] { + return -1, nil + } + } + + if aVer[3] < 0 && bVer[3] >= 0 { // Alpha vs Release. + return -1, nil + } + if aVer[3] >= 0 && bVer[3] < 0 { // Release vs Alpha. + return 1, nil }
- // Do the version comparison. - if iMaj > major { - return true + // Alpha vs Alpha. + aVer[3], bVer[3] = -aVer[3], -bVer[3] + if aVer[3] < bVer[3] { + return -1, nil } - if iMaj == major && iMin >= minor { - return true + if bVer[3] < aVer[3] { + return 1, nil } - return false + + return 0, nil // One is probably hardened, the other isn't. }
// Purge deletes the manifest. diff --git a/src/cmd/sandboxed-tor-browser/internal/ui/install.go b/src/cmd/sandboxed-tor-browser/internal/ui/install.go index 16bde15..5680319 100644 --- a/src/cmd/sandboxed-tor-browser/internal/ui/install.go +++ b/src/cmd/sandboxed-tor-browser/internal/ui/install.go @@ -210,11 +210,18 @@ func (c *Common) doUpdate(async *Async, dialFn dialFunc) { return }
+ // Ensure that the update entry version is actually neweer. + if !c.Manif.BundleUpdateVersionValid(update.AppVersion) { + log.Printf("launch: Update server provided a downgrade: '%v'", update.AppVersion) + async.Err = fmt.Errorf("update server provided a downgrade: '%v'", update.AppVersion) + return + } + // Figure out the best MAR to download. patches := make(map[string]*installer.Patch) for _, v := range update.Patch { if patches[v.Type] != nil { - async.Err = fmt.Errorf("duplicate patch entry for kind: %v", v.Type) + async.Err = fmt.Errorf("duplicate patch entry for kind: '%v'", v.Type) return } patches[v.Type] = &v @@ -253,7 +260,7 @@ func (c *Common) doUpdate(async *Async, dialFn dialFunc) { return } default: - async.Err = fmt.Errorf("unsupported hash function: %v", patch.HashFunction) + async.Err = fmt.Errorf("unsupported hash function: '%v'", patch.HashFunction) return }