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