commit 27241df5207a293b8452e92bd0b030dad233547b
Author: Yawning Angel <yawning(a)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
}