PERFORCE change 169812 for review
Gleb Kurtsou
gk at FreeBSD.org
Sun Oct 25 22:58:21 UTC 2009
http://p4web.freebsd.org/chv.cgi?CH=169812
Change 169812 by gk at 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 at FreeBSD.org>
+ * Copyright (c) 2009 Gleb Kurtsou <gk at 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;
More information about the p4-projects
mailing list