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>