Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Jun 2012 14:54:34 +0000
From:      gpf@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r238397 - in soc2012/gpf/pefs_kmod: sbin/pefs sys/fs/pefs
Message-ID:  <20120627145434.09F831065679@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gpf
Date: Wed Jun 27 14:54:33 2012
New Revision: 238397
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=238397

Log:
  /sbin/pefs verify:
  
  Verify integrity of .pefs.checksum file.
  
  - read .pefs.checksum's file header into memory
  - create the in memory checksum db from .pefs.checksum file (index hash
  tables & checksums
  - traverse the entire mounted pefs fs and for the moment, just print file
  names
  

Modified:
  soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c
  soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c
  soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h
  soc2012/gpf/pefs_kmod/sys/fs/pefs/pefs_vfsops.c

Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c	Wed Jun 27 12:30:56 2012	(r238396)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c	Wed Jun 27 14:54:33 2012	(r238397)
@@ -64,6 +64,10 @@
 #define dprintf(a)      (void)0
 #endif
 
+#define PEFS_EXTEND 1
+#define PEFS_NOEXTEND 2
+#define PEFS_REALLOC 3
+
 #define PEFS_CHECKSUM_FILE_VERSION 0xDD
 #define PEFS_HASH_BYTE_ALIGNMENT 512
 #define PEFS_EXTRA_TABLE_SIZE 15
@@ -105,11 +109,11 @@
 struct file_header {
 	uint32_t nhashes;
 	uint64_t file_id;
+	uint32_t offset_to_checksums;
 	char path[MAXPATHLEN + 1];
 	char dirpath[MAXPATHLEN + 1];
 	char filename[MAXNAMLEN + 1];
 	char *target_path;
-	uint32_t offset_to_checksums;
 	int fd, pfd;
 	struct checksum_head checksums;
 	TAILQ_ENTRY(file_header) file_header_entries;
@@ -325,11 +329,11 @@
 }
 
 static int
-pefs_allocate_hash_table(struct cuckoo_hash_table *chtp, uint32_t nelements, char reallocate)
+pefs_allocate_hash_table(struct cuckoo_hash_table *chtp, uint32_t nelements, int flags)
 {
 	uint32_t i;
 
-	if (reallocate == 0) {
+	if (flags == PEFS_EXTEND) {
 		/*
 		 * spending 15% more space for each table lowers the chance to fall into an
 		 * infinite loop during cuckoo insertion to about 1.5%.
@@ -341,7 +345,12 @@
 			return (PEFS_ERR_GENERIC);
 		}
 	}
-	else {
+	else if (flags == PEFS_NOEXTEND) {
+		chtp->size = nelements;
+		chtp->nelements = nelements;
+	}
+	/* reallocate the hash tables in case of infinite loop during cuckoo insert */
+	else if (flags == PEFS_REALLOC) {
 		chtp->size = pefs_next_prime(chtp->size + 1);
 			if (chtp->size < chtp->nelements) {
 			pefs_warn("numeric overflow while computing new hash table size");
@@ -517,7 +526,7 @@
 
 /* for debugging purposes */
 static void
-pefs_print_hash_table(struct cuckoo_hash_table *chtp, uint8_t hash_len)
+pefs_print_hash_tables(struct cuckoo_hash_table *chtp, uint8_t hash_len)
 {
 	struct file_header *fhp;
 	struct checksum *csp;
@@ -530,7 +539,8 @@
 		if (fhp != NULL) {
 			//dprintf(("\tpath=%s\tid = %llu\tnhashes = %d\n", fhp->path, fhp->file_id, fhp->nhashes));
 			dprintf(("\tid = %llu\tnhashes = %d\n", fhp->file_id, fhp->nhashes));
-			dprintf(("\tpath = %s\n", fhp->path));
+			if (fhp->path[0] == '/')
+				dprintf(("\tpath = %s\n", fhp->path));
 			TAILQ_FOREACH(csp, &(fhp->checksums), checksum_entries) {
 				dprintf(("\t\tdigest="));
 				for (j = 0; j < hash_len; j++)
@@ -547,7 +557,8 @@
 		if (fhp != NULL) {
 			//dprintf(("\tpath=%s\tid = %llu\tnhashes = %d\n", fhp->path, fhp->file_id, fhp->nhashes));
 			dprintf(("\tid = %llu\tnhashes = %d\n", fhp->file_id, fhp->nhashes));
-			dprintf(("\tpath = %s\n", fhp->path));
+			if (fhp->path[0] == '/')
+				dprintf(("\tpath = %s\n", fhp->path));
 			TAILQ_FOREACH(csp, &(fhp->checksums), checksum_entries) {
 				dprintf(("\t\tdigest="));
 				for (j = 0; j < hash_len; j++)
@@ -991,7 +1002,7 @@
 	pefs_rb_print(&hlc_head);
 	pefs_rb_warn(&hlc_head);
 
-	error = pefs_allocate_hash_table(chtp, nfiles, 0);
+	error = pefs_allocate_hash_table(chtp, nfiles, PEFS_EXTEND);
 	if (error != 0)
 		return (error);
 
@@ -1008,13 +1019,13 @@
 		 */
 		else if (error != 0) {
 			dprintf(("fell into an infinite loop!\n"));
-			error = pefs_allocate_hash_table(chtp, nfiles, 1);
+			error = pefs_allocate_hash_table(chtp, nfiles, PEFS_REALLOC);
 			if (error != 0)
 				return (error);
 			goto cuckoo_insert;
 		}
 	}
-	pefs_print_hash_table(chtp, hash_len);
+	pefs_print_hash_tables(chtp, hash_len);
 	pefs_symlink_warn(chtp, &fh_head);
 
 	return (error);
@@ -1325,4 +1336,328 @@
 	return (error);
 }
 
+static int
+pefs_read_checksum_file_header(int fdin, struct checksum_file_header *cfhp)
+{
+	uint32_t bytes, hash_table_size;
+
+	bytes = read(fdin, &(cfhp->version), sizeof(cfhp->version));
+	if (bytes != sizeof(cfhp->version)) {
+		warn("error reading from .pefs.checksum");
+		return (PEFS_ERR_IO);
+	}
+
+	bytes = read(fdin, &(cfhp->reserved), sizeof(cfhp->reserved));
+	if (bytes != sizeof(cfhp->reserved)) {
+		warn("error reading from .pefs.checksum");
+		return (PEFS_ERR_IO);
+	}
+
+	bytes = read(fdin, &(cfhp->hash_len), sizeof(cfhp->hash_len));
+	if (bytes != sizeof(cfhp->hash_len)) {
+		warn("error reading from .pefs.checksum");
+		return (PEFS_ERR_IO);
+	}
+
+	bytes = read(fdin, cfhp->hash_algo, sizeof(cfhp->hash_algo));
+	if (bytes != sizeof(cfhp->hash_algo)) {
+		warn("error reading from .pefs.checksum");
+		return (PEFS_ERR_IO);
+	}
+
+	bytes = read(fdin, &(cfhp->offset_to_hash_table), sizeof(cfhp->offset_to_hash_table));
+	if (bytes != sizeof(cfhp->offset_to_hash_table)) {
+		warn("error reading from .pefs.checksum");
+		return (PEFS_ERR_IO);
+	}
+
+	bytes = read(fdin, &hash_table_size, sizeof(hash_table_size));
+	if (bytes != sizeof(hash_table_size)) {
+		warn("error reading from .pefs.checksum");
+		return (PEFS_ERR_IO);
+	}
+	cfhp->hash_table_size = le32toh(hash_table_size);
+
+	dprintf(("+++printing checksum file header info+++\n"));
+	dprintf(("version %X\nhash_len %d\nhash_algo %s\n", cfhp->version, cfhp->hash_len, cfhp->hash_algo));
+	dprintf(("offset to hash table %d\nhash table size %d\n", cfhp->offset_to_hash_table, cfhp->hash_table_size));
+
+	return (0);
+}
+
+static int
+pefs_read_file_header(int fdin, struct file_header *fhp, uint32_t *buckets_offset)
+{
+	uint64_t file_id;
+	uint32_t nhashes, offset_to_checksums;
+	int bytes;
+
+	bytes = pread(fdin, &nhashes, sizeof(nhashes), *buckets_offset);
+	if (bytes != sizeof(nhashes)) {
+		warn("error reading from .pefs.checksum");
+		return (PEFS_ERR_IO);
+	}
+	fhp->nhashes = le32toh(nhashes);
+	(*buckets_offset)+= sizeof(nhashes);
+
+	bytes = pread(fdin, &offset_to_checksums, sizeof(offset_to_checksums), *buckets_offset);
+	if (bytes != sizeof(offset_to_checksums)) {
+		warn("error reading from .pefs.checksum");
+		return (PEFS_ERR_IO);
+	}
+	fhp->offset_to_checksums = le32toh(offset_to_checksums);
+	(*buckets_offset)+= sizeof(offset_to_checksums);
+
+	bytes = pread(fdin, &file_id, sizeof(file_id), *buckets_offset);
+	if (bytes != sizeof(file_id)) {
+		warn("error reading from .pefs.checksum");
+		return (PEFS_ERR_IO);
+	}
+	fhp->file_id = le64toh(file_id);
+	(*buckets_offset)+= sizeof(file_id);
+
+	//dprintf(("\nfile header offset = %d\n", *fh_offset));
+	//dprintf(("\n++priting file header info++\n"));
+	//dprintf(("nhashes %d\noffset_to_checksums %u\n", fhp->nhashes, fhp->offset_to_checksums));
+	//dprintf(("file id %llu\n", fhp->file_id));
+
+	return (0);
+}
+
+static int
+pefs_read_bucket(int fdin, struct bucket *bp, uint32_t *buckets_offset)
+{
+	struct file_header *fhp;
+	int error;
+
+	//dprintf(("bucket offset = %d\n", *buckets_offset));
+	fhp = malloc(sizeof(struct file_header));
+	if (fhp == NULL) {
+		pefs_warn("memory allocation error");
+		return (PEFS_ERR_SYS);
+	}
+
+	error = pefs_read_file_header(fdin, fhp, buckets_offset);
+	if (error != 0)
+		return (error);
+
+	if (fhp->nhashes == 0) {
+		free(fhp);
+		fhp = NULL;
+	}
+	bp->fhp = fhp;
+
+	//dprintf(("\n++priting bucket info++\n"));
+
+	return (0);
+}
+
+static int
+pefs_read_hash(int fdin, struct checksum *csp, uint32_t *hashes_offset, uint8_t hash_len)
+{
+	int bytes;
+
+	bytes = pread(fdin, csp->hash, hash_len, *hashes_offset);
+	if (bytes != hash_len) {
+		warn("error reading from .pefs.checksum");
+		return (PEFS_ERR_IO);
+	}
+	(*hashes_offset)+= hash_len;
+
+	//dprintf(("hashes offset = %d\n", *hashes_offset));
+	//dprintf(("hash %s\n", csp->hash));
+
+	return (0);
+}
+
+static void
+pefs_add_to_file_header(struct file_header *fhp, struct checksum *csp)
+{
+	TAILQ_INSERT_TAIL(&(fhp->checksums), csp, checksum_entries);
+}
+
+static int
+pefs_read_checksum_file(int fdin, struct checksum_file_header *cfhp, struct cuckoo_hash_table *chtp)
+{
+	struct bucket *bp;
+	struct checksum *csp;
+	struct file_header *fhp;
+	uint32_t i, k, buckets_offset, hashes_offset;
+	int error;
+
+	/* this points to where the buckets start */
+	buckets_offset = cfhp->offset_to_hash_table;
+
+	for (i = 0; i < chtp->size; i++) {
+		bp = &chtp->buckets1[i];
+		error = pefs_read_bucket(fdin, bp, &buckets_offset);
+		if (error != 0)
+			return (error);
+
+		fhp = bp->fhp;
+		if (fhp != NULL) {
+			TAILQ_INIT(&(fhp->checksums));
+			hashes_offset = fhp->offset_to_checksums;
+
+			for (k = 0; k < fhp->nhashes; k++) {
+				csp = malloc(sizeof(struct checksum));
+				if (csp == NULL) {
+					pefs_warn("memory allocation error");
+					return (PEFS_ERR_SYS);
+				}
+				csp->hash = malloc(cfhp->hash_len);
+				if (csp->hash == NULL) {
+					pefs_warn("memory allocation error");
+					return (PEFS_ERR_SYS);
+				}
+
+				error = pefs_read_hash(fdin, csp, &hashes_offset, cfhp->hash_len);
+				if (error != 0)
+					return (error);
+
+				pefs_add_to_file_header(fhp, csp);
+			}
+		}
+	}
+
+	for (i = 0; i < chtp->size; i++) {
+		bp = &chtp->buckets2[i];
+		error = pefs_read_bucket(fdin, bp, &buckets_offset);
+		if (error != 0)
+			return (error);
+
+		fhp = bp->fhp;
+		if (fhp != NULL) {
+			TAILQ_INIT(&(fhp->checksums));
+			hashes_offset = fhp->offset_to_checksums;
+
+			for (k = 0; k < fhp->nhashes; k++) {
+				csp = malloc(sizeof(struct checksum));
+				if (csp == NULL) {
+					pefs_warn("memory allocation error");
+					return (PEFS_ERR_SYS);
+				}
+				csp->hash = malloc(cfhp->hash_len);
+				if (csp->hash == NULL) {
+					pefs_warn("memory allocation error");
+					return (PEFS_ERR_SYS);
+				}
+
+				error = pefs_read_hash(fdin, csp, &hashes_offset, cfhp->hash_len);
+				if (error != 0)
+					return (error);
+
+				pefs_add_to_file_header(fhp, csp);
+			}
+		}
+	}
+
+	return (0);
+}
+
+static int
+pefs_traverse_fs(struct cuckoo_hash_table *cht, const EVP_MD *md, uint8_t hash_len, DIR *dirp, char *path)
+{
+	char tmpath[MAXPATHLEN];
+	DIR *dirtmp;
+	struct dirent *sdp;
+	int error;
+
+	while (dirp) {
+		sdp = readdir(dirp);
+		if (sdp != NULL) {
+			if (strcmp(sdp->d_name, "..") != 0 && strcmp(sdp->d_name, ".") != 0) {
+				dprintf(("dirent: %s\n", sdp->d_name));
+				snprintf(tmpath, sizeof(tmpath), "%s/%s", path, sdp->d_name);
+				switch (sdp->d_type) {
+				case DT_DIR:
+					dirtmp = opendir(tmpath);
+					if (dirtmp == NULL) {
+						pefs_warn("failed to open dir: %s", tmpath);
+						closedir(dirp);
+						return (PEFS_ERR_SYS);
+					}
+					error = pefs_traverse_fs(cht, md, hash_len, dirtmp, tmpath);
+					if (error != 0) {
+						closedir(dirp);
+						return (PEFS_ERR_SYS);
+					}
+					break;
+				/*
+				 * XXXgpf: Look up the file and verify its checksums.
+				 * Total number of checksums should be the same and checksums should match.
+				 * Also, take notice of hardlinks & symlink warnings.
+				 * After the traversal is done, we must have found all of our entries in the
+				 * checksum file.
+				 */
+				case DT_REG:
+					dprintf(("reg file\n"));
+					break;
+				case DT_LNK:
+					dprintf(("smlnk file\n"));
+					break;
+				default:
+					break;
+				}
+			}
+		}
+		else {
+			closedir(dirp);
+			return (0);
+		}
+	}
+
+	pefs_warn("invalid dirp argument for dir: %s", path);
+	return (PEFS_ERR_SYS);
+}
+
+/*
+ * XXXgpf: [TODO] comments
+ */
+int
+pefs_verify_checksum(int fdin, char *fsroot)
+{
+	struct checksum_file_header cfh;
+	struct cuckoo_hash_table cht;
+	const EVP_MD *md;
+	DIR *dirp;
+	int error;
+	uint8_t hash_len;
+
+	error = pefs_read_checksum_file_header(fdin, &cfh);
+	if (error != 0)
+		return (error);
+
+	OpenSSL_add_all_digests();
+	md = EVP_get_digestbyname(cfh.hash_algo);
+
+	if(md == NULL) {
+		pefs_warn("Unknown message digest %s", cfh.hash_algo);
+		return (PEFS_ERR_INVALID);
+	}
+	hash_len = EVP_MD_size(md);
+
+	error = pefs_allocate_hash_table(&cht, cfh.hash_table_size, PEFS_NOEXTEND);
+	if (error != 0)
+		return (error);
+
+	error = pefs_read_checksum_file(fdin, &cfh, &cht);
+	if (error != 0)
+		return (error);
+
+	pefs_print_hash_tables(&cht, hash_len);
+
+	dirp = opendir(fsroot);
+	if (dirp == NULL) {
+		pefs_warn("failed to open dir %s", fsroot);
+		return (PEFS_ERR_SYS);
+	}
+	error = pefs_traverse_fs(&cht, md, hash_len, dirp, fsroot);
+	if (error != 0)
+		return (error);
+
+	/* XXXgpf: [TODO] free mem in the end and when error occurs */
+	return (0);
+}
+
 RB_GENERATE(hardlink_head, hardlink_counter, hardlink_entries, pefs_rb_cmp);

Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c	Wed Jun 27 12:30:56 2012	(r238396)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c	Wed Jun 27 14:54:33 2012	(r238397)
@@ -76,6 +76,7 @@
 static int	pefs_showchains(int argc, char *argv[]);
 static int	pefs_showalgs(int argc, char *argv[]);
 static int	pefs_addchecksum(int argc, char *argv[]);
+static int	pefs_verify(int argc, char *argv[]);
 
 typedef int (*command_func_t)(int argc, char **argv);
 typedef int (*keyop_func_t)(struct pefs_keychain_head *kch, int fd,
@@ -103,6 +104,7 @@
 	{ "showchains",	pefs_showchains },
 	{ "showalgs",	pefs_showalgs },
 	{ "addchecksum", pefs_addchecksum},
+	{ "verify", pefs_verify},
 	{ NULL, NULL },
 };
 
@@ -1082,7 +1084,6 @@
 			if (fpin != NULL)
 				fclose(fpin);
 			pefs_usage();
-			break;
 		}
 	argc -= optind;
 	argv += optind;
@@ -1098,6 +1099,58 @@
 	return (error);
 }
 
+/*
+ * XXXgpf: Instead of a man page entry:
+ *
+ * pefs verify checksumpath filesystem
+ *
+ * $command ...
+ *
+ * XXX [TODO] comments
+ *
+ */
+static int
+pefs_verify(int argc, char *argv[])
+{
+	char fsroot[MAXPATHLEN];
+	int error, fdin, i;
+
+	while ((i = getopt(argc, argv, "a:i:p:")) != -1)
+		switch(i) {
+		/* XXXgpf: Should I add an option to tell if it's a mounted or unmounted fs ? */
+		default:
+			pefs_usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 2) {
+		if (argc < 2)
+			warnx("too few arguments");
+		else
+			warnx("too many arguments");
+		pefs_usage();
+	}
+
+	fdin = open(argv[0], O_RDONLY);
+	if (fdin == -1) {
+		warn("cannot open %s file: %s", PEFS_FILE_CHECKSUM, argv[0]);
+		return (PEFS_ERR_INVALID);
+	}
+	argc -=1;
+	argv +=1;
+
+	/* XXXgpf: For now, assume that verify works only with a mounted pefs fs */
+	initfsroot(argc, argv, 0, fsroot, sizeof(fsroot));
+
+	error = pefs_verify_checksum(fdin, fsroot);
+	if (error == 0)
+		printf("everything's ok!\n");
+
+	close(fdin);
+	return (error);
+}
+
 static void
 pefs_usage_alg(void)
 {
@@ -1124,6 +1177,7 @@
 "	pefs showchains [-fp] [-i iterations] [-k keyfile] filesystem\n"
 "	pefs showalgs\n"
 "	pefs addchecksum [-a algo] [-i inputfile] [-p checksumpath] filesystem\n"
+"	pefs verify [checksumpath filesystem]\n"
 );
 	exit(PEFS_ERR_USAGE);
 }

Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h	Wed Jun 27 12:30:56 2012	(r238396)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h	Wed Jun 27 14:54:33 2012	(r238397)
@@ -95,6 +95,7 @@
 	    const struct pefs_xkey *xk_parent);
 uintmax_t	pefs_keyid_as_int(char *keyid);
 int pefs_create_checksum_file(FILE *fpin, char *fsroot, char *csm_path, const char *algo);
+int pefs_verify_checksum(int fdin, char *fsroot);
 
 const char *	pefs_alg_name(struct pefs_xkey *xk);
 void	pefs_alg_list(FILE *stream);

Modified: soc2012/gpf/pefs_kmod/sys/fs/pefs/pefs_vfsops.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sys/fs/pefs/pefs_vfsops.c	Wed Jun 27 12:30:56 2012	(r238396)
+++ soc2012/gpf/pefs_kmod/sys/fs/pefs/pefs_vfsops.c	Wed Jun 27 14:54:33 2012	(r238397)
@@ -617,7 +617,6 @@
 pefs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
 {
 	int error;
-
 	error = VFS_VGET(VFS_TO_PEFS(mp)->pm_lowervfs, ino, flags, vpp);
 	if (error != 0)
 		return (error);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120627145434.09F831065679>