From owner-svn-soc-all@FreeBSD.ORG Wed Jun 6 12:38:36 2012 Return-Path: Delivered-To: svn-soc-all@FreeBSD.org Received: from socsvn.FreeBSD.org (unknown [IPv6:2001:4f8:fff6::2f]) by hub.freebsd.org (Postfix) with SMTP id 91C63106564A for ; Wed, 6 Jun 2012 12:38:34 +0000 (UTC) (envelope-from gpf@FreeBSD.org) Received: by socsvn.FreeBSD.org (sSMTP sendmail emulation); Wed, 06 Jun 2012 12:38:34 +0000 Date: Wed, 06 Jun 2012 12:38:34 +0000 From: gpf@FreeBSD.org To: svn-soc-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message-Id: <20120606123834.91C63106564A@hub.freebsd.org> Cc: Subject: socsvn commit: r237206 - soc2012/gpf/pefs_kmod/sbin/pefs X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 06 Jun 2012 12:38:36 -0000 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); }