From owner-p4-projects@FreeBSD.ORG Sat Jun 13 16:49:49 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 2E8F2106566C; Sat, 13 Jun 2009 16:49:49 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C8B1D1065675 for ; Sat, 13 Jun 2009 16:49:48 +0000 (UTC) (envelope-from gk@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id B531F8FC12 for ; Sat, 13 Jun 2009 16:49:48 +0000 (UTC) (envelope-from gk@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n5DGnmRn024425 for ; Sat, 13 Jun 2009 16:49:48 GMT (envelope-from gk@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n5DGnm33024423 for perforce@freebsd.org; Sat, 13 Jun 2009 16:49:48 GMT (envelope-from gk@FreeBSD.org) Date: Sat, 13 Jun 2009 16:49:48 GMT Message-Id: <200906131649.n5DGnm33024423@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to gk@FreeBSD.org using -f From: Gleb Kurtsou To: Perforce Change Reviews Cc: Subject: PERFORCE change 164284 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 13 Jun 2009 16:49:50 -0000 http://perforce.freebsd.org/chv.cgi?CH=164284 Change 164284 by gk@gk_h1 on 2009/06/13 16:49:12 basic cryptographic functionality Affected files ... .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#2 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#2 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#2 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_xbase64.c#1 add .. //depot/projects/soc2009/gk_pefs/sys/modules/pefs/Makefile#2 edit Differences ... ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#2 (text+ko) ==== @@ -37,6 +37,8 @@ * $FreeBSD$ */ +#include + struct pe_mount { struct mount *pem_vfs; struct vnode *pem_rootvp; /* Reference to root pe_node */ @@ -52,15 +54,35 @@ struct vnode *pe_vnode; /* Back pointer */ }; +struct pe_xuio { + struct uio xuio_uio; + void **xuio_bases; +}; + +typedef void (*pe_tr)(void *mem, size_t size, void *arg); + #define MOUNTTOPEMOUNT(mp) ((struct pe_mount *)((mp)->mnt_data)) #define VTOPE(vp) ((struct pe_node *)(vp)->v_data) #define PETOV(xp) ((xp)->pe_vnode) +struct vfsconf; +struct vop_generic_args; + int pefs_init(struct vfsconf *vfsp); int pefs_uninit(struct vfsconf *vfsp); int pe_nodeget(struct mount *mp, struct vnode *target, struct vnode **vpp); void pe_hashrem(struct pe_node *xp); int pe_bypass(struct vop_generic_args *ap); +struct pe_xuio* pe_xuio_create(struct uio* uio); +void pe_xuio_finish(struct pe_xuio* xuio, struct uio *src); +void pe_xuio_transfrom(struct pe_xuio *xuio, struct uio *src, pe_tr tr, void *arg); +int pe_name_encrypt(const char *plain, size_t plain_len, char *enc, size_t enc_size); +int pe_name_decrypt(const char *enc, size_t enc_len, char *plain, size_t plain_size); + +void pe_xor(void *mem, size_t size, void *arg); + +int pe_b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize); +int pe_b64_pton(char const *src, size_t srclen, u_char *target, size_t targsize); #ifdef DIAGNOSTIC struct vnode *pe_checkvp(struct vnode *vp, char *fil, int lno); ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#2 (text+ko) ==== @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -69,6 +70,7 @@ static MALLOC_DEFINE(M_PEFSHASH, "pefs_hash", "PEFS hash table"); MALLOC_DEFINE(M_PEFSNODE, "pefs_node", "PEFS vnode private part"); +static MALLOC_DEFINE(M_PEFSBUF, "pefs_buf", "PEFS buffers"); static struct vnode * pe_hashget(struct mount *, struct vnode *); static struct vnode * pe_hashins(struct mount *, struct pe_node *); @@ -186,7 +188,7 @@ /* * Make a new or get existing pefs node. * Vp is the alias vnode, lowervp is the lower vnode. - * + * * 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 caller's "spare" reference to created pefs vnode. @@ -241,7 +243,7 @@ if (error != 0) return (error); /* - * Atomically insert our new node into the hash or vget existing + * Atomically insert our new node into the hash or vget existing * if someone else has beaten us to it. */ *vpp = pe_hashins(mp, xp); @@ -270,6 +272,121 @@ mtx_unlock(&pe_hashmtx); } +void +pe_xor(void *mem, size_t size, void *arg) +{ + char *b = (char *)mem; + char *e = b + size; + + for (; b < e; b++) { + *b ^= 0xAA; + } +} + +int +pe_name_encrypt(const char *plain, size_t plain_len, char *enc, size_t enc_size) +{ + char b_static[64]; + char *b; + int r; + + if (plain_len <= sizeof(b_static)) + b = b_static; + else + b = malloc(plain_len, M_PEFSBUF, M_WAITOK); + memcpy(b, plain, plain_len); + // FIXME + for (int i = 0; i < plain_len; i++) + b[i] ^= 0xAA; + r = pe_b64_ntop(b, plain_len, enc, enc_size); + printf("pe_name_encrypt: %d; %.*s => %.*s\n", r, plain_len, plain, r, enc); + if (b != b_static) + free(b, M_PEFSBUF); + return r; +} + +int +pe_name_decrypt(const char *enc, size_t enc_len, char *plain, size_t plain_size) +{ + int r; + + r = pe_b64_pton(enc, enc_len, plain, plain_size); + if (r > 0) { + // FIXME + for (int i = 0; i < r; i++) + plain[i] ^= 0xAA; + } + printf("pe_name_decrypt: %d; %.*s => %.*s\n", r, enc_len, enc, r < 0 ? 0 : r, plain); + return r; +} + +struct pe_xuio* +pe_xuio_create(struct uio* uio) +{ + struct pe_xuio *xuio; + size_t len; + int iov_cnt; + + len = 0; + for (int i = 0; i < uio->uio_iovcnt; i++) { + len += uio->uio_iov[i].iov_len; + } + + iov_cnt = (len + PAGE_SIZE - 1) / PAGE_SIZE; + xuio = malloc(sizeof(struct pe_xuio) + (sizeof(void*) + sizeof(struct iovec)) * iov_cnt, + M_PEFSBUF, M_WAITOK); + xuio->xuio_uio = *uio; + xuio->xuio_uio.uio_segflg = UIO_SYSSPACE; + xuio->xuio_uio.uio_iov = (struct iovec *)(xuio + 1); + xuio->xuio_bases = (void **)(xuio->xuio_uio.uio_iov + iov_cnt); + for (int i = 0; i < iov_cnt; i++) { + xuio->xuio_uio.uio_iov[i].iov_len = imin(PAGE_SIZE, len); + len -= PAGE_SIZE; + xuio->xuio_bases[i] = xuio->xuio_uio.uio_iov[i].iov_base = + malloc(xuio->xuio_uio.uio_iov[i].iov_len, M_PEFSBUF, M_WAITOK); + } + + return (xuio); +} + +void +pe_xuio_finish(struct pe_xuio* xuio, struct uio *src) +{ + src->uio_offset = xuio->xuio_uio.uio_offset; + src->uio_resid = xuio->xuio_uio.uio_resid; + for (int i = 0; i < xuio->xuio_uio.uio_iovcnt; i++) { + free(xuio->xuio_bases[i], M_PEFSBUF); + } + free(xuio, M_PEFSBUF); +} + +void +pe_xuio_transfrom(struct pe_xuio *_xuio, struct uio *src, pe_tr tr, void *arg) +{ + struct uio *xuio = &_xuio->xuio_uio; + + KASSERT(xuio->uio_segflg == UIO_SYSSPACE && xuio->uio_rw == src->uio_rw, + ("pe_uio_transfrom")); + for (int i = 0; i < xuio->uio_iovcnt; i++) { + int n; + void *base = xuio->uio_iov[i].iov_base; + + if (xuio->uio_rw == UIO_READ) { + n = src->uio_iov[i].iov_len - xuio->uio_iov[i].iov_len; + base = ((caddr_t) base) - n; + } else { + n = src->uio_iov[i].iov_len; + } + if (xuio->uio_rw == UIO_WRITE) + uiomove(base, n, src); + if (tr) + tr(base, n, arg); + if (xuio->uio_rw == UIO_READ) + uiomove(base, n, src); + } +} + + #ifdef DIAGNOSTIC #ifdef KDB ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#2 (text+ko) ==== @@ -181,6 +181,7 @@ #include #include #include +#include #include @@ -189,10 +190,70 @@ #include #include -static int pe_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ -SYSCTL_INT(_debug, OID_AUTO, pefs_bug_bypass, CTLFLAG_RW, +static int pe_bug_bypass = 1; /* for debugging: enables bypass printf'ing */ +SYSCTL_INT(_debug, OID_AUTO, pefs_bug_bypass, CTLFLAG_RW, &pe_bug_bypass, 0, ""); +const static struct { + size_t namelen; + const char *name; +} _pe_name_shadow_list[] = { + { 1, "." }, + { 2, ".." }, + { 4, ".zfs" }, + { 5, ".snap" }, + { 10, "lost+found" }, + { 0, NULL }, +}; + +static int +pe_name_shadow(char *name, int namelen, /*OPTIONAL*/ struct componentname *cnp) +{ + if (cnp != NULL && cnp->cn_flags & ISDOTDOT) + return (0); + for (int i = 0; _pe_name_shadow_list[i].namelen && _pe_name_shadow_list[i].namelen <= namelen; i++) { + if (namelen == _pe_name_shadow_list[i].namelen && + memcmp(_pe_name_shadow_list[i].name, name, namelen) == 0) + return (0); + } + return (1); +} + +static int +pe_cn_shadow_create(struct componentname *cnp, struct componentname *o_cnp) +{ + char *pnbuf; + int r; + + pnbuf = uma_zalloc(namei_zone, M_WAITOK); + r = pe_name_encrypt(cnp->cn_nameptr, cnp->cn_namelen, pnbuf, MAXPATHLEN); + if (r <= 0) { + uma_zfree(namei_zone, pnbuf); + return (EIO); + } + *o_cnp = *cnp; + cnp->cn_pnbuf = pnbuf; + cnp->cn_nameptr = pnbuf; + cnp->cn_namelen = r; + cnp->cn_consume = 0; // XXX?? + + printf("%s: ENC cn_nameiop=%lx, cn_pnbuf=%s; cn_nameptr=%.*s; cn_consume=%d, cn_namelen=%d\n", + __func__, cnp->cn_nameiop, cnp->cn_pnbuf, (int) cnp->cn_namelen, cnp->cn_nameptr, + (int) cnp->cn_consume, (int) cnp->cn_namelen); + + return (0); +} + +static void +pe_cn_shadow_finish(struct componentname *cnp, const struct componentname *o_cnp) +{ + uma_zfree(namei_zone, cnp->cn_pnbuf); + cnp->cn_pnbuf = o_cnp->cn_pnbuf; + cnp->cn_nameptr = o_cnp->cn_nameptr; + cnp->cn_namelen = o_cnp->cn_namelen; + cnp->cn_consume = o_cnp->cn_consume; +} + /* * This is the 10-Apr-92 bypass routine. * This version has been optimized for speed, throwing away some @@ -339,14 +400,25 @@ pe_lookup(struct vop_lookup_args *ap) { struct componentname *cnp = ap->a_cnp; + struct componentname o_cnp = *ap->a_cnp; struct vnode *dvp = ap->a_dvp; + struct vnode *vp, *ldvp, *lvp; int flags = cnp->cn_flags; - struct vnode *vp, *ldvp, *lvp; + int shadow; int error; + printf("%s: cn_nameiop=%lx, cn_pnbuf=%s; cn_nameptr=%.*s; cn_consume=%d, cn_namelen=%d\n", + __func__, cnp->cn_nameiop, cnp->cn_pnbuf, (int) cnp->cn_namelen, cnp->cn_nameptr, + (int) cnp->cn_consume, (int) cnp->cn_namelen); + if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) return (EROFS); + + shadow = pe_name_shadow(cnp->cn_nameptr, cnp->cn_namelen, cnp); + if (shadow) + pe_cn_shadow_create(cnp, &o_cnp); + /* * Although it is possible to call pe_bypass(), we'll do * a direct call to reduce overhead @@ -359,6 +431,9 @@ (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) error = EROFS; + if (shadow) + pe_cn_shadow_finish(cnp, &o_cnp); + if ((error == 0 || error == EJUSTRETURN) && lvp != NULL) { if (ldvp == lvp) { *ap->a_vpp = dvp; @@ -499,7 +574,7 @@ vrele(fvp); return (EXDEV); } - + return (pe_bypass((struct vop_generic_args *)ap)); } @@ -620,7 +695,7 @@ * on the underlying filesystem. For now we just have to release lowervp * as soon as possible. * - * Note, we can't release any resources nor remove vnode from hash before + * Note, we can't release any resources nor remove vnode from hash before * appropriate VXLOCK stuff is is done because other process can find this * vnode in hash during inactivation and may be sitting in vget() and waiting * for pe_inactive to unlock vnode. Thus we will do all those in VOP_RECLAIM. @@ -715,6 +790,138 @@ return VOP_VPTOFH(lvp, ap->a_fhp); } +static void +pe_readdir_tr(void *mem, size_t sz, void *arg) +{ + struct dirent *de; + char d_name[MAXNAMLEN]; + int d_namelen; + int de_len; + + // FIXME + for (de = (struct dirent*) mem; sz > 0; + sz -= de_len, + de = (struct dirent *)(((caddr_t)de) + de_len)) { + de_len = GENERIC_DIRSIZ(de); + if (!pe_name_shadow(de->d_name, de->d_namlen, NULL)) + continue; + d_namelen = pe_name_decrypt(de->d_name, de->d_namlen, d_name, sizeof(d_name)); + printf("%s =>; res=%d; %.*s --> %.*s\n", __func__, d_namelen, + de->d_namlen, de->d_name, + d_namelen < 0 ? 0 : d_namelen, d_name); + if (d_namelen > 0) { + /* + * Do not change d_reclen + */ + strlcpy(de->d_name, d_name, de->d_namlen + 1); + de->d_namlen = d_namelen; + } + } +} + +static int +pe_readdir(struct vop_readdir_args *ap) +{ + struct uio *uio = ap->a_uio; + struct pe_xuio *xuio; + int error; + + if (0) + pe_readdir_tr(0, 0, 0); + xuio = pe_xuio_create(uio); + ap->a_uio = &xuio->xuio_uio; + error = pe_bypass((struct vop_generic_args *)ap); + ap->a_uio = uio; + printf("%s => %d; ncookies=%d\n", __func__, error, ap->a_ncookies ? *ap->a_ncookies : -1); + pe_xuio_transfrom(xuio, uio, pe_readdir_tr, NULL); + printf("%s: result _ iovec[0]: base=%p, len=%d\n", __func__, + uio->uio_iov[0].iov_base, uio->uio_iov[0].iov_len); + pe_xuio_finish(xuio, uio); + return (error); +} + +static int +pe_mkdir(struct vop_mkdir_args *ap) +{ + struct componentname *cnp = ap->a_cnp; + struct componentname o_cnp; + int shadow, error; + + shadow = pe_name_shadow(cnp->cn_nameptr, cnp->cn_namelen, cnp); + if (shadow) + pe_cn_shadow_create(cnp, &o_cnp); + + printf("%s: cn_nameiop=%lx, cn_nameptr=%.*s\n", + __func__, cnp->cn_nameiop, (int) cnp->cn_namelen, cnp->cn_nameptr); + error = pe_bypass((struct vop_generic_args *)ap); + + if (shadow) + pe_cn_shadow_finish(cnp, &o_cnp); + + return (error); + +} + +static int +pe_read(struct vop_read_args *ap) +{ + struct vnode *vp = ap->a_vp; + struct uio *uio = ap->a_uio; + struct pe_xuio *xuio; + struct vnode *lvp; + int error; + + if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VDIR) + return (ENOTSUP); + if (uio->uio_resid == 0) + return (0); + if (uio->uio_offset < 0) + return (EINVAL); + + printf("%s: uio_offset=%ju, uio_resid=%u, uio_segflg:sysspace=%d, uio_rw=%x, ioveccnt=%d\n", + __func__, + (intmax_t) uio->uio_offset, uio->uio_resid, + uio->uio_segflg == UIO_SYSSPACE, uio->uio_rw, uio->uio_iovcnt); + xuio = pe_xuio_create(uio); + lvp = PEVPTOLOWERVP(vp); + error = VOP_READ(lvp, &xuio->xuio_uio, ap->a_ioflag, ap->a_cred); + pe_xuio_transfrom(xuio, uio, pe_xor, NULL); + pe_xuio_finish(xuio, uio); + + return (error); +} + +static int +pe_write(struct vop_write_args *ap) +{ + struct vnode *vp = ap->a_vp; + struct uio *uio = ap->a_uio; + struct pe_xuio *xuio; + struct vnode *lvp; + int error; + + if (vp->v_type == VCHR || vp->v_type == VBLK) + return (ENOTSUP); + if (vp->v_type == VDIR) + return (EISDIR); + if (uio->uio_resid == 0) + return (0); + if (uio->uio_offset < 0) + return (EINVAL); + + printf("%s: uio_offset=%ju, uio_resid=%u, uio_segflg:sysspace=%d, uio_rw=%x, ioveccnt=%d\n", + __func__, + (intmax_t) uio->uio_offset, uio->uio_resid, + uio->uio_segflg == UIO_SYSSPACE, uio->uio_rw, uio->uio_iovcnt); + xuio = pe_xuio_create(uio); + pe_xuio_transfrom(xuio, uio, pe_xor, NULL); + lvp = PEVPTOLOWERVP(vp); + error = VOP_WRITE(lvp, &xuio->xuio_uio, ap->a_ioflag, ap->a_cred); + pe_xuio_finish(xuio, uio); + + return (error); +} + /* * Global vfs data structures */ @@ -727,14 +934,27 @@ .vop_inactive = pe_inactive, .vop_islocked = vop_stdislocked, .vop_lock1 = pe_lock, - .vop_lookup = pe_lookup, .vop_open = pe_open, .vop_print = pe_print, .vop_reclaim = pe_reclaim, - .vop_rename = pe_rename, .vop_setattr = pe_setattr, .vop_strategy = VOP_EOPNOTSUPP, .vop_unlock = pe_unlock, .vop_vptocnp = vop_stdvptocnp, .vop_vptofh = pe_vptofh, + /* */ + .vop_lookup = pe_lookup, + .vop_mkdir = pe_mkdir, + .vop_rmdir = VOP_EOPNOTSUPP, + .vop_create = VOP_EOPNOTSUPP, + .vop_remove = VOP_EOPNOTSUPP, + .vop_rename = pe_rename, + .vop_link = VOP_EOPNOTSUPP, + .vop_symlink = VOP_EOPNOTSUPP, + .vop_readlink = VOP_EOPNOTSUPP, + .vop_readdir = pe_readdir, + .vop_mknod = VOP_EOPNOTSUPP, + /* */ + .vop_read = pe_read, + .vop_write = pe_write, }; ==== //depot/projects/soc2009/gk_pefs/sys/modules/pefs/Makefile#2 (text+ko) ==== @@ -4,7 +4,8 @@ KMOD= pefs SRCS= vnode_if.h \ - pefs_subr.c pefs_vfsops.c pefs_vnops.c + pefs_subr.c pefs_vfsops.c pefs_vnops.c pefs_xbase64.c +DEBUG_FLAGS= -g .include