Date: Sun, 25 Oct 2009 22:58:20 GMT From: Gleb Kurtsou <gk@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 169812 for review Message-ID: <200910252258.n9PMwKJp088551@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/chv.cgi?CH=169812 Change 169812 by gk@gk_h1 on 2009/10/25 22:57:25 enable dircache only for supported filesystems grab vnode interlock inside pefs_node_buf_free do not abuse pkcs5, use hkdf where appropriate style Affected files ... .. //depot/projects/soc2009/gk_pefs/sbin/pefs/Makefile#7 edit .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_ctl.c#12 edit .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_ctl.h#10 edit .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_key.c#11 edit .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_keychain.c#7 edit .. //depot/projects/soc2009/gk_pefs/sys/crypto/hmac/hmac_sha512.c#2 edit .. //depot/projects/soc2009/gk_pefs/sys/crypto/hmac/hmac_sha512.h#2 edit .. //depot/projects/soc2009/gk_pefs/sys/crypto/salsa20/salsa20.c#5 edit .. //depot/projects/soc2009/gk_pefs/sys/crypto/salsa20/salsa20.h#4 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#16 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#18 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vfsops.c#15 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#26 edit Differences ... ==== //depot/projects/soc2009/gk_pefs/sbin/pefs/Makefile#7 (text+ko) ==== @@ -1,19 +1,16 @@ # $FreeBSD$ -MOUNT= ${.CURDIR}/../mount SYS= ${.CURDIR}/../../sys -.PATH: ${MOUNT} ${SYS}/geom/eli ${SYS}/crypto/hmac ${SYS}/crypto/sha2 +.PATH: ${SYS}/geom/eli ${SYS}/crypto/hmac ${SYS}/crypto/sha2 PROG= pefs -SRCS= pefs_ctl.c pefs_key.c pefs_keychain.c pefs_mount.c -SRCS+= getmntopts.c +SRCS= pefs_ctl.c pefs_key.c pefs_keychain.c SRCS+= hmac_sha512.c sha2.c SRCS+= pkcs5v2.c -LINKS= ${BINDIR}/pefs ${BINDIR}/mount_pefs NO_MAN= -CFLAGS+=-I${MOUNT} -I${SYS} +CFLAGS+=-I${SYS} WARNS?= 6 DEBUG_FLAGS+= -g ==== //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_ctl.c#12 (text+ko) ==== @@ -51,9 +51,11 @@ #include "pefs_ctl.h" #include "pefs_keychain.h" +#define PATH_MOUNT "/sbin/mount" #define PATH_UMOUNT "/sbin/umount" #define PATH_DEVRANDOM "/dev/random" +static int pefs_mount(int argc, char *argv[]); static int pefs_unmount(int argc, char *argv[]); static int pefs_addkey(int argc, char *argv[]); static int pefs_setkey(int argc, char *argv[]); @@ -459,6 +461,43 @@ } static int +pefs_mount(int argc, char *argv[]) +{ + char **nargv; + int nargc, topt, i, shift; + + topt = 0; + opterr = 0; + while ((i = getopt(argc, argv, "t:")) != -1) + switch(i) { + case 't': + if (strcmp(optarg, PEFS_FSTYPE) != 0) + errx(EX_USAGE, "invalid filesystem type: %s", optarg); + topt = 1; + break; + default: + break; + } + + shift = (topt == 0 ? 2 : 0); + nargc = argc + shift + 2; + nargv = malloc(nargc * sizeof(*nargv)); + nargv[0] = __DECONST(char *, "pefs mount"); + if (topt == 0) { + nargv[1] = __DECONST(char *, "-t"); + nargv[2] = __DECONST(char *, PEFS_FSTYPE); + } + for (i = 0; i < argc; i++) + nargv[i + shift + 1] = argv[i]; + nargv[nargc - 1] = NULL; + + if (execv(PATH_MOUNT, nargv) == -1) + errx(EX_OSERR, "exec %s", PATH_MOUNT); + + return (EX_OSERR); +} + +static int pefs_unmount(int argc, char *argv[]) { char **nargv; @@ -483,13 +522,13 @@ nargv = malloc((argc + 2) * sizeof(*nargv)); for (i = 0; i < argc; i++) nargv[i + 1] = argv[i]; - nargv[0] = __DECONST(char *, PATH_UMOUNT); + nargv[0] = __DECONST(char *, "pefs unmount"); nargv[argc + 1] = NULL; if (execv(PATH_UMOUNT, nargv) == -1) errx(EX_OSERR, "exec %s", PATH_UMOUNT); - return (0); + return (EX_OSERR); } static int @@ -839,7 +878,7 @@ pefs_usage(void) { fprintf(stderr, -"usage: pefs mount [-o options] from filesystem\n" +"usage: pefs mount [-o options] [from filesystem]\n" " pefs unmount [-fv] filesystem\n" " pefs addkey [-cCpv] [-a alg] [-i iterations] [-k keyfile] filesystem\n" " pefs setkey [-cCpvx] [-a alg] [-i iterations] [-k keyfile] directory\n" @@ -876,11 +915,6 @@ if (prog == NULL) prog = argv[0]; - if (strstr(prog, "mount_pefs")) { - pefs_kld_load(); - return (pefs_mount_prog(argc, argv)); - } - if (argc <= 1) pefs_usage(); ==== //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_ctl.h#10 (text+ko) ==== @@ -40,10 +40,12 @@ #define PEFS_KEYENC_MAC_SIZE (PEFS_KEY_SIZE / 2) struct pefs_xkeyenc { - struct pefs_xkey chained; - uint32_t alg; - uint32_t keybits; - u_char mac[PEFS_KEYENC_MAC_SIZE]; + struct { + struct pefs_xkey ke_next; + uint32_t ke_alg; + uint32_t ke_keybits; + } a; + u_char ke_mac[PEFS_KEYENC_MAC_SIZE]; }; struct pefs_keyparam { @@ -63,8 +65,6 @@ } void pefs_usage(void); -int pefs_mount(int argc, char *argv[]); -int pefs_mount_prog(int argc, char *argv[]); int pefs_getfsroot(const char *path, char *fsroot, size_t size); int pefs_key_get(struct pefs_xkey *xk, const char *prompt, int verify, struct pefs_keyparam *kp); ==== //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_key.c#11 (text+ko) ==== @@ -1,5 +1,6 @@ /*- * Copyright (c) 2004-2008 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * Copyright (c) 2009 Gleb Kurtsou <gk@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,8 +51,6 @@ #define PEFS_KEY_PROMPT_DEFAULT "passphrase" -#define PEFS_KEYENC_ITERATIONS 1000 - struct algorithm { const char *name; uint32_t id; @@ -76,6 +75,9 @@ { NULL, 0, 0 }, }; +static char magic_keyid_info[] = "<KEY ID>"; +static char magic_enckey_info[] = "<ENCRYPTED KEY>"; + const char * pefs_alg_name(struct pefs_xkey *xk) { @@ -197,7 +199,7 @@ hmac_sha512_update(&ctx, buf, strlen(buf)); } else { pkcs5v2_genkey(xk->pxk_key, PEFS_KEY_SIZE, buf, 0, buf, - strlen(buf), kp->kp_iterations); + kp->kp_iterations); hmac_sha512_update(&ctx, xk->pxk_key, PEFS_KEY_SIZE); } @@ -206,7 +208,7 @@ hmac_sha512_final(&ctx, xk->pxk_key, PEFS_KEY_SIZE); hmac_sha512_init(&ctx, xk->pxk_key, PEFS_KEY_SIZE); - hmac_sha512_update(&ctx, "<KEY ID>", 8); + hmac_sha512_update(&ctx, magic_keyid_info, sizeof(magic_keyid_info)); hmac_sha512_final(&ctx, xk->pxk_keyid, PEFS_KEYID_SIZE); return (0); @@ -217,24 +219,31 @@ const struct pefs_xkey *xk_parent) { const int keysize = 128 / 8; - const int datasize = sizeof(struct pefs_xkeyenc) - PEFS_KEYENC_MAC_SIZE; + const int datasize = sizeof(xe->a); struct hmac_sha512_ctx hmac_ctx; - u_char *data = (u_char *) xe; + u_char *data = (u_char *) &xe->a; EVP_CIPHER_CTX ctx; - u_char key[keysize]; + u_char key[PEFS_KEY_SIZE]; u_char mac[PEFS_KEYENC_MAC_SIZE]; int outsize; + char idx; - pkcs5v2_genkey(key, keysize, xk_parent->pxk_keyid, PEFS_KEYID_SIZE, - xk_parent->pxk_key, PEFS_KEY_SIZE, PEFS_KEYENC_ITERATIONS); + idx = 1; + bzero(key, PEFS_KEY_SIZE); + hmac_sha512_init(&hmac_ctx, xk_parent->pxk_key, PEFS_KEY_SIZE); + hmac_sha512_update(&hmac_ctx, key, PEFS_KEY_SIZE); + hmac_sha512_update(&hmac_ctx, magic_enckey_info, + sizeof(magic_enckey_info)); + hmac_sha512_update(&hmac_ctx, &idx, sizeof(idx)); + hmac_sha512_final(&hmac_ctx, key, PEFS_KEY_SIZE); - hmac_sha512_init(&hmac_ctx, key, keysize); + hmac_sha512_init(&hmac_ctx, key, PEFS_KEY_SIZE); if (!enc) { hmac_sha512_update(&hmac_ctx, data, datasize); hmac_sha512_final(&hmac_ctx, mac, PEFS_KEYENC_MAC_SIZE); bzero(&hmac_ctx, sizeof(hmac_ctx)); - if (memcmp(mac, xe->mac, PEFS_KEYENC_MAC_SIZE) != 0) - return (-1); + if (memcmp(mac, xe->ke_mac, PEFS_KEYENC_MAC_SIZE) != 0) + return (EINVAL); } EVP_CIPHER_CTX_init(&ctx); @@ -260,7 +269,7 @@ if (enc) { hmac_sha512_update(&hmac_ctx, data, datasize); - hmac_sha512_final(&hmac_ctx, xe->mac, + hmac_sha512_final(&hmac_ctx, xe->ke_mac, PEFS_KEYENC_MAC_SIZE); bzero(&hmac_ctx, sizeof(hmac_ctx)); } ==== //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_keychain.c#7 (text+ko) ==== @@ -121,9 +121,9 @@ error = pefs_key_decrypt(&ke, &kc_parent->kc_key); if (error) break; - kc->kc_key = ke.chained; - kc_parent->kc_key.pxk_alg = le32toh(ke.alg); - kc_parent->kc_key.pxk_keybits = le32toh(ke.keybits); + kc->kc_key = ke.a.ke_next; + kc_parent->kc_key.pxk_alg = le32toh(ke.a.ke_alg); + kc_parent->kc_key.pxk_keybits = le32toh(ke.a.ke_keybits); if (pefs_alg_name(&kc_parent->kc_key) == NULL) errx(EX_DATAERR, "keychain: db damaged"); kc->kc_key.pxk_index = -1; @@ -197,12 +197,12 @@ DB *db; int error; - ke.chained = *xknext; - ke.chained.pxk_index = (uint32_t)random(); - ke.chained.pxk_alg = htole32(ke.chained.pxk_alg); - ke.chained.pxk_keybits = htole32(ke.chained.pxk_keybits); - ke.alg = htole32(xk->pxk_alg); - ke.keybits = htole32(xk->pxk_keybits); + ke.a.ke_next = *xknext; + ke.a.ke_next.pxk_index = (uint32_t)random(); + ke.a.ke_next.pxk_alg = htole32(ke.a.ke_next.pxk_alg); + ke.a.ke_next.pxk_keybits = htole32(ke.a.ke_next.pxk_keybits); + ke.a.ke_alg = htole32(xk->pxk_alg); + ke.a.ke_keybits = htole32(xk->pxk_keybits); if (pefs_key_encrypt(&ke, xk) != 0) return (-1); ==== //depot/projects/soc2009/gk_pefs/sys/crypto/hmac/hmac_sha512.c#2 (text+ko) ==== @@ -107,4 +107,3 @@ hmac_sha512_update(&ctx, data, datasize); hmac_sha512_final(&ctx, md, mdsize); } - ==== //depot/projects/soc2009/gk_pefs/sys/crypto/hmac/hmac_sha512.h#2 (text+ko) ==== @@ -43,4 +43,3 @@ const uint8_t *data, size_t datasize, uint8_t *md, size_t mdsize); #endif /* _SYS_CRYPTO_HMAC_SHA512_H */ - ==== //depot/projects/soc2009/gk_pefs/sys/crypto/salsa20/salsa20.c#5 (text+ko) ==== @@ -251,4 +251,3 @@ } } } - ==== //depot/projects/soc2009/gk_pefs/sys/crypto/salsa20/salsa20.h#4 (text+ko) ==== @@ -22,4 +22,3 @@ void salsa20_crypt(salsa20_ctx *ctx, const uint8_t *plaintext, uint8_t *ciphertext, uint32_t len); #endif - ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#16 (text+ko) ==== @@ -102,6 +102,7 @@ }; #define PM_ROOT_CANRECURSE 0x01 +#define PM_DIRCACHE 0x02 struct pefs_mount { struct mount *pm_lowervfs; ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#18 (text+ko) ==== @@ -524,16 +524,24 @@ void pefs_node_buf_free(struct pefs_node *pn) { + void *bufs[2] = { NULL, NULL }; + int ind = 0; + + ASSERT_VI_UNLOCKED(pn->pn_vnode, "pefs_node_buf_free"); + VI_LOCK(pn->pn_vnode); if (pn->pn_buf_small != NULL && (pn->pn_flags & PN_LOCKBUF_SMALL) == 0) { - free(pn->pn_buf_small, M_PEFSBUF); - pn->pn_buf_small = 0; + bufs[ind++] = pn->pn_buf_small; + pn->pn_buf_small = NULL; } if (pn->pn_buf_large != NULL && (pn->pn_flags & PN_LOCKBUF_LARGE) == 0) { - free(pn->pn_buf_large, M_PEFSBUF); - pn->pn_buf_large = 0; + bufs[ind++] = pn->pn_buf_large; + pn->pn_buf_large = NULL; } + VI_UNLOCK(pn->pn_vnode); + free(bufs[0], M_PEFSBUF); + free(bufs[1], M_PEFSBUF); } struct pefs_key* ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vfsops.c#15 (text+ko) ==== @@ -48,42 +48,97 @@ static MALLOC_DEFINE(M_PEFSMNT, "pefs_mount", "PEFS mount structure"); +static const char *pefs_opts[] = { + "from", "export", "dircache", "nodircache", NULL +}; + +static void +dircache_init(struct mount *mp, int opt, struct pefs_mount *pm) +{ + char *lowerfs; + int supported; + + lowerfs = mp->mnt_vnodecovered->v_mount->mnt_vfc->vfc_name; + supported = (strcmp(lowerfs, "zfs") == 0 || + strcmp(lowerfs, "tmpfs") == 0); + if (opt < 0) + opt = supported; + else if (opt > 0 && supported == 0) { + printf("pefs: dircache is not supported by filesystem: %s\n", + lowerfs); + opt = 0; + } + + if (opt == 0) + pm->pm_flags &= ~PM_DIRCACHE; + else + pm->pm_flags |= PM_DIRCACHE; + PEFSDEBUG("pefs_mount: dircache %s\n", (opt ? "enabled" : "disabed")); +} + +static int +subdir(const char *p, const char *dir) +{ + int l; + + l = strlen(dir); + if (l <= 1) + return (1); + + if ((strncmp(p, dir, l) == 0) && (p[l] == '/' || p[l] == '\0')) + return (1); + + return (0); +} + /* * Mount null layer */ static int pefs_mount(struct mount *mp) { - int error = 0; struct vnode *lowerrootvp, *vp; struct vnode *pm_rootvp; + struct nameidata nd, *ndp = &nd; struct pefs_mount *pm; - char *target; + char *from, *from_free; int isvnunlocked = 0, len; - struct nameidata nd, *ndp = &nd; + int opt_dircache; + int error = 0; PEFSDEBUG("pefs_mount(mp = %p)\n", (void *)mp); if (mp->mnt_flag & MNT_ROOTFS) return (EOPNOTSUPP); - /* - * Update is a no-op - */ + + if (vfs_filteropt(mp->mnt_optnew, pefs_opts)) + return (EINVAL); + + opt_dircache = -1; + if (vfs_flagopt(mp->mnt_optnew, "dircache", NULL, 0)) { + vfs_deleteopt(mp->mnt_optnew, "dircache"); + opt_dircache = 1; + } else if (vfs_flagopt(mp->mnt_optnew, "nodircache", NULL, 0)) { + vfs_deleteopt(mp->mnt_optnew, "nodircache"); + opt_dircache = 0; + } + if (mp->mnt_flag & MNT_UPDATE) { - /* - * Only support update mounts for NFS export. - */ + error = EOPNOTSUPP; if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) - return (0); - else - return (EOPNOTSUPP); + error = 0; + if (opt_dircache >= 0) { + dircache_init(mp, opt_dircache, mp->mnt_data); + error = 0; + } + return (error); } /* * Get argument */ - error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); - if (error || target[len - 1] != '\0') + error = vfs_getopt(mp->mnt_optnew, "from", (void **)&from, &len); + if (error || from[len - 1] != '\0') return (EINVAL); /* @@ -98,8 +153,20 @@ /* * Find lower node */ - NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, curthread); + NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, from, curthread); error = namei(ndp); + + if (error == 0) { + from_free = NULL; + error = vn_fullpath(curthread, ndp->ni_vp, &from, + &from_free); + if (error != 0) + NDFREE(ndp, NDF_ONLY_PNBUF); + else + vfs_mountedfrom(mp, from); + free(from_free, M_TEMP); + + } /* * Re-lock vnode. */ @@ -124,6 +191,18 @@ return (EDEADLK); } + /* + * Check paths are not nested + */ + if ((lowerrootvp != mp->mnt_vnodecovered) && + (subdir(mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname) || + subdir(mp->mnt_stat.f_mntonname, mp->mnt_stat.f_mntfromname))) { + PEFSDEBUG("pefs_mount: %s and %s are nested paths\n", + mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); + vput(lowerrootvp); + return (EDEADLK); + } + pm = (struct pefs_mount *)malloc(sizeof(struct pefs_mount), M_PEFSMNT, M_WAITOK | M_ZERO); @@ -136,6 +215,7 @@ pm->pm_lowervfs = lowerrootvp->v_mount; if (lowerrootvp == mp->mnt_vnodecovered) pm->pm_flags |= PM_ROOT_CANRECURSE; + dircache_init(mp, opt_dircache, pm); /* * Save reference. Each mount also holds @@ -145,7 +225,7 @@ /* * Make sure the node alias worked */ - if (error) { + if (error != 0) { VOP_UNLOCK(vp, 0); vrele(lowerrootvp); free(pm, M_PEFSMNT); @@ -176,8 +256,6 @@ mp->mnt_data = pm; vfs_getnewfsid(mp); - vfs_mountedfrom(mp, target); - PEFSDEBUG("pefs_mount: lower %s, alias at %s\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); return (0); ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#26 (text+ko) ==== @@ -124,6 +124,15 @@ return (r); } +static inline int +pefs_cache_active(struct vnode *vp) +{ + struct pefs_mount *pm = VFS_TO_PEFS(vp->v_mount); + + return (pefs_dircache_enable && + (pm->pm_flags & PM_DIRCACHE) != 0); +} + static struct pefs_dircache_entry * pefs_cache_dirent(struct pefs_dircache *pd, struct dirent *de, struct pefs_ctx *ctx, struct pefs_key *pk) @@ -315,7 +324,7 @@ error = 0; dgen = pefs_getgen(dvp, cnp->cn_cred); pefs_dircache_lock(dpn->pn_dircache); - if (pefs_dircache_enable && + if (pefs_cache_active(dvp) && pefs_dircache_valid(dpn->pn_dircache, dgen)) { cache = pefs_dircache_lookup(dpn->pn_dircache, cnp->cn_nameptr, cnp->cn_namelen); @@ -375,7 +384,7 @@ return (0); } - if (pefs_dircache_enable) { + if (pefs_cache_active(dvp)) { pefs_dircache_lock(dpn->pn_dircache); /* Do not check if cache valid check keys are equal instead */ cache = pefs_dircache_lookup(dpn->pn_dircache, @@ -1172,9 +1181,7 @@ * vnode interlock. * Free remaining buffers in pefs_reclaim. */ - VI_LOCK(vp); pefs_node_buf_free(pn); - VI_UNLOCK(vp); if ((pn->pn_flags & PN_HASKEY) && vp->v_object != NULL) { if (vp->v_object->resident_page_count > 0) @@ -1214,12 +1221,12 @@ * prevent faults in pefs_lock(). */ + pefs_node_buf_free(pn); VI_LOCK(vp); #ifdef INVARIANTS if ((pn->pn_flags & (PN_LOCKBUF_SMALL | PN_LOCKBUF_LARGE)) != 0) printf("pefs_reclaim: node buffer leaked: vp: %p\n", vp); #endif - pefs_node_buf_free(pn); vp->v_data = NULL; vp->v_vnlock = &vp->v_lock; pn->pn_lowervp = NULL;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200910252258.n9PMwKJp088551>