socsvn commit: r237206 - soc2012/gpf/pefs_kmod/sbin/pefs

gpf at FreeBSD.org gpf at FreeBSD.org
Wed Jun 6 12:38:36 UTC 2012


Author: gpf
Date: Wed Jun  6 12:38:33 2012
New Revision: 237206
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=237206

Log:
  -change symlink semantic checks once again:
  We do not require that target file resides in pefs filesystem or that it's
  a regular file. Also, I don't see a way to check that symlink file itself
  resides in pefs filesystem, although if it does not, ioctl() calls will
  fail.
  
  - If however target file resides in pefs filesystem AND target file is a
  regular file or symlink AND target file is not given in user supplied
  inputlist, then print warning that it wasn't found. User will have to
  supply 2 entries if he wishes integrity checking for both target file
  and symlink file.
  

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  6 12:08:03 2012	(r237205)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c	Wed Jun  6 12:38:33 2012	(r237206)
@@ -55,7 +55,7 @@
 
 #include "pefs_ctl.h"
 
-//#define PEFS_INTEGRITY_DEBUG
+#define PEFS_INTEGRITY_DEBUG
 #if defined (PEFS_INTEGRITY_DEBUG)
 #define dprintf(a)		printf a
 #else
@@ -180,6 +180,10 @@
 
 	TAILQ_INIT(&(fhp->checksums));
 
+	/*
+	 * XXXgpf: [TODO] deal with symlinks
+	 */
+
 	/* XXXgpf: what happens if file size > 2^64? */
 	if (stat(fhp->path, &sb) != 0) {
 		warn("cannot stat file %s", fhp->path);
@@ -365,6 +369,8 @@
 						free(csp->hash);
 					free(csp);
 				}
+				if (fhp->target_path != NULL)
+					free(fhp->target_path);
 				free(fhp);
 			}
 		}
@@ -382,6 +388,8 @@
 						free(csp->hash);
 					free(csp);
 				}
+				if (fhp->target_path != NULL)
+					free(fhp->target_path);
 				free(fhp);
 			}
 		}
@@ -410,6 +418,32 @@
 	return (nbucket);
 }
 
+static struct file_header *
+pefs_cuckoo_lookup(struct cuckoo_hash_table *chtp, struct file_header *fhp)
+{
+	struct file_header *elem, *elem1, *elem2;
+	int pos1, pos2;
+
+	elem = fhp;
+	pos1 = pefs_hash1(chtp, elem);
+	elem1 = chtp->buckets1[pos1].fhp;
+	if (elem1 != NULL) {
+		if (elem1->file_id == elem->file_id) {
+			return (elem1);
+		}
+	}
+
+	pos2 = pefs_hash2(chtp, elem);
+	elem2 = chtp->buckets2[pos2].fhp;
+	if (elem2 != NULL) {
+		if (elem2->file_id == elem->file_id) {
+			return (elem2);
+		}
+	}
+
+	return (NULL);
+}
+
 static int
 pefs_cuckoo_insert(struct cuckoo_hash_table *chtp,
 	struct file_header *fhp)
@@ -502,6 +536,7 @@
 		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));
 			TAILQ_FOREACH(csp, &(fhp->checksums), checksum_entries) {
 				dprintf(("\t\tdigest="));
 				for (j = 0; j < hash_len; j++)
@@ -563,6 +598,53 @@
 	return (error);
 }
 
+// XXXgpf: void?
+static void
+pefs_symlink_warn(struct cuckoo_hash_table *chtp, struct file_header_head *fhhp,
+			struct statfs *fsp)
+{
+	struct statfs this_fs;
+	struct stat sb;
+	struct file_header targetfh;
+	struct file_header *fhp, *res;
+	int error;
+
+	TAILQ_FOREACH(fhp, fhhp, file_header_entries) {
+		/*
+		 * If fhp == symlink and target file resides in pefs filesystem and
+		 * target file == regular file || symlink, then grab target's filename MAC and
+		 * look it up in our hash table. Print a warning message if it is not found.
+		 */
+		if (fhp->target_path != NULL) {
+			if (statfs(fhp->target_path, &this_fs) == -1) {
+				pefs_warn("statfs failed: %s: %s", fhp->target_path, strerror(errno));
+				continue;
+			}
+
+			if ((fsp->f_fsid.val[0] != this_fs.f_fsid.val[0]) ||
+				(fsp->f_fsid.val[1] != this_fs.f_fsid.val[1]))
+				continue;
+
+			if (lstat(fhp->target_path, &sb) != 0) {
+				warn("cannot stat file %s", fhp->target_path);
+				continue;
+			}
+
+			if (S_ISLNK(sb.st_mode) == 0 && S_ISREG(sb.st_mode) == 0)
+				continue;
+
+			strlcpy(targetfh.path, fhp->target_path, sizeof(targetfh.path));
+			error = pefs_get_file_id(&targetfh);
+			if (error == 0) {
+				res = pefs_cuckoo_lookup(chtp, &targetfh);
+				if (res == NULL)
+					pefs_warn("target file %s of symlink %s was not found in inputlist",
+						targetfh.path, fhp->path);
+			}
+		}
+	}
+}
+
 /* XXXgpf: for debugging purposes */
 static void
 pefs_rb_print(struct hardlink_head *hlc_headp)
@@ -599,7 +681,6 @@
 	}
 }
 
-/* XXXgpf: [TODO] comments */
 static int
 pefs_rb_insert(struct hardlink_head *hlc_headp, struct file_header *fhp, struct stat *sbp)
 {
@@ -650,6 +731,7 @@
 	struct stat sb;
 	struct statfs this_fs;
 	char *pch;
+	size_t target_path_size;
 	int nchars;
 
 	if (lstat(fhp->path, &sb) != 0) {
@@ -657,10 +739,9 @@
 		return (PEFS_ERR_SYS);
 	}
 
-	/*
-	 * XXXgpf: [TODO] deal with other types of files
-	 */
 	if (S_ISLNK(sb.st_mode) != 0) {
+		fhp->target_path = NULL;
+
 		nchars = readlink(fhp->path, sbuf, sizeof(sbuf));
 		if (nchars == -1) {
 			warn("readlink failed: %s", fhp->path);
@@ -668,21 +749,22 @@
 		}
 
 		/*
-		 * XXXgpf: target_path can be used to tell if user has supplied target_file
+		 * Target_path can be used to tell if user has supplied target_file
 		 * in input file-list, since symlinks are not traversed. User will have to
 		 * provide fullpaths for both symlink & target file if he wants integrity
-		 * checking for both.
-		 * [TODO] make sure they are properly free()d and print warning errors
-		 * in case user does not supply separate entry for target_file.
+		 * checking for both. However, we will print warning messages in case
+		 * target file does reside in pefs filesystem but is not provided in
+		 * user supplied input list.
 		 */
-		fhp->target_path = malloc(MAXPATHLEN);
+		target_path_size = MAXPATHLEN;
+		fhp->target_path = malloc(target_path_size);
 		if (fhp->target_path == NULL) {
 			warn("memory allocation error");
 			return (PEFS_ERR_SYS);
 		}
 
 		sbuf[nchars] = '\0';
-		/* turn relative paths to absolute paths */
+		/* turn relative paths to absolute paths which are needed for ioctl() */
 		if (sbuf[0] != '/') {
 			strlcpy(parent_dir, fhp->path, sizeof(parent_dir));
 			pch = strrchr(parent_dir, '/');
@@ -691,39 +773,36 @@
 				return (PEFS_ERR_NOENT);
 			}
 			*pch = '\0';
-			snprintf(fhp->target_path, MAXPATHLEN, "%s/%s", parent_dir, sbuf);
+			snprintf(fhp->target_path, target_path_size, "%s/%s", parent_dir, sbuf);
 		}
 		else
-			strlcpy(fhp->target_path, sbuf, sizeof(fhp->target_path));
+			strlcpy(fhp->target_path, sbuf, target_path_size);
 
-		/* target file should be in pefs filesystem */
-		if (statfs(fhp->target_path, &this_fs) == -1) {
-			pefs_warn("statfs failed: %s: %s", fhp->target_path, strerror(errno));
-			return (PEFS_ERR_SYS);
-		}
-
-		if ((fsp->f_fsid.val[0] != this_fs.f_fsid.val[0]) ||
-			(fsp->f_fsid.val[1] != this_fs.f_fsid.val[1])) {
-			pefs_warn("symlink target filename: %s does not reside in filesystem %s",
-				fhp->target_path, fsp->f_mntonname);
-			return (PEFS_ERR_INVALID);
-		}
-
-		/* symlink file should be in pefs filesystem */
-		if (statfs(fhp->path, &this_fs) == -1) {
-			pefs_warn("statfs failed: %s: %s", fhp->path, strerror(errno));
+		/*
+		 * The only semantic check that is performed on target file is an attempt
+		 * to stat() the file, in order to make sure the file exists. This is
+		 * intentional since target file is allowed to reside on a different
+		 * filesystem or in the same filesystem, but not be a regular file or a
+		 * symlink.
+		 * e.g. a directory
+		 */
+		if (lstat(fhp->target_path, &sb) != 0) {
+			warn("cannot stat symlink's target file %s", fhp->target_path);
 			return (PEFS_ERR_SYS);
 		}
 
-		if ((fsp->f_fsid.val[0] != this_fs.f_fsid.val[0]) ||
-			(fsp->f_fsid.val[1] != this_fs.f_fsid.val[1])) {
-			pefs_warn("filename: %s does not reside in filesystem %s",
-				fhp->path, fsp->f_mntonname);
-			return (PEFS_ERR_INVALID);
-		}
-
+		/*
+		 * XXXgpf:
+		 * Is there a way to check that symlink file itself exists in pefs filesystem?
+		 * fstatfs() for example requires a fd and we can't open() the symlink without
+		 * either failing, or having to traverse it.
+		 * On the other hand, if the symlink does not reside in pefs fs, then the calls to
+		 * ioctl() later on will fail.
+		 */
 		return (0);
 	}
+	else
+		fhp->target_path = NULL;
 
 	if (S_ISREG(sb.st_mode) == 0) {
 		pefs_warn("filename: %s is not a regular file", fhp->path);
@@ -786,9 +865,9 @@
  * the checksum file.
  * A) The total sum of entries is gathered so that the hash tables are allocated.
  * B) For each file entry:
- * 		B1) semantic checks: 
- * 			B1a) file should reside in pefs filesystem & file should be regular file. 
- * 			B1b) if symlink, acquire and save the absolute path of the symlink's 
+ * 		B1) semantic checks:
+ * 			B1a) file should reside in pefs filesystem & file should be regular file.
+ * 			B1b) if symlink, acquire and save the absolute path of the symlink's
  * 				target. Try to stat() the target but don't do anything else.
  * 			B1c) If hardlink, save a reference to this file entry in our rb tree.
  * 			rb-tree uses inodes as keys and is used in part C to print warnings.
@@ -802,8 +881,8 @@
  * into an infinite loop during insertion, we re-allocate larger hash tables
  * and try again until we succeed. The possibility to fail twice in a row is
  * 1.5% * 1.5% = 0.0225%
- *
- * XXXgpf: [TODO] more comments
+ * E) For each symlink found in input list, print warnings if its target file
+ * was not found in input list as well since symlinks are not traversed.
  */
 static int
 pefs_create_in_memory_db(FILE *fpin, const EVP_MD *md, uint8_t hash_len,
@@ -853,9 +932,6 @@
 
 	pefs_rb_print(&hlc_head);
 	pefs_rb_warn(&hlc_head);
-	/*
-	 * XXXgpf: [TODO] print warnings for dem hardlinks
-	 */
 
 cuckoo_insert:
 	TAILQ_FOREACH(fhp, &fh_head, file_header_entries) {
@@ -874,6 +950,7 @@
 		}
 	}
 	pefs_print_hash_table(chtp, hash_len);
+	pefs_symlink_warn(chtp, &fh_head, &fs);
 
 	return (error);
 }


More information about the svn-soc-all mailing list