Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Jun 2012 19:02:33 +0000
From:      gpf@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r238413 - soc2012/gpf/pefs_kmod/sbin/pefs
Message-ID:  <20120627190233.BC1871065672@hub.freebsd.org>

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

Log:
  pefs verify
  
  for each slnk/reg file:
  
  - look it up in index tables and compare total number of checksums as
  well as checksum values.
  - generate warning for hardlinks and symlinks just like addchecksum command
  does.
  - make sure that all files in .pefs.checksum are found in pefs filesystem
  
  for the moment, verify works with a mounted pefs fs. will probably expand
  and make it work with an unmouted filesystem.
  

Modified:
  soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c

Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c	Wed Jun 27 18:44:36 2012	(r238412)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c	Wed Jun 27 19:02:33 2012	(r238413)
@@ -107,15 +107,19 @@
 
 /* XXXgpf: [TODO] turns offsets to uint64_t? */
 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;
-	int fd, pfd;
-	struct checksum_head checksums;
+	/* on disk information */
+	uint32_t nhashes;	/* the number of hashes for the file */
+	uint64_t file_id;	/* id is MAC tweak from filename (first 64 bits) */
+	uint32_t offset_to_checksums;	/* in file offset to start of checksums */
+
+	/* in memory information */
+	char path[MAXPATHLEN + 1];	/* fullpath for this file */
+	char dirpath[MAXPATHLEN + 1]; /* fullpath for this file's parent dir */
+	char filename[MAXNAMLEN + 1]; /* filename */
+	char *target_path; /*fullpath to this symlink's immediate next target */
+	int fd, pfd;	/* file descriptors for the file and its parent dir */
+	int found;		/* mark that this entry was found during "verify" action */
+	struct checksum_head checksums;		/* this file's checksums */
 	TAILQ_ENTRY(file_header) file_header_entries;
 	TAILQ_ENTRY(file_header) fh_hardlink_entries;
 };
@@ -889,7 +893,7 @@
 	}
 
 	/* Keep all hardlink file headers in a rb tree */
-	if (sb.st_nlink > 1)
+	if (sb.st_nlink > 1 && hlc_headp != NULL)
 		return (pefs_rb_insert(hlc_headp, fhp, &sb));
 
 	return (0);
@@ -995,7 +999,7 @@
 		pefs_close_file(fhp);
 	}
 
-	/* checking I/O error with pefs_next_file()*/
+	/* checking I/O error from pefs_next_file() */
 	if (error != 0)
 		return (error);
 
@@ -1476,6 +1480,9 @@
 	TAILQ_INSERT_TAIL(&(fhp->checksums), csp, checksum_entries);
 }
 
+/*
+ * XXXgpf: [TODO] comments
+ */
 static int
 pefs_read_checksum_file(int fdin, struct checksum_file_header *cfhp, struct cuckoo_hash_table *chtp)
 {
@@ -1498,6 +1505,7 @@
 		if (fhp != NULL) {
 			TAILQ_INIT(&(fhp->checksums));
 			hashes_offset = fhp->offset_to_checksums;
+			fhp->found = 0;
 
 			for (k = 0; k < fhp->nhashes; k++) {
 				csp = malloc(sizeof(struct checksum));
@@ -1530,6 +1538,7 @@
 		if (fhp != NULL) {
 			TAILQ_INIT(&(fhp->checksums));
 			hashes_offset = fhp->offset_to_checksums;
+			fhp->found = 0;
 
 			for (k = 0; k < fhp->nhashes; k++) {
 				csp = malloc(sizeof(struct checksum));
@@ -1556,49 +1565,159 @@
 }
 
 static int
-pefs_traverse_fs(struct cuckoo_hash_table *cht, const EVP_MD *md, uint8_t hash_len, DIR *dirp, char *path)
+pefs_compare_checksums(struct file_header *fhp, struct file_header *indexfhp, uint8_t hash_len)
+{
+	struct checksum *csp1, *csp2;
+	uint32_t i;
+	int error;
+
+	dprintf(("comparing hashes for file with fid: %llu\t%llu\n", fhp->file_id, indexfhp->file_id));
+
+	if (fhp->nhashes != indexfhp->nhashes) {
+		pefs_warn("number of hashes differ between on disk file and stored values for file %s: %u vs %u",
+			fhp->path, fhp->nhashes, indexfhp->nhashes);
+		return (1);
+	}
+
+	csp1 = TAILQ_FIRST(&fhp->checksums);
+	csp2 = TAILQ_FIRST(&indexfhp->checksums);
+	i = 1;
+	while (csp1 != NULL && csp2 != NULL) {
+		error = memcmp(csp1->hash, csp2->hash, hash_len);
+		if (error != 0) {
+			pefs_warn("checksum no: %u differs between on disk file and stored values for file %s",
+				i, fhp->path);
+			return (1);
+		}
+		csp1 = TAILQ_NEXT(csp1, checksum_entries);
+		csp2 = TAILQ_NEXT(csp2, checksum_entries);
+		i++;
+	}
+
+	return (0);
+}
+
+/*
+ * XXXgpf: [TODO] comments
+ */
+static int
+pefs_traverse_fs(struct cuckoo_hash_table *chtp, const EVP_MD *md, uint8_t hash_len, DIR *dirp,
+	char *path, struct statfs *fsp, struct hardlink_head *hlc_headp, struct file_header_head *fh_headp)
 {
 	char tmpath[MAXPATHLEN];
+	struct stat sb;
 	DIR *dirtmp;
 	struct dirent *sdp;
+	struct file_header *fhp, *indexfhp;
 	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);
-					}
+			if (strcmp(sdp->d_name, "..") == 0 || strcmp(sdp->d_name, ".") == 0 ||
+				strcmp(sdp->d_name, ".pefs.db") == 0 || strcmp(sdp->d_name, ".pefs.conf") == 0 ||
+				strcmp(sdp->d_name, ".pefs.checksum") == 0)
+				continue;
+
+			//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(chtp, md, hash_len, dirtmp, tmpath, fsp, hlc_headp, fh_headp);
+				if (error != 0) {
+					closedir(dirp);
+					return (PEFS_ERR_SYS);
+				}
+				break;
+			/*
+			 * 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.
+			 */
+			/* FALLTHROUGH */
+			case DT_REG:
+			case DT_LNK:
+				fhp = malloc(sizeof(struct file_header));
+				if (fhp == NULL) {
+					warn("memory allocation error");
+					closedir(dirp);
+					return (PEFS_ERR_SYS);
+				}
+				strlcpy(fhp->path, tmpath, sizeof(fhp->path));
+				error = pefs_open_semantic_checks(fhp, fsp, NULL);
+				if (error != 0) {
+					closedir(dirp);
+					free(fhp);
+					return (error);
+				}
+
+				error = pefs_get_file_id(fhp);
+				if (error != 0) {
+					pefs_close_file(fhp);
+					free(fhp);
+					return (error);
+				}
+
+				indexfhp = pefs_cuckoo_lookup(chtp, fhp);
+				if (indexfhp == NULL) {
+					pefs_close_file(fhp);
+					free(fhp);
 					break;
+				}
+				indexfhp->found = 1;
+
+				error = pefs_compute_file_checksums(fhp, md, hash_len);
+				if (error != 0) {
+					pefs_close_file(fhp);
+					free(fhp);
+					return (error);
+				}
+
+				error = lstat(fhp->path, &sb);
+				if (error != 0) {
+					warn("cannot stat file %s", fhp->path);
+					pefs_close_file(fhp);
+					free(fhp);
+					return (PEFS_ERR_SYS);
+				}
+
+				error = pefs_rb_insert(hlc_headp, fhp, &sb);
+				if (error != 0) {
+					pefs_close_file(fhp);
+					free(fhp);
+					return (error);
+				}
+
 				/*
-				 * 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.
+				 * XXXgpf: there's a chance of a false positive here.
+				 * When creating .pefs.checksum we only check if there's a file id
+				 * collision between files that need integrity checking, not against
+				 * the entire filesystem. So there's a possibility we will have a
+				 * false positive in case there are 2 files with the same file id
+				 * now that we traverse the entire fs.
+				 *
+				 * So should exit and treat a checksum comparison as an error?
 				 */
-				case DT_REG:
-					dprintf(("reg file\n"));
-					break;
-				case DT_LNK:
-					dprintf(("smlnk file\n"));
-					break;
-				default:
-					break;
-				}
+				error = pefs_compare_checksums(fhp, indexfhp, hash_len);
+				//if (error != 0) {
+					//pefs_close_file(fhp);
+					//free(fhp);
+					//break;
+				//}
+
+				TAILQ_INSERT_TAIL(fh_headp, fhp, file_header_entries);
+				pefs_close_file(fhp);
+				break;
+			default:
+				break;
 			}
 		}
 		else {
@@ -1611,19 +1730,50 @@
 	return (PEFS_ERR_SYS);
 }
 
+static void
+pefs_found_all_entries(struct cuckoo_hash_table *chtp)
+{
+	struct file_header *fhp;
+	uint32_t i;
+
+	for (i = 0; i < chtp->size; i++) {
+		fhp = chtp->buckets1[i].fhp;
+		if (fhp != NULL)
+			if (fhp->found != 1)
+				pefs_warn("file with file id %llu was not found in filesystem but exists in checksum file",
+					fhp->file_id);
+	}
+
+	for (i = 0; i < chtp->size; i++) {
+		fhp = chtp->buckets2[i].fhp;
+		if (fhp != NULL)
+			if (fhp->found != 1)
+				pefs_warn("file with file id %llu was not found in filesystem but exists in checksum file",
+					fhp->file_id);
+	}
+}
+
 /*
  * XXXgpf: [TODO] comments
  */
 int
 pefs_verify_checksum(int fdin, char *fsroot)
 {
+	struct statfs fs;
 	struct checksum_file_header cfh;
 	struct cuckoo_hash_table cht;
+	struct file_header_head fh_head;
+	struct hardlink_head hlc_head;
 	const EVP_MD *md;
 	DIR *dirp;
 	int error;
 	uint8_t hash_len;
 
+	if (statfs(fsroot, &fs) == -1) {
+		pefs_warn("statfs failed: %s: %s", fsroot, strerror(errno));
+		return (PEFS_ERR_SYS);
+	}
+
 	error = pefs_read_checksum_file_header(fdin, &cfh);
 	if (error != 0)
 		return (error);
@@ -1645,17 +1795,26 @@
 	if (error != 0)
 		return (error);
 
-	pefs_print_hash_tables(&cht, hash_len);
+	//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);
+
+	RB_INIT(&hlc_head);
+	TAILQ_INIT(&fh_head);
+
+	error = pefs_traverse_fs(&cht, md, hash_len, dirp, fsroot, &fs, &hlc_head, &fh_head);
 	if (error != 0)
 		return (error);
 
+	//pefs_rb_print(&hlc_head);
+	pefs_rb_warn(&hlc_head);
+	pefs_symlink_warn(&cht, &fh_head);
+	pefs_found_all_entries(&cht);
+
 	/* XXXgpf: [TODO] free mem in the end and when error occurs */
 	return (0);
 }



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