From c8ee5d27503af87aa18f79713f939cff2ddf1672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 24 May 2016 14:48:21 -0400 Subject: [PATCH 1/2] CVE-2016-1581: Fix bad permissions on zfs.img MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using a file backed zpool as created by "lxd init", the created file was world readable, which would allow an untrusted user to read container data. This fix makes sure that zfs.img is always created 600 from now on and also fixes the permission of any zfs.img file at LXD startup time. Reported-by: Robie Basak Signed-off-by: Stéphane Graber --- lxd/db.go | 2 +- lxd/db_update.go | 19 +++++++++++++++++++ lxd/main.go | 5 +++++ test/main.sh | 4 ++++ test/suites/security.sh | 26 ++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 test/suites/security.sh diff --git a/lxd/db.go b/lxd/db.go index ca6d5d4..4b71cea 100644 --- a/lxd/db.go +++ b/lxd/db.go @@ -34,7 +34,7 @@ type Profile struct { // Profiles will contain a list of all Profiles. type Profiles []Profile -const DB_CURRENT_VERSION int = 29 +const DB_CURRENT_VERSION int = 30 // CURRENT_SCHEMA contains the current SQLite SQL Schema. const CURRENT_SCHEMA string = ` diff --git a/lxd/db_update.go b/lxd/db_update.go index 4b0df51..509d149 100644 --- a/lxd/db_update.go +++ b/lxd/db_update.go @@ -15,6 +15,19 @@ import ( log "gopkg.in/inconshreveable/log15.v2" ) +func dbUpdateFromV29(db *sql.DB) error { + if shared.PathExists(shared.VarPath("zfs.img")) { + err := os.Chmod(shared.VarPath("zfs.img"), 0600) + if err != nil { + return err + } + } + + stmt := `INSERT INTO schema (version, updated_at) VALUES (?, strftime("%s"));` + _, err := db.Exec(stmt, 30) + return err +} + func dbUpdateFromV28(db *sql.DB) error { stmt := ` INSERT INTO profiles_devices (profile_id, name, type) SELECT id, "aadisable", 2 FROM profiles WHERE name="docker"; @@ -999,6 +1012,12 @@ func dbUpdate(d *Daemon, prevVersion int) error { return err } } + if prevVersion < 30 { + err = dbUpdateFromV29(db) + if err != nil { + return err + } + } return nil } diff --git a/lxd/main.go b/lxd/main.go index 27265b8..156decb 100644 --- a/lxd/main.go +++ b/lxd/main.go @@ -855,6 +855,11 @@ they otherwise would. return fmt.Errorf("Failed to open %s: %s", storageDevice, err) } + err = f.Chmod(0600) + if err != nil { + return fmt.Errorf("Failed to chmod %s: %s", storageDevice, err) + } + err = f.Truncate(int64(storageLoopSize * 1024 * 1024 * 1024)) if err != nil { return fmt.Errorf("Failed to create sparse file %s: %s", storageDevice, err) diff --git a/test/main.sh b/test/main.sh index 5b5f486..fa22aa3 100755 --- a/test/main.sh +++ b/test/main.sh @@ -377,6 +377,10 @@ echo "==> TEST: basic usage" TEST_CURRENT=test_basic_usage test_basic_usage +echo "==> TEST: security" +TEST_CURRENT=test_security +test_security + echo "==> TEST: images (and cached image expiry)" TEST_CURRENT=test_image_expiry test_image_expiry diff --git a/test/suites/security.sh b/test/suites/security.sh new file mode 100644 index 0000000..ae9e9eb --- /dev/null +++ b/test/suites/security.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +test_security() { + ensure_import_testimage + ensure_has_localhost_remote "${LXD_ADDR}" + + # CVE-2016-1581 + if [ "${LXD_BACKEND}" = "zfs" ]; then + LXD_INIT_DIR=$(mktemp -d -p "${TEST_DIR}" XXX) + chmod +x "${LXD_INIT_DIR}" + spawn_lxd "${LXD_INIT_DIR}" + + ZFS_POOL="lxdtest-$(basename "${LXD_DIR}")-init" + LXD_DIR=${LXD_INIT_DIR} lxd init --storage-backend zfs --storage-create-loop 1 --storage-pool "${ZFS_POOL}" --auto + + PERM=$(stat -c %a "${LXD_INIT_DIR}/zfs.img") + if [ "${PERM}" != "600" ]; then + echo "Bad zfs.img permissions: ${PERM}" + zpool destroy "${ZFS_POOL}" + false + fi + + zpool destroy "${ZFS_POOL}" + kill_lxd "${LXD_INIT_DIR}" + fi +} -- 2.7.4