blob: 6dd3a4312bb0700be2d89670feaea1caf3764166 [file] [log] [blame]
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import glob
import logging
import os
import tempfile
from autotest_lib.client.bin import test
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib import utils
PARTITION_TEST_PATH = 'platform_SecureEraseFile_test_file'
TEST_PATH = '/mnt/stateful_partition/' + PARTITION_TEST_PATH
BINARY = '/usr/bin/secure_erase_file'
DEVNAME_PREFIX = 'DEVNAME='
class platform_SecureEraseFile(test.test):
"""Validate secure_erase_file tool behavior.
We can't verify from this test that data has been destroyed from the
underlying physical device, but we can confirm that it's not reachable from
userspace.
"""
version = 1
def __write_test_file(self, path, blocksize, count):
cmd = '/bin/dd if=/dev/urandom of=%s bs=%s count=%d' % (
path, blocksize, count)
utils.run(cmd)
if not os.path.exists(path):
raise error.TestError('Failed to generate test file')
def __get_partition(self, path):
info = os.lstat(path)
major = os.major(info.st_dev)
minor = os.minor(info.st_dev)
uevent_path = '/sys/dev/block/%d:%d/uevent' % (major, minor)
with open(uevent_path, 'r') as uevent_file:
for l in uevent_file.readlines():
if l.startswith(DEVNAME_PREFIX):
return '/dev/' + l[len(DEVNAME_PREFIX):].strip()
raise error.TestError('Unable to find partition for path: ' + path)
def __get_extents(self, path, partition):
extents = []
cmd = 'debugfs -R "extents %s" %s' % (path, partition)
result = utils.run(cmd)
for line in result.stdout.splitlines():
# Discard header line.
if line.startswith('Level'):
continue
fields = line.split()
# Ignore non-leaf extents
if fields[0].strip('/') != fields[1]:
continue
extents.append({'offset': fields[7], 'length': fields[10]})
return extents
def __verify_cleared(self, partition, extents):
out_path = tempfile.mktemp()
for e in extents:
cmd = 'dd if=%s bs=4K skip=%s count=%s of=%s' % (
partition, e['offset'], e['length'], out_path)
utils.run(cmd)
with open(out_path, 'r') as out_file:
d = out_file.read()
for i, byte in enumerate(d):
if ord(byte) != 0x00 and ord(byte) != 0xFF:
logging.info('extent[%d] = %s', i, hex(ord(byte)))
raise error.TestError('Bad byte found')
def __test_and_verify_cleared(self, blocksize, count):
self.__write_test_file(TEST_PATH, blocksize, count)
utils.run('sync')
logging.info('original file contents: ')
res = utils.run('xxd %s' % TEST_PATH)
logging.info(res.stdout)
partition = self.__get_partition(TEST_PATH)
extents = self.__get_extents(PARTITION_TEST_PATH, partition)
if len(extents) == 0:
raise error.TestError('No extents found for ' + TEST_PATH)
utils.run('%s %s' % (BINARY, TEST_PATH))
# secure_erase_file confirms that the file has been erased and that its
# contents are not accessible. If that is not the case, it will return
# with a non-zero exit code.
if os.path.exists(TEST_PATH):
raise error.TestError('Secure Erase failed to unlink file.')
self.__verify_cleared(partition, extents)
def run_once(self):
# Secure erase is only supported on eMMC today; pass if
# no device is present.
if len(glob.glob('/dev/mmcblk*')) == 0:
raise error.TestNAError('Skipping test; no eMMC device found.')
self.__test_and_verify_cleared('64K', 2)
self.__test_and_verify_cleared('1M', 16)
def after_run_once(self):
if os.path.exists(TEST_PATH):
os.unlink(TEST_PATH)