All of lore.kernel.org
 help / color / mirror / Atom feed
From: agk@sourceware.org <agk@sourceware.org>
To: lvm-devel@redhat.com
Subject: LVM2 ./Makefile.in ./make.tmpl.in ./configure ...
Date: 26 Mar 2012 23:09:40 -0000	[thread overview]
Message-ID: <20120326230940.29002.qmail@sourceware.org> (raw)

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk at sourceware.org	2012-03-26 23:09:38

Modified files:
	.              : Makefile.in make.tmpl.in configure configure.in 
Added files:
	verity         : Makefile.in veritysetup.c 
Removed files:
	veritysetup    : Makefile.in veritysetup.c 

Log message:
	Rename verity dir

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/Makefile.in.diff?cvsroot=lvm2&r1=1.72&r2=1.73
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/make.tmpl.in.diff?cvsroot=lvm2&r1=1.132&r2=1.133
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/configure.diff?cvsroot=lvm2&r1=1.178&r2=1.179
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/configure.in.diff?cvsroot=lvm2&r1=1.193&r2=1.194
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/verity/Makefile.in.diff?cvsroot=lvm2&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/verity/veritysetup.c.diff?cvsroot=lvm2&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/veritysetup/Makefile.in.diff?cvsroot=lvm2&r1=1.1&r2=NONE
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/veritysetup/veritysetup.c.diff?cvsroot=lvm2&r1=1.2&r2=NONE

--- LVM2/Makefile.in	2012/03/23 09:39:03	1.72
+++ LVM2/Makefile.in	2012/03/26 23:09:37	1.73
@@ -36,12 +36,16 @@
   SUBDIRS += libdaemon
 endif
 
+ifeq ("@VERITYSETUP@", "yes")
+  SUBDIRS += verity
+endif
+
 # FIXME Should use intermediate Makefiles here!
 ifeq ($(MAKECMDGOALS),distclean)
   SUBDIRS = doc include man scripts \
     libdaemon lib tools daemons libdm \
     udev po liblvm test \
-    unit-tests/datastruct unit-tests/mm unit-tests/regex
+    unit-tests/datastruct unit-tests/mm unit-tests/regex verity
 endif
 DISTCLEAN_DIRS += lcov_reports*
 DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
@@ -53,6 +57,7 @@
 liblvm: lib
 daemons: lib libdaemon tools
 tools: lib libdaemon device-mapper
+verity: libdm
 po: tools daemons
 
 lib.device-mapper: include.device-mapper
--- LVM2/make.tmpl.in	2012/02/28 18:35:04	1.132
+++ LVM2/make.tmpl.in	2012/03/26 23:09:37	1.133
@@ -194,6 +194,7 @@
 POTFILES = $(SOURCES:%.c=%.pot)
 
 .PHONY: all pofile distclean clean cleandir cflow device-mapper
+.PHONY: verity install_verity $(SUBDIRS.install_verity)
 .PHONY: install install_cluster install_device-mapper install_lvm2
 .PHONY: install_lib_shared install_dm_plugin install_lvm2_plugin
 .PHONY: install_ocf
@@ -207,6 +208,7 @@
 SUBDIRS.install_device-mapper := $(SUBDIRS:=.install_device-mapper)
 SUBDIRS.install_lvm2 := $(SUBDIRS:=.install_lvm2)
 SUBDIRS.install_ocf := $(SUBDIRS:=.install_ocf)
+SUBDIRS.install_verity := $(SUBDIRS:=.install_verity)
 SUBDIRS.pofile := $(SUBDIRS:=.pofile)
 SUBDIRS.cflow := $(SUBDIRS:=.cflow)
 SUBDIRS.clean := $(SUBDIRS:=.clean)
--- LVM2/configure	2012/03/24 01:59:59	1.178
+++ LVM2/configure	2012/03/26 23:09:37	1.179
@@ -10913,7 +10913,7 @@
 
 
 ################################################################################
-ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile doc/Makefile doc/example.conf include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_!
 lvmetad_systemd_red_hat.socket scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/dm_event_systemd_red_hat.service scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile veritysetup/Makefile"
+ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile doc/Makefile doc/example.conf include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_!
 lvmetad_systemd_red_hat.socket scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/dm_event_systemd_red_hat.service scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile verity/Makefile"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -11657,7 +11657,7 @@
     "unit-tests/datastruct/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/datastruct/Makefile" ;;
     "unit-tests/regex/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/regex/Makefile" ;;
     "unit-tests/mm/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/mm/Makefile" ;;
-    "veritysetup/Makefile") CONFIG_FILES="$CONFIG_FILES veritysetup/Makefile" ;;
+    "verity/Makefile") CONFIG_FILES="$CONFIG_FILES verity/Makefile" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
--- LVM2/configure.in	2012/03/24 01:59:59	1.193
+++ LVM2/configure.in	2012/03/26 23:09:38	1.194
@@ -1641,7 +1641,7 @@
 unit-tests/datastruct/Makefile
 unit-tests/regex/Makefile
 unit-tests/mm/Makefile
-veritysetup/Makefile
+verity/Makefile
 ])
 AC_OUTPUT
 
/cvs/lvm2/LVM2/verity/Makefile.in,v  -->  standard output
revision 1.1
--- LVM2/verity/Makefile.in
+++ -	2012-03-26 23:09:39.480886000 +0000
@@ -0,0 +1,33 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This file is part of the device-mapper userspace tools.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+SOURCES = veritysetup.c
+
+TARGETS = veritysetup
+
+INCLUDES += @VERITYSETUP_CFLAGS@
+
+include $(top_builddir)/make.tmpl
+
+VERITYSETUP_LIBS = @VERITYSETUP_LIBS@
+
+all: veritysetup
+
+veritysetup: $(OBJECTS)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o veritysetup $(OBJECTS) $(VERITYSETUP_LIBS)
+
+install_verity: $(TARGETS)
+	$(INSTALL_PROGRAM) -D veritysetup $(sbindir)/veritysetup
/cvs/lvm2/LVM2/verity/veritysetup.c,v  -->  standard output
revision 1.1
--- LVM2/verity/veritysetup.c
+++ -	2012-03-26 23:09:39.593521000 +0000
@@ -0,0 +1,999 @@
+/*
+ * veritysetup
+ *
+ * (C) 2012 Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Compile flags to use a specific crypto library:
+ * openssl: -lpopt -DCRYPT_OPENSSL -lcrypto
+ * nss: -lpopt -DCRYPT_NSS -I/usr/include/nspr/ -I/usr/include/nss -lnss3
+ * gcrypt: -lpopt -DCRYPT_GCRYPT -lgcrypt -lgpg-error
+ */
+
+#define _FILE_OFFSET_BITS	64
+
+#ifdef HAVE_CONFIG_H
+#  include "configure.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <arpa/inet.h>
+#include <popt.h>
+
+#ifdef CRYPT_OPENSSL
+#  include <openssl/evp.h>
+#  include <openssl/rand.h>
+#elif defined(CRYPT_GCRYPT)
+#  include <gcrypt.h>
+#elif defined(CRYPT_NSS)
+#  include <nss.h>
+#  include <sechash.h>
+#  include <pk11pub.h>
+#endif
+
+#if !defined(CRYPT_OPENSSL) && !defined(CRYPT_GCRYPT) && !defined(CRYPT_NSS)
+#error No crypto engine specified
+#endif
+
+#define DEFAULT_BLOCK_SIZE	4096
+#define DM_VERITY_MAX_LEVELS	63
+
+#define DEFAULT_SALT_SIZE	32
+#define MAX_SALT_SIZE		384
+
+#define MODE_VERIFY	0
+#define MODE_CREATE	1
+#define MODE_ACTIVATE	2
+
+#define MAX_FORMAT_VERSION	1
+
+static int mode = -1;
+static int use_superblock = 1;
+
+static const char *dm_device;
+static const char *data_device;
+static const char *hash_device;
+static const char *hash_algorithm = NULL;
+static const char *root_hash;
+
+static int version = -1;
+static int data_block_size = 0;
+static int hash_block_size = 0;
+static char *data_blocks_string = NULL;
+static long long data_blocks = 0;
+static char *hash_start_string = NULL;
+static long long hash_start = 0;
+static const char *salt_string = NULL;
+
+static FILE *data_file;
+static FILE *hash_file;
+
+static off_t data_file_blocks;
+static off_t hash_file_blocks;
+static off_t used_hash_blocks;
+
+static unsigned char *root_hash_bytes;
+static unsigned char *calculated_digest;
+
+static unsigned char *salt_bytes;
+static unsigned salt_size;
+
+static unsigned digest_size;
+static unsigned char digest_size_bits;
+static unsigned char levels;
+static unsigned char hash_per_block_bits;
+
+static off_t hash_level_block[DM_VERITY_MAX_LEVELS];
+static off_t hash_level_size[DM_VERITY_MAX_LEVELS];
+
+static off_t superblock_position;
+
+static int retval = 0;
+
+struct superblock {
+	uint8_t signature[8];
+	uint8_t version;
+	uint8_t data_block_bits;
+	uint8_t hash_block_bits;
+	uint8_t pad1[1];
+	uint16_t salt_size;
+	uint8_t pad2[2];
+	uint32_t data_blocks_hi;
+	uint32_t data_blocks_lo;
+	uint8_t algorithm[16];
+	uint8_t salt[MAX_SALT_SIZE];
+	uint8_t pad3[88];
+};
+
+#define DM_VERITY_SIGNATURE	"verity\0\0"
+#define DM_VERITY_VERSION	0
+
+#if defined(__GNUC__) && __GNUC__ >= 2
+	__attribute__((__noreturn__))
+#endif
+static void help(poptContext popt_context,
+		 enum poptCallbackReason reason,
+		 struct poptOption *key,
+		 const char *arg,
+		 void *data)
+{
+	if (!strcmp(key->longName, "help")) {
+		poptPrintHelp(popt_context, stdout, 0);
+	} else {
+		printf("veritysetup");
+#ifdef DM_LIB_VERSION
+		printf(", device mapper version %s", DM_LIB_VERSION);
+#endif
+		printf("\n");
+	}
+	exit(0);
+}
+
+static struct poptOption popt_help_options[] = {
+	{ NULL,			0,	POPT_ARG_CALLBACK, help, 0, NULL, NULL },
+	{ "help",		'h',	POPT_ARG_NONE, NULL, 0, "Show help", NULL },
+	{ "version",		0,	POPT_ARG_NONE, NULL, 0, "Show version", NULL },
+	POPT_TABLEEND
+};
+
+static struct poptOption popt_options[] = {
+	{ NULL,			'\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, NULL, NULL },
+	{ "create",		'c',	POPT_ARG_VAL, &mode, MODE_CREATE, "Create hash", NULL },
+	{ "verify",		'v',	POPT_ARG_VAL, &mode, MODE_VERIFY, "Verify integrity", NULL },
+	{ "activate",		'a',	POPT_ARG_VAL, &mode, MODE_ACTIVATE, "Activate the device", NULL },
+	{ "no-superblock",	0,	POPT_ARG_VAL, &use_superblock, 0, "Do not create/use superblock" },
+	{ "format",		0,	POPT_ARG_INT, &version, 0, "Format version (1 - normal format, 0 - original Chromium OS format)", "number" },
+	{ "data-block-size",	0, 	POPT_ARG_INT, &data_block_size, 0, "Block size on the data device", "bytes" },
+	{ "hash-block-size",	0, 	POPT_ARG_INT, &hash_block_size, 0, "Block size on the hash device", "bytes" },
+	{ "data-blocks",	0,	POPT_ARG_STRING, &data_blocks_string, 0, "The number of blocks in the data file", "blocks" },
+	{ "hash-start",		0,	POPT_ARG_STRING, &hash_start_string, 0, "Starting block on the hash device", "512-byte sectors" },
+	{ "algorithm",		0,	POPT_ARG_STRING, &hash_algorithm, 0, "Hash algorithm (default sha256)", "string" },
+	{ "salt",		0,	POPT_ARG_STRING, &salt_string, 0, "Salt", "hex string" },
+	POPT_TABLEEND
+};
+
+#if defined(__GNUC__) && __GNUC__ >= 2
+	__attribute__((__format__(__printf__, 1, 2), __noreturn__))
+#endif
+static void exit_err(const char *msg, ...)
+{
+	va_list args;
+	va_start(args, msg);
+	vfprintf(stderr, msg, args);
+	va_end(args);
+	fputc('\n', stderr);
+	exit(2);
+}
+
+#if defined(__GNUC__) && __GNUC__ >= 2
+	__attribute__((__noreturn__))
+#endif
+static void stream_err(FILE *f, const char *msg)
+{
+	if (ferror(f)) {
+		perror(msg);
+		exit(2);
+	} else if (feof(f)) {
+		exit_err("eof on %s", msg);
+	} else {
+		exit_err("unknown error on %s", msg);
+	}
+}
+
+static void *xmalloc(size_t s)
+{
+	void *ptr = malloc(!s ? 1 : s);
+	if (!ptr) exit_err("out of memory");
+	return ptr;
+}
+
+static char *xstrdup(const char *str)
+{
+	return strcpy(xmalloc(strlen(str) + 1), str);
+}
+
+static char *xprint(unsigned long long num)
+{
+	size_t s = snprintf(NULL, 0, "%llu", num);
+	char *p = xmalloc(s + 1);
+	snprintf(p, s + 1, "%llu", num);
+	return p;
+}
+
+static char *xhexprint(unsigned char *bytes, size_t len)
+{
+	size_t i;
+	char *p = xmalloc(len * 2 + 1);
+	p[0] = 0;
+	for (i = 0; i < len; i++)
+		snprintf(p + i * 2, 3, "%02x", bytes[i]);
+	return p;
+}
+
+static off_t get_size(FILE *f, const char *name)
+{
+	struct stat st;
+	int h = fileno(f);
+	if (h < 0) {
+		perror("fileno");
+		exit(2);
+	}
+	if (fstat(h, &st)) {
+		perror("fstat");
+		exit(2);
+	}
+	if (S_ISREG(st.st_mode)) {
+		return st.st_size;
+	} else if (S_ISBLK(st.st_mode)) {
+		unsigned long long size64;
+		unsigned long sizeul;
+		if (!ioctl(h, BLKGETSIZE64, &size64)) {
+			return_size64:
+			if ((off_t)size64 < 0 || (off_t)size64 != size64) {
+				size_overflow:
+				exit_err("%s: device size overflow", name);
+			}
+			return size64;
+		}
+		if (!ioctl(h, BLKGETSIZE, &sizeul)) {
+			size64 = (unsigned long long)sizeul * 512;
+			if (size64 / 512 != sizeul) goto size_overflow;
+			goto return_size64;
+		}
+		perror("BLKGETSIZE");
+		exit(2);
+	} else {
+		exit_err("%s is not a file or a block device", name);
+	}
+	return -1;	/* never reached, shut up warning */
+}
+
+static void block_fseek(FILE *f, off_t block, int block_size)
+{
+	unsigned long long pos = (unsigned long long)block * block_size;
+	if (pos / block_size != block ||
+	    (off_t)pos < 0 ||
+	    (off_t)pos != pos)
+		exit_err("seek position overflow");
+	if (fseeko(f, pos, SEEK_SET)) {
+		perror("fseek");
+		exit(2);
+	}
+}
+
+
+#ifdef CRYPT_OPENSSL
+
+static const EVP_MD *evp;
+
+static int hash_init(const char *name)
+{
+	OpenSSL_add_all_digests();
+	evp = EVP_get_digestbyname(name);
+	if (!evp)
+		return 0;
+	return EVP_MD_size(evp);
+}
+
+typedef EVP_MD_CTX hash_context;
+
+static void hash_context_init(hash_context *ctx)
+{
+	EVP_MD_CTX_init(ctx);
+}
+
+static void hash_context_reset(hash_context *ctx)
+{
+	if (EVP_DigestInit_ex(ctx, evp, NULL) != 1)
+		exit_err("EVP_DigestInit_ex failed");
+}
+
+static void hash_context_update(hash_context *ctx, unsigned char *data, size_t len)
+{
+	if (EVP_DigestUpdate(ctx, data, len) != 1)
+		exit_err("EVP_DigestUpdate failed");
+}
+
+static void hash_context_final(hash_context *ctx, unsigned char *digest)
+{
+	if (EVP_DigestFinal_ex(ctx, digest, NULL) != 1)
+		exit_err("EVP_DigestFinal_ex failed");
+}
+
+static void hash_context_destroy(hash_context *ctx)
+{
+	if (EVP_MD_CTX_cleanup(ctx) != 1)
+		exit_err("EVP_MD_CTX_cleanup failed");
+}
+
+static void crypto_rand_bytes(unsigned char *data, size_t len)
+{
+	if (RAND_bytes(data, len) != 1)
+		exit_err("RAND_bytes failed");
+}
+
+#elif defined(CRYPT_GCRYPT)
+
+static int gcrypt_id;
+
+static int hash_init(const char *name)
+{
+	retry:
+	gcrypt_id = gcry_md_map_name(name);
+	if (!gcrypt_id) {
+		if (!strcmp(name, "wp512")) {
+			name = "whirlpool";
+			goto retry;
+		}
+		if (!strcmp(name, "rmd160")) {
+			name = "ripemd160";
+			goto retry;
+		}
+		return 0;
+	}
+	return gcry_md_get_algo_dlen(gcrypt_id);
+}
+
+typedef gcry_md_hd_t hash_context;
+
+static void hash_context_init(hash_context *ctx)
+{
+	if (gcry_md_open(ctx, gcrypt_id, 0))
+		exit_err("gcry_md_open failed");
+}
+
+static void hash_context_reset(hash_context *ctx)
+{
+	gcry_md_reset(*ctx);
+}
+
+static void hash_context_update(hash_context *ctx, unsigned char *data, size_t len)
+{
+	gcry_md_write(*ctx, data, len);
+}
+
+static void hash_context_final(hash_context *ctx, unsigned char *digest)
+{
+	unsigned char *p = gcry_md_read(*ctx, gcrypt_id);
+	memcpy(digest, p, gcry_md_get_algo_dlen(gcrypt_id));
+}
+
+static void hash_context_destroy(hash_context *ctx)
+{
+	gcry_md_close(*ctx);
+}
+
+static void crypto_rand_bytes(unsigned char *data, size_t len)
+{
+	gcry_randomize(data, len, GCRY_STRONG_RANDOM);
+}
+
+#elif defined(CRYPT_NSS)
+
+static HASH_HashType nss_alg;
+
+static int hash_init(const char *name)
+{
+	if (NSS_NoDB_Init(NULL) != SECSuccess)
+		exit_err("NSS_Init failed");
+	if (!strcmp(name, "md2"))
+		nss_alg = HASH_AlgMD2;
+	else if (!strcmp(name, "md5"))
+		nss_alg = HASH_AlgMD5;
+	else if (!strcmp(name, "sha1"))
+		nss_alg = HASH_AlgSHA1;
+	else if (!strcmp(name, "sha256"))
+		nss_alg = HASH_AlgSHA256;
+	else if (!strcmp(name, "sha384"))
+		nss_alg = HASH_AlgSHA384;
+	else if (!strcmp(name, "sha512"))
+		nss_alg = HASH_AlgSHA512;
+	else
+		return 0;
+
+	return HASH_ResultLen(nss_alg);
+}
+
+typedef HASHContext *hash_context;
+
+static void hash_context_init(hash_context *ctx)
+{
+	*ctx = HASH_Create(nss_alg);
+	if (!*ctx)
+		exit_err("HASH_Create failed");
+}
+
+static void hash_context_reset(hash_context *ctx)
+{
+	HASH_Begin(*ctx);
+}
+
+static void hash_context_update(hash_context *ctx, unsigned char *data, size_t len)
+{
+	HASH_Update(*ctx, data, len);
+}
+
+static void hash_context_final(hash_context *ctx, unsigned char *digest)
+{
+	unsigned result_len;
+	HASH_End(*ctx, digest, &result_len, HASH_ResultLen(nss_alg));
+}
+
+static void hash_context_destroy(hash_context *ctx)
+{
+	HASH_Destroy(*ctx);
+}
+
+static void crypto_rand_bytes(unsigned char *data, size_t len)
+{
+	if (PK11_GenerateRandom(data, len) != SECSuccess)
+		exit_err("PK11_GenerateRandom failed");
+}
+
+#endif
+
+
+static off_t verity_position_at_level(off_t block, int level)
+{
+	return block >> (level * hash_per_block_bits);
+}
+
+static void calculate_positions(void)
+{
+	unsigned long long hash_position;
+	int i;
+
+	digest_size_bits = 0;
+	while (1 << digest_size_bits < digest_size)
+		digest_size_bits++;
+	hash_per_block_bits = 0;
+	while (((hash_block_size / digest_size) >> hash_per_block_bits) > 1)
+		hash_per_block_bits++;
+	if (!hash_per_block_bits)
+		exit_err("at least two hashes must fit in a hash file block");
+	levels = 0;
+
+	if (data_file_blocks) {
+		while (hash_per_block_bits * levels < 64 &&
+		       (unsigned long long)(data_file_blocks - 1) >>
+		       (hash_per_block_bits * levels))
+			levels++;
+	}
+
+	if (levels > DM_VERITY_MAX_LEVELS)
+		exit_err("too many tree levels");
+
+	hash_position = hash_start * 512 / hash_block_size;
+	for (i = levels - 1; i >= 0; i--) {
+		off_t s;
+		hash_level_block[i] = hash_position;
+		s = verity_position_at_level(data_file_blocks, i);
+		s = (s >> hash_per_block_bits) +
+		    !!(s & ((1 << hash_per_block_bits) - 1));
+		hash_level_size[i] = s;
+		if (hash_position + s < hash_position ||
+		    (off_t)(hash_position + s) < 0 ||
+		    (off_t)(hash_position + s) != hash_position + s)
+			exit_err("hash device offset overflow");
+		hash_position += s;
+	}
+	used_hash_blocks = hash_position;
+}
+
+static void create_or_verify_zero(FILE *wr, unsigned char *left_block, unsigned left_bytes)
+{
+	if (left_bytes) {
+		if (mode != MODE_CREATE) {
+			unsigned x;
+			if (fread(left_block, left_bytes, 1, wr) != 1)
+				stream_err(wr, "read");
+			for (x = 0; x < left_bytes; x++) if (left_block[x]) {
+				retval = 1;
+				fprintf(stderr, "spare area is not zeroed@position %lld\n", (long long)ftello(wr) - left_bytes);
+			}
+		} else {
+			if (fwrite(left_block, left_bytes, 1, wr) != 1)
+				stream_err(wr, "write");
+		}
+	}
+}
+
+static void create_or_verify_stream(FILE *rd, FILE *wr, int block_size, off_t blocks)
+{
+	unsigned char *left_block = xmalloc(hash_block_size);
+	unsigned char *data_buffer = xmalloc(block_size);
+	unsigned char *read_digest = mode != MODE_CREATE ? xmalloc(digest_size) : NULL;
+	off_t blocks_to_write = (blocks >> hash_per_block_bits) +
+				!!(blocks & ((1 << hash_per_block_bits) - 1));
+	hash_context ctx;
+	hash_context_init(&ctx);
+	memset(left_block, 0, hash_block_size);
+	while (blocks_to_write--) {
+		unsigned x;
+		unsigned left_bytes = hash_block_size;
+		for (x = 0; x < 1 << hash_per_block_bits; x++) {
+			if (!blocks)
+				break;
+			blocks--;
+			if (fread(data_buffer, block_size, 1, rd) != 1)
+				stream_err(rd, "read");
+			hash_context_reset(&ctx);
+			if (version >= 1) {
+				hash_context_update(&ctx, salt_bytes, salt_size);
+			}
+			hash_context_update(&ctx, data_buffer, block_size);
+			if (!version) {
+				hash_context_update(&ctx, salt_bytes, salt_size);
+			}
+			hash_context_final(&ctx, calculated_digest);
+			if (!wr)
+				break;
+			if (mode != MODE_CREATE) {
+				if (fread(read_digest, digest_size, 1, wr) != 1)
+					stream_err(wr, "read");
+				if (memcmp(read_digest, calculated_digest, digest_size)) {
+					retval = 1;
+					fprintf(stderr, "verification failed at position %lld in %s file\n", (long long)ftello(rd) - block_size, rd == data_file ? "data" : "metadata");
+				}
+			} else {
+				if (fwrite(calculated_digest, digest_size, 1, wr) != 1)
+					stream_err(wr, "write");
+			}
+			if (!version) {
+				left_bytes -= digest_size;
+			} else {
+				create_or_verify_zero(wr, left_block, (1 << digest_size_bits) - digest_size);
+				left_bytes -= 1 << digest_size_bits;
+			}
+		}
+		if (wr)
+			create_or_verify_zero(wr, left_block, left_bytes);
+	}
+	if (mode == MODE_CREATE && wr) {
+		if (fflush(wr)) {
+			perror("fflush");
+			exit(1);
+		}
+		if (ferror(wr)) {
+			stream_err(wr, "write");
+		}
+	}
+	hash_context_destroy(&ctx);
+	free(left_block);
+	free(data_buffer);
+	if (mode != MODE_CREATE)
+		free(read_digest);
+}
+
+static char **make_target_line(void)
+{
+	const int line_elements = 14;
+	char **line = xmalloc(line_elements * sizeof(char *));
+	int i = 0;
+	char *algorithm_copy = xstrdup(hash_algorithm);
+		/* transform ripemdXXX to rmdXXX */
+	if (!strncmp(algorithm_copy, "ripemd", 6))
+		memmove(algorithm_copy + 1, algorithm_copy + 4, strlen(algorithm_copy + 4) + 1);
+	if (!strcmp(algorithm_copy, "whirlpool"))
+		strcpy(algorithm_copy, "wp512");
+	line[i++] = xstrdup("0");
+	line[i++] = xprint((unsigned long long)data_file_blocks * data_block_size / 512);
+	line[i++] = xstrdup("verity");
+	line[i++] = xprint(version);
+	line[i++] = xstrdup(data_device);
+	line[i++] = xstrdup(hash_device);
+	line[i++] = xprint(data_block_size);
+	line[i++] = xprint(hash_block_size);
+	line[i++] = xprint(data_file_blocks);
+	line[i++] = xprint(hash_start * 512 / hash_block_size);
+	line[i++] = algorithm_copy;
+	line[i++] = xhexprint(calculated_digest, digest_size);
+	line[i++] = !salt_size ? xstrdup("-") : xhexprint(salt_bytes, salt_size);
+	line[i++] = NULL;
+	if (i > line_elements)
+		exit_err("INTERNAL ERROR: insufficient array size");
+	return line;
+}
+
+static void free_target_line(char **line)
+{
+	int i;
+	for (i = 0; line[i]; i++)
+		free(line[i]);
+	free(line);
+}
+
+static void create_or_verify(void)
+{
+	int i;
+
+	memset(calculated_digest, 0, digest_size);
+	if (mode != MODE_ACTIVATE)
+		for (i = 0; i < levels; i++) {
+			block_fseek(hash_file, hash_level_block[i], hash_block_size);
+			if (!i) {
+				block_fseek(data_file, 0, data_block_size);
+				create_or_verify_stream(data_file, hash_file, data_block_size, data_file_blocks);
+			} else {
+				FILE *hash_file_2 = fopen(hash_device, "r");
+				if (!hash_file_2) {
+					perror(hash_device);
+					exit(2);
+				}
+				block_fseek(hash_file_2, hash_level_block[i - 1], hash_block_size);
+				create_or_verify_stream(hash_file_2, hash_file, hash_block_size, hash_level_size[i - 1]);
+				fclose(hash_file_2);
+			}
+		}
+
+	if (levels) {
+		block_fseek(hash_file, hash_level_block[levels - 1], hash_block_size);
+		create_or_verify_stream(hash_file, NULL, hash_block_size, 1);
+	} else {
+		block_fseek(data_file, 0, data_block_size);
+		create_or_verify_stream(data_file, NULL, data_block_size, data_file_blocks);
+	}
+
+	if (mode != MODE_CREATE) {
+		if (memcmp(calculated_digest, root_hash_bytes, digest_size)) {
+			fprintf(stderr, "verification failed in the root block\n");
+			retval = 1;
+		}
+		if (!retval && mode == MODE_VERIFY)
+			fprintf(stderr, "hash successfully verified\n");
+	} else {
+		char **target_line;
+		char *p;
+		if (fsync(fileno(hash_file))) {
+			perror("fsync");
+			exit(1);
+		}
+		printf("hash device size: %llu\n", (unsigned long long)used_hash_blocks * hash_block_size);
+		printf("data block size %u, hash block size %u, %u tree levels\n", data_block_size, hash_block_size, levels);
+		if (salt_size)
+			p = xhexprint(salt_bytes, salt_size);
+		else
+			p = xstrdup("-");
+		printf("salt: %s\n", p);
+		free(p);
+		p = xhexprint(calculated_digest, digest_size);
+		printf("root hash: %s\n", p);
+		free(p);
+		printf("target line:");
+		target_line = make_target_line();
+		for (i = 0; target_line[i]; i++)
+			printf(" %s", target_line[i]);
+		free_target_line(target_line);
+		printf("\n");
+	}
+}
+
+#if defined(__GNUC__) && __GNUC__ >= 2
+	__attribute__((__noreturn__))
+#endif
+static void activate(void)
+{
+	int i;
+	size_t len = 1;
+	char *table_arg;
+	char **target_line = make_target_line();
+	for (i = 0; target_line[i]; i++) {
+		if (i)
+			len++;
+		len += strlen(target_line[i]);
+	}
+	table_arg = xmalloc(len);
+	table_arg[0] = 0;
+	for (i = 0; target_line[i]; i++) {
+		if (i)
+			strcat(table_arg, " ");
+		strcat(table_arg, target_line[i]);
+	}
+	free_target_line(target_line);
+	execlp("dmsetup", "dmsetup", "-r", "create", dm_device, "--table", table_arg, NULL);
+	perror("dmsetup");
+	exit(2);
+}
+
+static void get_hex(const char *string, unsigned char **result, size_t len, const char *description)
+{
+	size_t rl = strlen(string);
+	unsigned u;
+	if (strspn(string, "0123456789ABCDEFabcdef") != rl)
+		exit_err("invalid %s", description);
+	if (rl != len * 2)
+		exit_err("invalid length of %s", description);
+	*result = xmalloc(len);
+	memset(*result, 0, len);
+	for (u = 0; u < rl; u++) {
+		unsigned char c = (string[u] & 15) + (string[u] > '9' ? 9 : 0);
+		(*result)[u / 2] |= c << (((u & 1) ^ 1) << 2);
+	}
+}
+
+static struct superblock superblock;
+
+static void load_superblock(void)
+{
+	long long sb_data_blocks;
+
+	block_fseek(hash_file, superblock_position, 1);
+	if (fread(&superblock, sizeof(struct superblock), 1, hash_file) != 1)
+		stream_err(hash_file, "read");
+	if (memcmp(superblock.signature, DM_VERITY_SIGNATURE, sizeof(superblock.signature)))
+		exit_err("superblock not found on the hash device");
+	if (superblock.version > MAX_FORMAT_VERSION)
+		exit_err("unknown version");
+	if (superblock.data_block_bits < 9 || superblock.data_block_bits >= 31)
+		exit_err("invalid data_block_bits in the superblock");
+	if (superblock.hash_block_bits < 9 || superblock.hash_block_bits >= 31)
+		exit_err("invalid data_block_bits in the superblock");
+	sb_data_blocks = ((unsigned long long)ntohl(superblock.data_blocks_hi) << 31 << 1) | ntohl(superblock.data_blocks_lo);
+	if (sb_data_blocks < 0 || (off_t)sb_data_blocks < 0 || (off_t)sb_data_blocks != sb_data_blocks)
+		exit_err("invalid data blocks in the superblock");
+	if (!memchr(superblock.algorithm, 0, sizeof(superblock.algorithm)))
+		exit_err("invalid hash algorithm in the superblock");
+	if (ntohs(superblock.salt_size) > MAX_SALT_SIZE)
+		exit_err("invalid salt_size in the superblock");
+
+	if (version == -1) {
+		version = superblock.version;
+	} else {
+		if (version != superblock.version)
+			exit_err("version (%d) does not match superblock value (%d)", version, superblock.version);
+	}
+
+	if (!data_block_size) {
+		data_block_size = 1 << superblock.data_block_bits;
+	} else {
+		if (data_block_size != 1 << superblock.data_block_bits)
+			exit_err("data block size (%d) does not match superblock value (%d)", data_block_size, 1 << superblock.data_block_bits);
+	}
+
+	if (!hash_block_size) {
+		hash_block_size = 1 << superblock.hash_block_bits;
+	} else {
+		if (hash_block_size != 1 << superblock.hash_block_bits)
+			exit_err("hash block size (%d) does not match superblock value (%d)", hash_block_size, 1 << superblock.hash_block_bits);
+	}
+
+	if (!data_blocks_string) {
+		data_blocks = sb_data_blocks;
+		data_blocks_string = (char *)"";
+	} else {
+		if (data_blocks != sb_data_blocks)
+			exit_err("data blocks (%lld) does not match superblock value (%lld)", data_blocks, sb_data_blocks);
+	}
+
+	if (!hash_algorithm) {
+		hash_algorithm = (char *)superblock.algorithm;
+	} else {
+		if (strcmp(hash_algorithm, (char *)superblock.algorithm))
+			exit_err("hash algorithm (%s) does not match superblock value (%s)", hash_algorithm, superblock.algorithm);
+	}
+
+	if (!salt_bytes) {
+		salt_size = ntohs(superblock.salt_size);
+		salt_bytes = xmalloc(salt_size);
+		memcpy(salt_bytes, superblock.salt, salt_size);
+	} else {
+		if (salt_size != ntohs(superblock.salt_size) ||
+		    memcmp(salt_bytes, superblock.salt, salt_size))
+			exit_err("salt does not match superblock value");
+	}
+}
+
+static void save_superblock(void)
+{
+	memset(&superblock, 0, sizeof(struct superblock));
+
+	memcpy(&superblock.signature, DM_VERITY_SIGNATURE, sizeof(superblock.signature));
+	superblock.version = version;
+	superblock.data_block_bits = ffs(data_block_size) - 1;
+	superblock.hash_block_bits = ffs(hash_block_size) - 1;
+	superblock.salt_size = htons(salt_size);
+	superblock.data_blocks_hi = htonl(data_file_blocks >> 31 >> 1);
+	superblock.data_blocks_lo = htonl(data_file_blocks & 0xFFFFFFFF);
+	strncpy((char *)superblock.algorithm, hash_algorithm, sizeof superblock.algorithm);
+	memcpy(superblock.salt, salt_bytes, salt_size);
+
+	block_fseek(hash_file, superblock_position, 1);
+	if (fwrite(&superblock, sizeof(struct superblock), 1, hash_file) != 1)
+		stream_err(hash_file, "write");
+}
+
+int main(int argc, const char **argv)
+{
+	poptContext popt_context;
+	int r;
+	const char *s;
+	char *end;
+
+	if (sizeof(struct superblock) != 512)
+		exit_err("INTERNAL ERROR: bad superblock size %ld", (long)sizeof(struct superblock));
+
+	popt_context = poptGetContext("verity", argc, argv, popt_options, 0);
+
+	poptSetOtherOptionHelp(popt_context, "[-c | -v | -a] [<device name> if activating] <data device> <hash device> [<root hash> if activating or verifying] [OPTION...]");
+
+	if (argc <= 1) {
+		poptPrintHelp(popt_context, stdout, 0);
+		exit(1);
+	}
+
+	r = poptGetNextOpt(popt_context);
+	if (r < -1)
+		exit_err("bad option %s", poptBadOption(popt_context, 0));
+
+	if (mode < 0)
+		exit_err("verify, create or activate mode not specified");
+
+	if (mode == MODE_ACTIVATE) {
+		dm_device = poptGetArg(popt_context);
+		if (!dm_device)
+			exit_err("device name is missing");
+		if (!*dm_device || strchr(dm_device, '/'))
+			exit_err("invalid device name to activate");
+	}
+
+	data_device = poptGetArg(popt_context);
+	if (!data_device)
+		exit_err("data device is missing");
+
+	hash_device = poptGetArg(popt_context);
+	if (!hash_device)
+		exit_err("metadata device is missing");
+
+	if (mode != MODE_CREATE) {
+		root_hash = poptGetArg(popt_context);
+		if (!root_hash)
+			exit_err("root hash not specified");
+	}
+
+	s = poptGetArg(popt_context);
+	if (s)
+		exit_err("extra argument %s", s);
+
+	data_file = fopen(data_device, "r");
+	if (!data_file) {
+		perror(data_device);
+		exit(2);
+	}
+
+	hash_file = fopen(hash_device, mode != MODE_CREATE ? "r" : "r+");
+	if (!hash_file && errno == ENOENT && mode == MODE_CREATE)
+		hash_file = fopen(hash_device, "w+");
+	if (!hash_file) {
+		perror(hash_device);
+		exit(2);
+	}
+
+	if (data_blocks_string) {
+		data_blocks = strtoll(data_blocks_string, &end, 10);
+		if (!*data_blocks_string || *end)
+			exit_err("invalid number of data blocks");
+	}
+
+	if (hash_start_string) {
+		hash_start = strtoll(hash_start_string, &end, 10);
+		if (!*hash_start_string || *end)
+			exit_err("invalid hash start");
+	}
+
+	if (hash_start < 0 ||
+	   (unsigned long long)hash_start * 512 / 512 != hash_start ||
+	   (off_t)(hash_start * 512) < 0 ||
+	   (off_t)(hash_start * 512) != hash_start * 512) exit_err("invalid hash start");
+
+	if (salt_string || !use_superblock) {
+		if (!salt_string || !strcmp(salt_string, "-"))
+			salt_string = "";
+		salt_size = strlen(salt_string) / 2;
+		if (salt_size > MAX_SALT_SIZE)
+			exit_err("too long salt (max %d bytes)", MAX_SALT_SIZE);
+		get_hex(salt_string, &salt_bytes, salt_size, "salt");
+	}
+
+	if (use_superblock) {
+		superblock_position = hash_start * 512;
+		if (mode != MODE_CREATE)
+			load_superblock();
+	}
+
+	if (version == -1)
+		version = MAX_FORMAT_VERSION;
+	if (version < 0 || version > MAX_FORMAT_VERSION)
+		exit_err("invalid format version");
+
+	if (!data_block_size)
+		data_block_size = DEFAULT_BLOCK_SIZE;
+	if (!hash_block_size)
+		hash_block_size = data_block_size;
+
+	if (data_block_size < 512 || (data_block_size & (data_block_size - 1)) || data_block_size >= 1U << 31)
+		exit_err("invalid data block size");
+
+	if (hash_block_size < 512 || (hash_block_size & (hash_block_size - 1)) || hash_block_size >= 1U << 31)
+		exit_err("invalid hash block size");
+
+	if (data_blocks < 0 || (off_t)data_blocks < 0 || (off_t)data_blocks != data_blocks)
+		exit_err("invalid number of data blocks");
+
+	data_file_blocks = get_size(data_file, data_device) / data_block_size;
+	hash_file_blocks = get_size(hash_file, hash_device) / hash_block_size;
+
+	if (data_file_blocks < data_blocks)
+		exit_err("data file is too small");
+	if (data_blocks_string)
+		data_file_blocks = data_blocks;
+
+	if (use_superblock) {
+		hash_start = hash_start + (sizeof(struct superblock) + 511) / 512;
+		hash_start = (hash_start + (hash_block_size / 512 - 1)) & ~(long long)(hash_block_size / 512 - 1);
+	}
+
+	if ((unsigned long long)hash_start * 512 % hash_block_size)
+		exit_err("hash start not aligned on block size");
+
+	if (!hash_algorithm)
+		hash_algorithm = "sha256";
+	if (strlen(hash_algorithm) >= sizeof(superblock.algorithm) && use_superblock)
+		exit_err("hash algorithm name is too long");
+
+	digest_size = hash_init(hash_algorithm);
+	if (!digest_size) exit_err("hash algorithm %s not found", hash_algorithm);
+
+	if (!salt_bytes) {
+		salt_size = DEFAULT_SALT_SIZE;
+		salt_bytes = xmalloc(salt_size);
+		crypto_rand_bytes(salt_bytes, salt_size);
+	}
+
+	calculated_digest = xmalloc(digest_size);
+
+ 	if (mode != MODE_CREATE) {
+		get_hex(root_hash, &root_hash_bytes, digest_size, "root_hash");
+	}
+
+	calculate_positions();
+
+	create_or_verify();
+
+	if (use_superblock) {
+		if (mode == MODE_CREATE)
+			save_superblock();
+	}
+
+	fclose(data_file);
+	fclose(hash_file);
+
+	if (mode == MODE_ACTIVATE && !retval)
+		activate();
+
+	free(salt_bytes);
+	free(calculated_digest);
+	if (mode != MODE_CREATE)
+		free(root_hash_bytes);
+	poptFreeContext(popt_context);
+
+	return retval;
+}



                 reply	other threads:[~2012-03-26 23:09 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120326230940.29002.qmail@sourceware.org \
    --to=agk@sourceware.org \
    --cc=lvm-devel@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.