socsvn commit: r238397 - in soc2012/gpf/pefs_kmod: sbin/pefs
sys/fs/pefs
gpf at FreeBSD.org
gpf at FreeBSD.org
Wed Jun 27 14:54:36 UTC 2012
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);
More information about the svn-soc-all
mailing list