PERFORCE change 165990 for review

Gleb Kurtsou gk at FreeBSD.org
Mon Jul 13 09:18:13 UTC 2009


http://perforce.freebsd.org/chv.cgi?CH=165990

Change 165990 by gk at gk_h1 on 2009/07/13 09:18:07

	Use salsa20 for encryption
	Remove all cipher block alignment handling bloat
	Implement key generation function (using salsa20)
	Use uma zones for cryptographically sensitive info (to bzero memory before free)
	Add key reference counting and locking
	Support nodes without key
	Add transparent mode. Emulate read-only filesystem if no keys specified

Affected files ...

.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#6 edit
.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_crypto.c#3 edit
.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#6 edit
.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vfsops.c#5 edit
.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#6 edit

Differences ...

==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#6 (text+ko) ====

@@ -37,24 +37,28 @@
  * $FreeBSD$
  */
 
+#include <sys/param.h>
+#include <sys/mutex.h>
+#include <sys/refcount.h>
 #include <sys/queue.h>
 #include <sys/uio.h>
 
 #ifdef _KERNEL
 
-#define PEFS_BLOCK			16
-#define PEFS_TWEAK_SIZE			16
-#define PEFS_KEY_SIZE			64
+#define PEFS_TWEAK_SIZE			8
+#define PEFS_KEY_BITS			256
+#define PEFS_KEY_SIZE			(PEFS_KEY_BITS / 8)
 #define PEFS_NAME_CSUM_SIZE		2
 
 #define PEFS_NAME_NTOP_SIZE(a)		(((a) * 4 + 2)/3)
 #define PEFS_NAME_PTON_SIZE(a)		(((a) * 3)/4)
 
-SLIST_HEAD(pefs_key_head, pefs_key);
+LIST_HEAD(pefs_key_head, pefs_key);
 
 struct pefs_key {
-	SLIST_ENTRY(pefs_key) pk_entry;
 	volatile u_int pk_refcnt;
+	LIST_ENTRY(pefs_key) pk_entry;
+	struct mtx *pk_entry_lock;
 	char pk_name[PEFS_KEY_SIZE];
 	char pk_data[PEFS_KEY_SIZE];
 };
@@ -64,16 +68,20 @@
 	char ptk_tweak[PEFS_TWEAK_SIZE];
 };
 
+#define PN_HASKEY			0x0001
+
 struct pefs_node {
 	LIST_ENTRY(pefs_node) pn_hash;	/* Hash list */
 	struct vnode *pn_lowervp;	/* VREFed once */
 	struct vnode *pn_vnode;		/* Back pointer */
+	int pn_flags;
 	struct pefs_tkey pn_tkey;
 };
 
 struct pefs_mount {
 	struct mount *pm_vfs;
 	struct vnode *pm_rootvp;	/* Reference to root pefs_node */
+	struct mtx pm_keys_lock;
 	struct pefs_key_head pm_keys;
 };
 
@@ -128,21 +136,30 @@
 
 struct vfsconf;
 struct vop_generic_args;
+struct pefs_ctx;
 
 int pefs_init(struct vfsconf *vfsp);
 int pefs_uninit(struct vfsconf *vfsp);
-int pefs_node_get(struct mount *mp, struct vnode *lowervp, struct vnode **vpp, struct pefs_tkey *ptk);
+void pefs_crypto_init(void);
+void pefs_crypto_uninit(void);
+
+int pefs_node_get(struct mount *mp, struct vnode *lvp, struct vnode *ldvp, struct vnode **vpp, struct ucred *cred, struct pefs_tkey *ptk);
 void pefs_node_free(struct pefs_node *xp);
+int pefs_node_lookup_name(struct vnode *lvp, struct vnode *ldvp, struct ucred *cred, char *encname, int *encname_len);
 struct pefs_key* pefs_node_key(struct pefs_node *pn);
-struct pefs_tkey* pefs_node_tkey(struct pefs_node *pn);
+
+struct pefs_ctx *pefs_ctx_get(void);
+void pefs_ctx_free(struct pefs_ctx *ctx);
+
+struct pefs_key* pefs_key_get(char *passwd, int passwd_len);
+struct pefs_key* pefs_key_ref(struct pefs_key *pk);
+void pefs_key_release(struct pefs_key *pk);
 
-void pefs_data_encrypt(struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc);
-void pefs_data_encrypt_buf(struct pefs_tkey *ptk, off_t offset, void *mem, size_t size);
-void pefs_data_decrypt(struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc);
-void pefs_data_decrypt_buf(struct pefs_tkey *ptk, off_t offset, void *mem, size_t size);
+void pefs_data_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc);
+void pefs_data_decrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc);
 
-int pefs_name_encrypt(struct pefs_tkey *ptk, const char *plain, size_t plain_len, char *enc, size_t enc_size);
-int pefs_name_decrypt(struct pefs_key *pk, struct pefs_tkey *ptk, const char *enc, size_t enc_len, char *plain, size_t plain_size);
+int pefs_name_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, const char *plain, size_t plain_len, char *enc, size_t enc_size);
+int pefs_name_decrypt(struct pefs_ctx *ctx, struct pefs_key *pk, struct pefs_tkey *ptk, const char *enc, size_t enc_len, char *plain, size_t plain_size);
 
 int pefs_name_ntop(u_char const *src, size_t srclength, char *target, size_t targsize);
 int pefs_name_pton(char const *src, size_t srclen, u_char *target, size_t targsize);
@@ -150,6 +167,7 @@
 struct pefs_chunk* pefs_chunk_create(size_t size);
 void pefs_chunk_restore(struct pefs_chunk* pc);
 void pefs_chunk_free(struct pefs_chunk* pc);
+void* pefs_chunk_pullup(struct pefs_chunk *pc, size_t size);
 struct uio* pefs_chunk_uio(struct pefs_chunk *pc, off_t uio_offset, enum uio_rw uio_rw);
 struct uio* pefs_chunk_uio_range(struct pefs_chunk *pc, size_t skip, size_t size, off_t uio_offset, enum uio_rw uio_rw);
 void* pefs_chunk_get(struct pefs_chunk *pc, size_t *size, long *_state);
@@ -160,6 +178,25 @@
 
 extern struct vop_vector pefs_vnodeops;
 
+static inline struct pefs_key*
+pefs_rootkey(struct pefs_mount *pm)
+{
+	struct pefs_key *pk;
+
+	mtx_lock(&pm->pm_keys_lock);
+	pk = LIST_FIRST(&pm->pm_keys);
+	mtx_unlock(&pm->pm_keys_lock);
+
+	return (pk);
+}
+
+static inline int
+pefs_no_keys(struct vnode *vp)
+{
+	return (!(VP_TO_PN(vp)->pn_flags & PN_HASKEY) &&
+			pefs_rootkey(VFS_TO_PEFS(vp->v_mount)) == NULL);
+}
+
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_PEFSBUF);
 #endif

==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_crypto.c#3 (text+ko) ====

@@ -29,96 +29,167 @@
 #include <sys/param.h>
 #include <sys/lock.h>
 #include <sys/libkern.h>
+#include <sys/malloc.h>
 #include <sys/mount.h>
+#include <sys/queue.h>
 #include <sys/vnode.h>
 
-#include <crypto/rc4/rc4.h>
+#include <vm/uma.h>
+
+#include <crypto/salsa20/salsa20.h>
 
 #include <fs/pefs/pefs.h>
 
-#if 0
+static const char magic_tweak_name[PEFS_TWEAK_SIZE] = {
+	0x5c, 0x83, 0xcb, 0x96, 0x2f, 0xaf, 0x3b, 0xb5,
+};
+
+#define MAGIC_KEYGEN_ITERATIONS		32
+
+static const uint8_t magic_key_keygen[PEFS_KEY_SIZE] = {
+	0xd2, 0x68, 0x7d, 0x52, 0xb7, 0xc1, 0xe0, 0xc7,
+	0x26, 0xf1, 0x53, 0xaf, 0xa1, 0x46, 0x7a, 0xc9,
+	0x3a, 0x37, 0xc6, 0xf6, 0x7d, 0xd3, 0xbe, 0xed,
+	0xf4, 0x52, 0x24, 0x9e, 0x6c, 0x85, 0xd9, 0x5c,
+};
+
+static const uint8_t magic_tweak_keygen[PEFS_TWEAK_SIZE] = {
+	0xc8, 0x27, 0xa3, 0x7e, 0xcf, 0x86, 0x3d, 0x0d,
+};
+
+struct pefs_ctx {
+	salsa20_ctx pctx_salsa;
+};
+
+static uma_zone_t pefs_ctx_zone;
+static uma_zone_t pefs_key_zone;
+
+void
+pefs_crypto_init(void)
+{
+	pefs_ctx_zone = uma_zcreate("pefs_ctx", sizeof(struct pefs_ctx), 
+			NULL, NULL, NULL, (uma_fini) bzero, 
+			UMA_ALIGN_PTR, 0);
+	pefs_key_zone = uma_zcreate("pefs_key", sizeof(struct pefs_key), 
+			NULL, NULL, NULL, (uma_fini) bzero, 
+			UMA_ALIGN_PTR, 0);
+}
+
+void
+pefs_crypto_uninit(void)
+{
+	uma_zdestroy(pefs_ctx_zone);
+	uma_zdestroy(pefs_key_zone);
+}
+
+struct pefs_ctx *
+pefs_ctx_get(void)
+{
+	return uma_zalloc(pefs_ctx_zone, M_WAITOK);
+}
+
+void
+pefs_ctx_free(struct pefs_ctx *ctx)
+{
+	uma_zfree(pefs_ctx_zone, ctx);
+}
+
 static void
-pefs_xor(void *mem, size_t size)
+pefs_key_generate(struct pefs_ctx *ctx, uint8_t *key)
 {
-	char *b = (char *)mem;
-	char *e = b + size;
+	uint8_t tweak[PEFS_TWEAK_SIZE];
+	int i, j;
+
+	memcpy(tweak, magic_tweak_keygen, PEFS_TWEAK_SIZE);
+
+	salsa20_keysetup(&ctx->pctx_salsa, magic_key_keygen, PEFS_KEY_BITS);
+	salsa20_ivsetup(&ctx->pctx_salsa, tweak, 0);
+	salsa20_crypt(&ctx->pctx_salsa, key, key, PEFS_KEY_SIZE);
 
-	for (; b < e; b++) {
-		*b ^= 0xAA;
+	for (i = 1; i < MAGIC_KEYGEN_ITERATIONS; i++) {
+		for (j = 0; j < PEFS_TWEAK_SIZE; j++)
+			tweak[j]++;
+		salsa20_keysetup(&ctx->pctx_salsa, key, PEFS_KEY_BITS);
+		salsa20_ivsetup(&ctx->pctx_salsa, tweak, i * 64);
+		salsa20_crypt(&ctx->pctx_salsa, key, key, PEFS_KEY_SIZE);
 	}
 }
 
-static void
-pefs_xor_chunk(struct pefs_chunk *pc)
+struct pefs_key *
+pefs_key_get(char *passwd, int passwd_len)
+{
+	struct pefs_ctx *ctx;
+	struct pefs_key *pk;
+	int i;
+
+	pk = uma_zalloc(pefs_key_zone, M_WAITOK | M_ZERO);
+	refcount_init(&pk->pk_refcnt, 1);
+
+	if (passwd_len > PEFS_KEY_SIZE)
+		passwd_len = PEFS_KEY_SIZE;
+	memcpy(pk->pk_name, passwd, passwd_len);
+	for (i = passwd_len; i < PEFS_KEY_SIZE; i++)
+		pk->pk_name[i] = passwd[i % passwd_len];
+
+	ctx = pefs_ctx_get();
+	pefs_key_generate(ctx, pk->pk_name);
+	memcpy(pk->pk_data, pk->pk_name, PEFS_KEY_SIZE);
+	pefs_key_generate(ctx, pk->pk_data);
+	pefs_ctx_free(ctx);
+
+	return (pk);
+}
+
+struct pefs_key *
+pefs_key_ref(struct pefs_key *pk)
 {
-	long arg = 0;
-	char *mem;
-	size_t size;
+	refcount_acquire(&pk->pk_refcnt);
+	return (pk);
+}
 
-	while (1) {
-		mem = pefs_chunk_get(pc, &size, &arg);
-		if (mem == NULL)
-			break;
-		pefs_xor(mem, size);
-	}
+void
+pefs_key_release(struct pefs_key *pk)
+{
+	if (pk == NULL)
+		return;
+	if (refcount_release(&pk->pk_refcnt))
+		uma_zfree(pefs_key_zone, pk);
 }
-#endif
 
 void
-pefs_data_encrypt(struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc)
+pefs_data_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc)
 {
 	long arg = 0;
 	char *mem;
 	size_t size;
+	int free_ctx = 0;
 
 	if (ptk->ptk_key == NULL) {
 		PEFSDEBUG("!!! %s: NULL ptk_key\n", __func__);
 		return;
 	}
-	if (offset % PEFS_BLOCK != 0) {
-		PEFSDEBUG("!!! %s: invalid offset %jd\n", __func__, offset);
-		return;
+	if (ctx == NULL) {
+		ctx = pefs_ctx_get();
+		free_ctx = 1;
 	}
 
-	// FIXME
-	struct rc4_state rc4state;
-	rc4_init(&rc4state, ptk->ptk_key->pk_data, PEFS_KEY_SIZE);
+	salsa20_keysetup(&ctx->pctx_salsa, ptk->ptk_key->pk_data, PEFS_KEY_BITS);
+	salsa20_ivsetup(&ctx->pctx_salsa, ptk->ptk_tweak, offset);
 	while (1) {
 		mem = pefs_chunk_get(pc, &size, &arg);
 		if (mem == NULL)
 			break;
-		rc4_crypt(&rc4state, mem, mem, size);
+		salsa20_crypt(&ctx->pctx_salsa, mem, mem, size);
 	}
-}
 
-void
-pefs_data_encrypt_buf(struct pefs_tkey *ptk, off_t offset, void *mem, size_t size)
-{
-	if (ptk->ptk_key == NULL) {
-		PEFSDEBUG("!!! %s: NULL ptk_key\n", __func__);
-		return;
-	}
-	if (offset % PEFS_BLOCK != 0) {
-		PEFSDEBUG("!!! %s: invalid offset %jd\n", __func__, offset);
-		return;
-	}
-
-	// FIXME
-	struct rc4_state rc4state;
-	rc4_init(&rc4state, ptk->ptk_key->pk_data, PEFS_KEY_SIZE);
-	rc4_crypt(&rc4state, mem, mem, size);
+	if (free_ctx)
+		pefs_ctx_free(ctx);
 }
 
 void
-pefs_data_decrypt(struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc)
+pefs_data_decrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc)
 {
-	pefs_data_encrypt(ptk, offset, pc);
-}
-
-void
-pefs_data_decrypt_buf(struct pefs_tkey *ptk, off_t offset, void *mem, size_t size)
-{
-	pefs_data_encrypt_buf(ptk, offset, mem, size);
+	pefs_data_encrypt(ctx, ptk, offset, pc);
 }
 
 /*
@@ -135,9 +206,15 @@
 		count -= 2;
 	}
 
+	/*  Fold 32-bit sum to 16 bits */
+	while (sum >> 16)
+		sum = (sum & 0xffff) + (sum >> 16);
+
 	/*  Add left-over byte, if any */
-	if (count > 0)
+	if (count > 0) {
 		sum += * (unsigned char *) buf;
+		sum <<= 8;
+	}
 
 	/*  Fold 32-bit sum to 16 bits */
 	while (sum >> 16)
@@ -147,13 +224,15 @@
 }
 
 int
-pefs_name_encrypt(struct pefs_tkey *ptk, const char *plain, size_t plain_len, char *enc, size_t enc_size)
+pefs_name_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, const char *plain, size_t plain_len, char *enc, size_t enc_size)
 {
 	char *buf;
 	size_t size;
 	u_short csum;
+	int free_ctx = 0;
 	int r;
 
+
 	if (ptk == NULL || ptk->ptk_key == NULL) {
 		PEFSDEBUG("!!!! %s: NULL key\n", __func__);
 		return (-1);
@@ -174,10 +253,17 @@
 	csum = pefs_name_checksum(buf, size);
 	memcpy(buf + size - PEFS_NAME_CSUM_SIZE, &csum, PEFS_NAME_CSUM_SIZE);
 
-	// FIXME
-	struct rc4_state rc4state;
-	rc4_init(&rc4state, ptk->ptk_key->pk_name, PEFS_KEY_SIZE);
-	rc4_crypt(&rc4state, buf, buf, size);
+	if (ctx == NULL) {
+		ctx = pefs_ctx_get();
+		free_ctx = 1;
+	}
+
+	salsa20_keysetup(&ctx->pctx_salsa, ptk->ptk_key->pk_name, PEFS_KEY_BITS);
+	salsa20_ivsetup(&ctx->pctx_salsa, magic_tweak_name, 0);
+	salsa20_crypt(&ctx->pctx_salsa, buf, buf, size);
+
+	if (free_ctx)
+		pefs_ctx_free(ctx);
 
 	r = pefs_name_ntop(buf, size, enc, enc_size);
 
@@ -189,9 +275,10 @@
 }
 
 int
-pefs_name_decrypt(struct pefs_key *pk, struct pefs_tkey *ptk, const char *enc, size_t enc_len, char *plain, size_t plain_size)
+pefs_name_decrypt(struct pefs_ctx *ctx, struct pefs_key *pk, struct pefs_tkey *ptk, const char *enc, size_t enc_len, char *plain, size_t plain_size)
 {
 	u_short csum;
+	int free_ctx = 0;
 	int r;
 
 	if (pk == NULL) {
@@ -205,10 +292,17 @@
 		return (-1);
 	}
 
-	// FIXME
-	struct rc4_state rc4state;
-	rc4_init(&rc4state, pk->pk_name, PEFS_KEY_SIZE);
-	rc4_crypt(&rc4state, plain, plain, r);
+	if (ctx == NULL) {
+		ctx = pefs_ctx_get();
+		free_ctx = 1;
+	}
+
+	salsa20_keysetup(&ctx->pctx_salsa, pk->pk_name, PEFS_KEY_BITS);
+	salsa20_ivsetup(&ctx->pctx_salsa, magic_tweak_name, 0);
+	salsa20_crypt(&ctx->pctx_salsa, plain, plain, r);
+
+	if (free_ctx)
+		pefs_ctx_free(ctx);
 
 	csum = pefs_name_checksum(plain, r);
 	if (csum != 0) {
@@ -227,7 +321,8 @@
 	if (r < plain_size)
 		plain[r] = '\0';
 
-	printf("pefs_name_decrypt: %d; %.*s => %.*s\n", r, enc_len, enc, r < 0 ? 0 : r, plain);
+	PEFSDEBUG("pefs_name_decrypt: %d; %.*s => %.*s\n", r, enc_len, enc, r < 0 ? 0 : r, plain);
 
 	return r;
 }
+

==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#6 (text+ko) ====

@@ -41,9 +41,12 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
-#include <sys/mutex.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/dirent.h>
+#include <sys/queue.h>
 #include <sys/proc.h>
 #include <sys/uio.h>
 #include <sys/vnode.h>
@@ -66,32 +69,38 @@
 
 static LIST_HEAD(pefs_node_hashhead, pefs_node) *pefs_node_hashtbl;
 static u_long pefs_node_hash;
-struct mtx pefs_hashmtx;
+static struct mtx pefs_hashmtx;
 
 static MALLOC_DEFINE(M_PEFSHASH, "pefs_hash", "PEFS hash table");
-static MALLOC_DEFINE(M_PEFSNODE, "pefs_node", "PEFS vnode private part");
 MALLOC_DEFINE(M_PEFSBUF, "pefs_buf", "PEFS buffers");
 
+static uma_zone_t pefs_node_zone;
+
 /*
  * Initialise cache headers
  */
 int
 pefs_init(struct vfsconf *vfsp)
 {
+	PEFSDEBUG("pefs_init\n");
 
-	PEFSDEBUG("pefs_init\n");		/* printed during system boot */
+	pefs_node_zone = uma_zcreate("pefs_node", sizeof(struct pefs_node), 
+			NULL, NULL, NULL, (uma_fini) bzero, 
+			UMA_ALIGN_PTR, 0);
+	
 	pefs_node_hashtbl = hashinit(NPENODECACHE, M_PEFSHASH, &pefs_node_hash);
-	mtx_init(&pefs_hashmtx, "pehs", NULL, MTX_DEF);
+	mtx_init(&pefs_hashmtx, "pefs_hash", NULL, MTX_DEF);
+	pefs_crypto_init();
 	return (0);
 }
 
 int
-pefs_uninit(vfsp)
-	struct vfsconf *vfsp;
+pefs_uninit(struct vfsconf *vfsp)
 {
-
+	pefs_crypto_uninit();
 	mtx_destroy(&pefs_hashmtx);
 	free(pefs_node_hashtbl, M_PEFSHASH);
+	uma_zdestroy(pefs_node_zone);
 	return (0);
 }
 
@@ -166,36 +175,119 @@
 }
 
 static void
-pefs_insmntque_dtr(struct vnode *vp, void *xp)
+pefs_insmntque_dtr(struct vnode *vp, void *_pn)
 {
+	struct pefs_node *pn = _pn;
+
+	PEFSDEBUG("pefs_insmntque_dtr: free node %p\n", pn);
 	vp->v_data = NULL;
 	vp->v_vnlock = &vp->v_lock;
-	free(xp, M_PEFSNODE);
+	pefs_key_release(pn->pn_tkey.ptk_key);
+	uma_zfree(pefs_node_zone, pn);
 	vp->v_op = &dead_vnodeops;
 	(void) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
 	vgone(vp);
 	vput(vp);
 }
 
+int
+pefs_node_lookup_name(struct vnode *lvp, struct vnode *ldvp, struct ucred *cred, char *encname, int *encname_len)
+{
+	struct vnode *nldvp;
+	int error, locked, dlocked;
+	int buflen = *encname_len;
+ 
+	PEFSDEBUG("%s: lvp=%p, ldvp=%p, cred=%p\n", __func__, lvp, ldvp, cred);
+	ASSERT_VOP_LOCKED(lvp, "pefs_node_lookup_name");
+	locked = VOP_ISLOCKED(lvp);
+	if (ldvp) {
+		dlocked = VOP_ISLOCKED(ldvp);
+		if (dlocked)
+			VOP_UNLOCK(ldvp, 0);
+	} else {
+		dlocked = 0;
+	}
+ 
+	vref(lvp);
+	VOP_UNLOCK(lvp, 0);
+	nldvp = lvp;
+	error = vn_vptocnp(&nldvp, cred, encname, encname_len);
+	PEFSDEBUG("%s: vn_vptocnp(dvp) result %d; nldvp=%p; ldvp=%p, len=%d\n", __func__, error, nldvp, ldvp, *encname_len);
+	if (!error)
+		vdrop(nldvp);
+	vrele(lvp);
+	vn_lock(lvp, locked | LK_RETRY);
+	if (ldvp && dlocked)
+		vn_lock(ldvp, dlocked | LK_RETRY);
+	if (error)
+		return (ENOENT);
+
+	memcpy(encname, encname + *encname_len, buflen - *encname_len);
+	*encname_len = buflen - *encname_len;
+	if (*encname_len < buflen)
+		encname[*encname_len] = '\0';
+	PEFSDEBUG("%s: len=%d %s\n", __func__, *encname_len, encname);
+
+	return 0;
+}
+
+static int
+pefs_node_lookup_key(struct pefs_mount *pm, struct vnode *lvp, struct vnode *ldvp, struct ucred *cred, struct pefs_tkey *ptk)
+{
+ 	char *namebuf;
+	char *encname;
+	int error, encname_len, name_len;
+ 
+	namebuf = malloc((MAXNAMLEN + 1)*2, M_PEFSBUF, M_WAITOK | M_ZERO);
+	encname = namebuf + MAXNAMLEN + 1;
+	encname_len = MAXNAMLEN + 1;
+ 
+	error = pefs_node_lookup_name(lvp, ldvp, cred, encname, &encname_len);
+	if (!error) {
+		free(namebuf, M_PEFSBUF);
+		return (error);
+	}
+ 
+	PEFSDEBUG("%s: encname_len=%d; encname=%s\n", __func__, encname_len,
+			encname);
+	
+	name_len = pefs_name_decrypt(NULL, pefs_rootkey(pm), ptk, 
+			encname, encname_len, 
+			namebuf, MAXNAMLEN + 1);
+
+	if (name_len < 0) {
+		PEFSDEBUG("%s: not found: %.*s\n", __func__, encname_len, encname);
+		error = 0;
+ 	} else {
+		pefs_key_ref(ptk->ptk_key);
+	}
+	
+ 	free(namebuf, M_PEFSBUF);
+	
+	return (error);
+}
+
 /*
  * Make a new or get existing pefs node.
- * Vp is the alias vnode, lowervp is the lower vnode.
+ * vp is the alias vnode
+ * lvp is the lower vnode
+ * ldvp is the lower directory vnode, used if no key specified
  *
- * The lowervp assumed to be locked and having "spare" reference. This routine
- * vrele lowervp if pefs node was taken from hash. Otherwise it "transfers"
+ * The lvp assumed to be locked and having "spare" reference. This routine
+ * vrele lvp if pefs node was taken from hash. Otherwise it "transfers"
  * the caller's "spare" reference to created pefs vnode.
  */
 int
-pefs_node_get(struct mount *mp, struct vnode *lowervp, struct vnode **vpp, struct pefs_tkey *ptk)
+pefs_node_get(struct mount *mp, struct vnode *lvp, struct vnode *ldvp, struct vnode **vpp, struct ucred *cred, struct pefs_tkey *ptk)
 {
 	struct pefs_node *xp;
 	struct vnode *vp;
 	int error;
 
 	/* Lookup the hash firstly */
-	*vpp = pefs_hashget(mp, lowervp);
+	*vpp = pefs_hashget(mp, lvp);
 	if (*vpp != NULL) {
-		vrele(lowervp);
+		vrele(lvp);
 		return (0);
 	}
 
@@ -203,7 +295,7 @@
 	 * We do not serialize vnode creation, instead we will check for
 	 * duplicates later, when adding new vnode to hash.
 	 *
-	 * Note that duplicate can only appear in hash if the lowervp is
+	 * Note that duplicate can only appear in hash if the lvp is
 	 * locked LK_SHARED.
 	 */
 
@@ -212,26 +304,39 @@
 	 * might cause a bogus v_data pointer to get dereferenced
 	 * elsewhere if MALLOC should block.
 	 */
-	xp = malloc(sizeof(struct pefs_node),
-	    M_PEFSNODE, M_WAITOK | M_ZERO);
+	xp = uma_zalloc(pefs_node_zone, M_WAITOK | M_ZERO);
+
+	if (ptk != NULL && ptk->ptk_key != NULL) {
+		xp->pn_tkey = *ptk;
+		xp->pn_flags = PN_HASKEY;
+		pefs_key_ref(xp->pn_tkey.ptk_key);
+	} else if (mp->mnt_data != NULL && pefs_rootkey(VFS_TO_PEFS(mp)) != NULL) {
+		if (cred == NULL)
+			cred = curthread->td_ucred;
+		error = pefs_node_lookup_key(VFS_TO_PEFS(mp), lvp, ldvp, cred, &xp->pn_tkey);
+		if (error) {
+			uma_zfree(pefs_node_zone, xp);
+			return (error);
+		}
+		if (xp->pn_tkey.ptk_key != NULL)
+			xp->pn_flags = PN_HASKEY;
+	}
 
 	error = getnewvnode("pefs", mp, &pefs_vnodeops, &vp);
 	if (error) {
-		free(xp, M_PEFSNODE);
+		pefs_key_release(xp->pn_tkey.ptk_key);
+		uma_zfree(pefs_node_zone, xp);
 		return (error);
 	}
 
-	if (ptk != NULL)
-		xp->pn_tkey = *ptk;
+	if (xp->pn_tkey.ptk_key == NULL)
+		PEFSDEBUG("%s: creating node without key: %p: %p->%p\n", __func__, xp, vp, lvp);
 
-	if (!ptk)
-		PEFSDEBUG("%s: creating node without key: %p: %p->%p\n", __func__, xp, vp, lowervp);
-
 	xp->pn_vnode = vp;
-	xp->pn_lowervp = lowervp;
-	vp->v_type = lowervp->v_type;
+	xp->pn_lowervp = lvp;
+	vp->v_type = lvp->v_type;
 	vp->v_data = xp;
-	vp->v_vnlock = lowervp->v_vnlock;
+	vp->v_vnlock = lvp->v_vnlock;
 	if (vp->v_vnlock == NULL)
 		panic("pefs_node_get: Passed a NULL vnlock.\n");
 	error = insmntque1(vp, mp, pefs_insmntque_dtr, xp);
@@ -243,7 +348,7 @@
 	 */
 	*vpp = pefs_hashins(mp, xp);
 	if (*vpp != NULL) {
-		vrele(lowervp);
+		vrele(lvp);
 		vp->v_vnlock = &vp->v_lock;
 		xp->pn_lowervp = NULL;
 		vrele(vp);
@@ -260,33 +365,28 @@
 void
 pefs_node_free(struct pefs_node *xp)
 {
-
+	PEFSDEBUG("pefs_node_free: free node %p\n", xp);
 	mtx_lock(&pefs_hashmtx);
 	LIST_REMOVE(xp, pn_hash);
 	mtx_unlock(&pefs_hashmtx);
-	free(xp, M_PEFSNODE);
+	pefs_key_release(xp->pn_tkey.ptk_key);
+	uma_zfree(pefs_node_zone, xp);
 }
 
 struct pefs_key*
 pefs_node_key(struct pefs_node *pn)
 {
-	if (pn->pn_tkey.ptk_key == NULL) {
-		PEFSDEBUG("!!!!! %s: key is not set: pn=%p\n", __func__, pn);
-		// FIXME !!!!!
-		pn->pn_tkey.ptk_key = SLIST_FIRST(&VFS_TO_PEFS(pn->pn_vnode->v_mount)->pm_keys);
-	}
-	return (pn->pn_tkey.ptk_key);
+	struct pefs_key *pk;
 
-}
-
-struct pefs_tkey*
-pefs_node_tkey(struct pefs_node *pn)
-{
-	if (pn->pn_tkey.ptk_key == NULL) {
-		pefs_node_key(pn);
+	if (pn->pn_flags & PN_HASKEY) {
+		MPASS(pn->pn_tkey.ptk_key != NULL);
+		pk = pn->pn_tkey.ptk_key;
+	} else {
+		MPASS(pn->pn_tkey.ptk_key == NULL);
+		pk = pefs_rootkey(VFS_TO_PEFS(pn->pn_vnode->v_mount));
 	}
-	return (&pn->pn_tkey);
-
+	MPASS(pk != NULL);
+	return (pefs_key_ref(pk));
 }
 
 struct pefs_chunk*
@@ -296,7 +396,6 @@
 	int iovcnt;
 
 	iovcnt = (size + PAGE_SIZE - 1) / PAGE_SIZE;
-	PEFSDEBUG("%s: length=%u; iovcnt=%d\n", __func__, size, iovcnt);
 	pc = malloc(sizeof(struct pefs_chunk) + (sizeof(void*) + sizeof(struct iovec) * 2) * iovcnt,
 			M_PEFSBUF, M_WAITOK | M_ZERO);
 
@@ -314,8 +413,8 @@
 		pc->pc_iov[i].iov_base = pc->pc_bases[i];
 		size -= len;
 	}
-	if (size != 0)
-		panic("pefs_chunk initialization error\n");
+
+	MPASS(size == 0);
 
 	return (pc);
 }
@@ -335,6 +434,19 @@
 	}
 }
 
+void*
+pefs_chunk_pullup(struct pefs_chunk *pc, size_t size)
+{
+	if (size > PAGE_SIZE)
+		panic("pefs_chunk_pullup: size > PAGE_SIZE");
+	if (pc->pc_iovcnt == 0)
+		panic("pefs_chunk_pullup: chunk is empty");
+	if (size > pc->pc_size || size > pc->pc_iov[0].iov_len)
+		panic("pefs_chunk_pullup: size is too large: %u, available %u",
+				size, min(pc->pc_size, pc->pc_iov[0].iov_len));
+	return (pc->pc_iov[0].iov_base);
+}
+
 void
 pefs_chunk_free(struct pefs_chunk* pc)
 {
@@ -375,8 +487,6 @@
 		pc->pc_uio.uio_iov[i].iov_len = min(size, pc->pc_iov[skip_iov + i].iov_len - skip);
 		size -= pc->pc_uio.uio_iov[i].iov_len;
 		skip = 0;
-		printf("%s: creating iov: i=%d; len=%d; base=%p\n", __func__, i,
-				pc->pc_uio.uio_iov[i].iov_len, pc->pc_uio.uio_iov[i].iov_base);
 	}
 	pc->pc_uio.uio_iovcnt = i;
 
@@ -389,7 +499,7 @@
 	void *mem;
 
 	if (!size || !state || *state < 0)
-		panic("invalid args");
+		panic("pefs_chunk_get: invalid args");
 	if (*state >= pc->pc_iovcnt) {
 		*size = 0;
 		return (NULL);
@@ -443,9 +553,6 @@
 	if (skip_begin + skip_end == 0)
 		return;
 
-	PEFSDEBUG("%s: skip_begin=%d; skip_end=%d; size=%d\n", __func__,
-			skip_begin, skip_end, pc->pc_size);
-
 	for (int i = 0; i < pc->pc_iovcnt && skip_begin; i++) {
 		struct iovec *iov = &pc->pc_iov[i];
 
@@ -504,9 +611,9 @@
 	 * with a funny vop vector.
 	 */
 	if (vp->v_op != pefs_vnodeop_p) {
-		printf ("pefs_checkvp: on non-null-node\n");
+		printf("pefs_checkvp: on non-null-node\n");
 		while (pefs_checkvp_barrier) /*WAIT*/ ;
-		panic("pefs_checkvp");
+		panic("pefs_checkvp: on non-null-node");
 	};
 #endif
 	if (a->pefs_lowervp == NULLVP) {

==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vfsops.c#5 (text+ko) ====

@@ -67,9 +67,6 @@
 	int isvnunlocked = 0, len;
 	struct nameidata nd, *ndp = &nd;
 
-	// FIXME
-	struct pefs_key *pk;
-
 	PEFSDEBUG("pefs_mount(mp = %p)\n", (void *)mp);
 
 	if (mp->mnt_flag & MNT_ROOTFS)
@@ -132,17 +129,19 @@
 		return (EDEADLK);
 	}
 
-	// FIXME
-	pk = malloc(sizeof(struct pefs_key), M_PEFSBUF, M_WAITOK | M_ZERO);
-	memset(pk->pk_data, 0xaa, PEFS_KEY_SIZE);
-	memset(pk->pk_name, 0xbb, PEFS_KEY_SIZE);
+	xmp = (struct pefs_mount *) malloc(sizeof(struct pefs_mount),
+				M_PEFSMNT, M_WAITOK | M_ZERO);	/* XXX */
 
-	xmp = (struct pefs_mount *) malloc(sizeof(struct pefs_mount),
-				M_PEFSMNT, M_WAITOK);	/* XXX */
+	mtx_init(&xmp->pm_keys_lock, "pefs_mount lock", NULL, MTX_DEF);
+	LIST_INIT(&xmp->pm_keys);
 
-	SLIST_INIT(&xmp->pm_keys);
+#if 0
 	// FIXME
-	SLIST_INSERT_HEAD(&xmp->pm_keys, pk, pk_entry);
+	struct pefs_key *pk;
+	pk = pefs_key_get("a", 1);
+	pk->pk_entry_lock = &xmp->pm_keys_lock;
+	LIST_INSERT_HEAD(&xmp->pm_keys, pk, pk_entry);
+#endif
 
 	/*
 	 * Save reference to underlying FS
@@ -153,7 +152,7 @@
 	 * Save reference.  Each mount also holds
 	 * a reference on the root vnode.
 	 */
-	error = pefs_node_get(mp, lowerrootvp, &vp, NULL);
+	error = pefs_node_get(mp, lowerrootvp, NULL, &vp, NULL, NULL);
 	/*
 	 * Make sure the node alias worked
 	 */
@@ -220,8 +219,16 @@
 	 */
 	pm = VFS_TO_PEFS(mp);
 	mp->mnt_data = 0;
-	//FIXME
-	free(SLIST_FIRST(&pm->pm_keys), M_PEFSMNT);
+	mtx_lock(&pm->pm_keys_lock);
+	while (!LIST_EMPTY(&pm->pm_keys)) {
+		struct pefs_key *pk = LIST_FIRST(&pm->pm_keys);
+
+		LIST_REMOVE(pk, pk_entry);
+		pk->pk_entry_lock = NULL;
+		pefs_key_release(pk);
+	}
+	mtx_unlock(&pm->pm_keys_lock);
+	mtx_destroy(&pm->pm_keys_lock);
 	free(pm, M_PEFSMNT);
 	return 0;
 }
@@ -302,7 +309,7 @@
 	if (error)
 		return (error);
 
-	return (pefs_node_get(mp, *vpp, vpp, NULL));
+	return (pefs_node_get(mp, *vpp, NULL, vpp, NULL, NULL));
 }
 
 static int
@@ -314,7 +321,7 @@
 	if (error)
 		return (error);
 
-	error = pefs_node_get(mp, *vpp, vpp, NULL);
+	error = pefs_node_get(mp, *vpp, NULL, vpp, NULL, NULL);
 	printf("pefs_fhtovp: error=%d; vp=%p; v_object=%p\n", error,
 			!error ? *vpp : NULL, !error ? (*vpp)->v_object : NULL);
 	if (error)
@@ -346,4 +353,4 @@
 };
 
 VFS_SET(pefs_vfsops, pefs, VFCF_LOOPBACK);
-MODULE_DEPEND(pefs, rc4, 1, 1, 1);
+MODULE_DEPEND(pefs, salsa20, 1, 1, 1);

==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#6 (text+ko) ====

@@ -65,16 +65,6 @@
 SYSCTL_INT(_debug, OID_AUTO, pefs_bug_bypass, CTLFLAG_RW,
 	&pefs_bug_bypass, 0, "");
 
-const static struct {
-	size_t namelen;
-	const char *name;
-} _pefs_name_skip_list[] = {
-	{ 4, ".zfs" },
-	{ 5, ".snap" },
-	{ 10, "lost+found" },
-	{ 0, NULL },
-};
-
 struct pefs_enccn {
 	struct componentname pec_cn;
 	void *pec_buf;
@@ -86,12 +76,6 @@
 {
 	if (name[0] == '.' && (namelen == 1 || (namelen == 2 && name[1] == '.')))
 		return (1);
-	for (int i = 0; _pefs_name_skip_list[i].namelen &&
-			_pefs_name_skip_list[i].namelen <= namelen; i++) {
-		if (namelen == _pefs_name_skip_list[i].namelen &&
-				memcmp(_pefs_name_skip_list[i].name, name, namelen) == 0)
-			return (1);
-	}
 	return (0);
 }
 
@@ -135,7 +119,7 @@
 	pec->pec_tkey.ptk_key = pk;
 	PEFSDEBUG("%s: pk=%p\n", __func__, pk);
 	pec->pec_buf = uma_zalloc(namei_zone, M_WAITOK);
-	r = pefs_name_encrypt(&pec->pec_tkey,
+	r = pefs_name_encrypt(NULL, &pec->pec_tkey,
 			cnp->cn_nameptr, cnp->cn_namelen, pec->pec_buf, MAXPATHLEN);
 	if (r <= 0) {
 		uma_zfree(namei_zone, pec->pec_buf);
@@ -165,26 +149,30 @@
 static struct dirent*
 pefs_enccn_lookup_dirent(struct pefs_key *pk, struct pefs_tkey *ptk, void *mem, size_t sz, char *name, int namelen, char *buf, size_t buf_sz)
 {
+	struct pefs_ctx *ctx;
 	struct dirent *de;
 	int d_namelen;

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list