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>