summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2012-05-04 16:52:02 -0700
committerGerrit <chrome-bot@google.com>2012-05-17 13:32:27 -0700
commite97760cec3a4e08f6b3b3266bfcb02137197a7a7 (patch)
tree6308492b933472758ff7bd282b9b6d7c4eb95526
parentfeac077c1d96d81f9c1c0b5253d0223b0a2d9448 (diff)
downloadvboot-e97760cec3a4e08f6b3b3266bfcb02137197a7a7.tar.gz
mount-encrypted: provide umount option for shutdown
When shutting the system down, mount-encrypted can be used to clean up all its bind mounts and devices. BUG=None TEST=x86-alex build, manual testing Change-Id: I025ce8c16c55f8556d7fff45eb6ac2b7a835101a Signed-off-by: Kees Cook <keescook@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/21913 Reviewed-by: Elly Jones <ellyjones@chromium.org>
-rw-r--r--utility/mount-encrypted.c34
-rw-r--r--utility/mount-encrypted.h76
-rw-r--r--utility/mount-helpers.c89
-rw-r--r--utility/mount-helpers.h3
4 files changed, 155 insertions, 47 deletions
diff --git a/utility/mount-encrypted.c b/utility/mount-encrypted.c
index 37c4d607..a62de854 100644
--- a/utility/mount-encrypted.c
+++ b/utility/mount-encrypted.c
@@ -829,6 +829,34 @@ failed:
return 0;
}
+/* Clean up all bind mounts, mounts, attaches, etc. Only the final
+ * action informs the return value. This makes it so that failures
+ * can be cleaned up from, and continue the shutdown process on a
+ * second call. If the loopback cannot be found, claim success.
+ */
+static int shutdown(void)
+{
+ struct bind_mount *bind;
+
+ for (bind = bind_mounts; bind->src; ++ bind) {
+ INFO("Unmounting %s.", bind->dst);
+ if (umount(bind->dst))
+ PERROR("umount(%s)", bind->dst);
+ }
+
+ /* TODO(keescook): this can actually succeed with binds mounted. */
+ INFO("Unmounting %s.", kEncryptedMount);
+ if (umount(kEncryptedMount))
+ PERROR("umount(%s)", kEncryptedMount);
+
+ INFO("Removing %s.", kCryptDev);
+ if (!dm_teardown(kCryptDev))
+ ERROR("dm_teardown(%s)", kCryptDev);
+
+ INFO("Unlooping %s.", kEncryptedBlock);
+ return loop_detach_name(kEncryptedBlock) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
static void check_mount_states(void)
{
@@ -909,12 +937,14 @@ int main(int argc, char *argv[])
tpm_init();
if (argc > 1) {
+ if (!strcmp(argv[1], "umount"))
+ return shutdown();
if (!strcmp(argv[1], "device"))
return device_details();
if (!strcmp(argv[1], "finalize"))
return finalize_from_cmdline(argc > 2 ? argv[2] : NULL);
- fprintf(stderr, "Usage: %s [device|finalize]\n",
+ fprintf(stderr, "Usage: %s [device|finalize|umount]\n",
argv[0]);
return 1;
}
@@ -929,7 +959,7 @@ int main(int argc, char *argv[])
okay = setup_encrypted();
}
- INFO("Done.");
+ INFO_DONE("Done.");
/* Continue boot. */
return !okay;
diff --git a/utility/mount-encrypted.h b/utility/mount-encrypted.h
index d84de4f9..e3a85d95 100644
--- a/utility/mount-encrypted.h
+++ b/utility/mount-encrypted.h
@@ -7,7 +7,8 @@
#ifndef _MOUNT_ENCRYPTED_H_
#define _MOUNT_ENCRYPTED_H_
-#define DEBUG_ENABLED 0
+#define DEBUG_ENABLED 1
+#define DEBUG_TIME_DELTA 1
#include <openssl/err.h>
#include <openssl/sha.h>
@@ -15,8 +16,8 @@
#define DIGEST_LENGTH SHA256_DIGEST_LENGTH
#define _ERROR(f, a...) do { \
- fprintf(stderr, "ERROR %s (%s, %d): ", \
- __func__, __FILE__, __LINE__); \
+ fprintf(stderr, "ERROR[pid:%d] %s (%s, %d): ", \
+ getpid(), __func__, __FILE__, __LINE__); \
fprintf(stderr, f, ## a); \
} while (0)
#define ERROR(f, a...) do { \
@@ -39,48 +40,87 @@
#if DEBUG_ENABLED
static struct timeval tick;
-# define TICK_INIT() gettimeofday(&tick, NULL)
+static struct timeval tick_start;
+# define TICK_INIT() do { \
+ gettimeofday(&tick, NULL); \
+ tick_start = tick; \
+} while (0)
# ifdef DEBUG_TIME_DELTA
+/* This timeval helper copied from glibc manual. */
+static inline int timeval_subtract(struct timeval *result,
+ struct timeval *x,
+ struct timeval *y)
+{
+ /* Perform the carry for the later subtraction by updating y. */
+ if (x->tv_usec < y->tv_usec) {
+ int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
+ y->tv_usec -= 1000000 * nsec;
+ y->tv_sec += nsec;
+ }
+ if (x->tv_usec - y->tv_usec > 1000000) {
+ int nsec = (x->tv_usec - y->tv_usec) / 1000000;
+ y->tv_usec += 1000000 * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait.
+ * tv_usec is certainly positive.
+ */
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_usec = x->tv_usec - y->tv_usec;
+
+ /* Return 1 if result is negative. */
+ return x->tv_sec < y->tv_sec;
+}
# define TICK_REPORT() do { \
struct timeval now, diff; \
gettimeofday(&now, NULL); \
- diff.tv_sec = now.tv_sec - tick.tv_sec; \
- if (tick.tv_usec > now.tv_usec) { \
- diff.tv_sec -= 1; \
- diff.tv_usec = 1000000 - tick.tv_usec + now.tv_usec; \
- } else { \
- diff.tv_usec = now.tv_usec - tick.tv_usec; \
- } \
+ timeval_subtract(&diff, &now, &tick); \
+ printf("\tTook: [pid:%d, %2lu.%06lus]\n", getpid(), \
+ (unsigned long)diff.tv_sec, (unsigned long)diff.tv_usec); \
tick = now; \
- printf("\tTook: [%2d.%06d]\n", (int)diff.tv_sec, (int)diff.tv_usec); \
} while (0)
# else
# define TICK_REPORT() do { \
gettimeofday(&tick, NULL); \
- printf("[%d:%2d.%06d] ", getpid(), (int)tick.tv_sec, (int)tick.tv_usec); \
+ printf("[%2d.%06d] ", (int)tick.tv_sec, (int)tick.tv_usec); \
} while (0)
# endif
+# define TICK_DONE() do { \
+ struct timeval tick_done; \
+ TICK_REPORT(); \
+ timeval_subtract(&tick_done, &tick, &tick_start); \
+ printf("Process Lifetime: [pid:%d, %2d.%06ds]\n", getpid(), \
+ (int)tick_done.tv_sec, (int)tick_done.tv_usec); \
+} while (0)
#else
# define TICK_INIT() do { } while (0)
# define TICK_REPORT() do { } while (0)
+# define TICK_DONE() do { } while (0)
#endif
-#define INFO(f, a...) do { \
- TICK_REPORT(); \
+#define _INFO(f, a...) do { \
+ printf("[pid:%d] ", getpid()); \
printf(f, ## a); \
printf("\n"); \
fflush(stdout); \
} while (0)
+#define INFO(f, a...) do { \
+ TICK_REPORT(); \
+ _INFO(f, ## a); \
+} while (0)
#define INFO_INIT(f, a...) do { \
TICK_INIT(); \
INFO(f, ## a); \
} while (0)
+#define INFO_DONE(f, a...) do { \
+ TICK_DONE(); \
+ INFO(f, ## a); \
+} while (0)
#if DEBUG_ENABLED
# define DEBUG(f, a...) do { \
TICK_REPORT(); \
- printf(f, ## a); \
- printf("\n"); \
- fflush(stdout); \
+ _INFO(f, ## a); \
} while (0)
#else
# define DEBUG(f, a...) do { } while (0)
diff --git a/utility/mount-helpers.c b/utility/mount-helpers.c
index bd7a5218..05214973 100644
--- a/utility/mount-helpers.c
+++ b/utility/mount-helpers.c
@@ -155,23 +155,29 @@ static int is_loop_device(int fd)
major(info.st_rdev) == kLoopMajor);
}
-static int loop_is_attached(int fd)
+static int loop_is_attached(int fd, struct loop_info64 *info)
{
- struct loop_info info;
+ struct loop_info64 local_info;
- errno = 0;
- if (ioctl(fd, LOOP_GET_STATUS, &info) && errno == ENXIO)
- return 0;
-
- return 1;
+ return ioctl(fd, LOOP_GET_STATUS64, info ? info : &local_info) == 0;
}
-static int loop_allocate(gchar **loopback)
+/* Returns either the matching loopback name, or next available, if NULL. */
+static int loop_locate(gchar **loopback, const char *name)
{
- int i, fd;
+ int i, fd, namelen = 0;
+
+ if (name) {
+ namelen = strlen(name);
+ if (namelen >= LO_NAME_SIZE)
+ return -1;
+ }
*loopback = NULL;
for (i = 0; i < kLoopMax; ++i) {
+ struct loop_info64 info;
+ int attached;
+
g_free(*loopback);
*loopback = g_strdup_printf(kLoopTemplate, i);
if (!*loopback) {
@@ -184,13 +190,24 @@ static int loop_allocate(gchar **loopback)
PERROR("open(%s)", *loopback);
goto failed;
}
- if (is_loop_device(fd) && !loop_is_attached(fd)) {
+ if (!is_loop_device(fd)) {
close(fd);
+ continue;
+ }
+
+ memset(&info, 0, sizeof(info));
+ attached = loop_is_attached(fd, &info);
+ close(fd);
+
+ if ((attached && name &&
+ strncmp((char *)info.lo_file_name, name, namelen) == 0) ||
+ (!attached && !name)) {
+ /* Reopen for working on it. */
fd = open(*loopback, O_RDWR | O_NOFOLLOW);
- if (is_loop_device(fd) && !loop_is_attached(fd))
+ if (is_loop_device(fd) &&
+ loop_is_attached(fd, NULL) == attached)
return fd;
}
- close(fd);
}
ERROR("Ran out of loopback devices");
@@ -200,37 +217,55 @@ failed:
return -1;
}
+static int loop_detach_fd(int fd)
+{
+ if (ioctl(fd, LOOP_CLR_FD, 0)) {
+ PERROR("LOOP_CLR_FD");
+ return 0;
+ }
+ return 1;
+}
+
int loop_detach(const gchar *loopback)
{
- int fd;
+ int fd, rc = 1;
fd = open(loopback, O_RDONLY | O_NOFOLLOW);
if (fd < 0) {
PERROR("open(%s)", loopback);
return 0;
}
- if (!is_loop_device(fd) || !loop_is_attached(fd))
- goto failed;
- if (ioctl(fd, LOOP_CLR_FD, 0)) {
- PERROR("LOOP_CLR_FD");
- goto failed;
- }
+ if (!is_loop_device(fd) || !loop_is_attached(fd, NULL) ||
+ !loop_detach_fd(fd))
+ rc = 0;
close (fd);
- return 1;
+ return rc;
+}
-failed:
- close(fd);
- return 0;
+int loop_detach_name(const char *name)
+{
+ gchar *loopback = NULL;
+ int loopfd, rc;
+
+ loopfd = loop_locate(&loopback, name);
+ if (loopfd < 0)
+ return 0;
+ rc = loop_detach_fd(loopfd);
+
+ close(loopfd);
+ g_free(loopback);
+ return rc;
}
+/* Closes fd, returns name of loopback device pathname. */
gchar *loop_attach(int fd, const char *name)
{
gchar *loopback = NULL;
int loopfd;
struct loop_info64 info;
- loopfd = loop_allocate(&loopback);
+ loopfd = loop_locate(&loopback, NULL);
if (loopfd < 0)
return NULL;
if (ioctl(loopfd, LOOP_SET_FD, fd) < 0) {
@@ -295,7 +330,7 @@ int dm_setup(size_t sectors, const gchar *encryption_key, const char *name,
return 1;
}
-void dm_teardown(const gchar *device)
+int dm_teardown(const gchar *device)
{
const char *argv[] = {
"/sbin/dmsetup",
@@ -304,7 +339,9 @@ void dm_teardown(const gchar *device)
NULL
};
/* TODO(keescook): replace with call to libdevmapper. */
- runcmd(argv, NULL);
+ if (runcmd(argv, NULL) != 0)
+ return 0;
+ return 1;
}
char *dm_get_key(const gchar *device)
diff --git a/utility/mount-helpers.h b/utility/mount-helpers.h
index 66fb1026..19f6242f 100644
--- a/utility/mount-helpers.h
+++ b/utility/mount-helpers.h
@@ -18,11 +18,12 @@ uint8_t *hexify_string(char *string, uint8_t *binary, size_t length);
/* Loopback device attach/detach helpers. */
gchar *loop_attach(int fd, const char *name);
int loop_detach(const gchar *loopback);
+int loop_detach_name(const char *name);
/* Encrypted device mapper setup/teardown. */
int dm_setup(size_t sectors, const gchar *encryption_key, const char *name,
const gchar *device, const char *path);
-void dm_teardown(const gchar *device);
+int dm_teardown(const gchar *device);
char *dm_get_key(const gchar *device);
/* Sparse file creation. */