From 80676c685fe2b52ce0c48a7d9d922895d0c583b8 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Thu, 29 Jun 2017 22:05:23 +0200 Subject: [PATCH] contentenc: add safer "bPool" pool variant; add pBlockPool bPool verifies the lengths of slices going in and out. Also, add a plaintext block pool - pBlockPool - and use it for decryption. --- internal/contentenc/bpool.go | 39 +++++++++++++++++++++++++++++++++ internal/contentenc/content.go | 40 +++++++++++++--------------------- internal/fusefrontend/file.go | 4 ++-- 3 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 internal/contentenc/bpool.go diff --git a/internal/contentenc/bpool.go b/internal/contentenc/bpool.go new file mode 100644 index 0000000..c4517d3 --- /dev/null +++ b/internal/contentenc/bpool.go @@ -0,0 +1,39 @@ +package contentenc + +import ( + "log" + "sync" +) + +// bPool is a byte slice pool +type bPool struct { + sync.Pool + sliceLen int +} + +func newBPool(sliceLen int) bPool { + return bPool{ + Pool: sync.Pool{ + New: func() interface{} { return make([]byte, sliceLen) }, + }, + sliceLen: sliceLen, + } +} + +// Put grows the slice "s" to its maximum capacity and puts it into the pool. +func (b *bPool) Put(s []byte) { + s = s[:cap(s)] + if len(s) != b.sliceLen { + log.Panicf("wrong len=%d, want=%d", len(s), b.sliceLen) + } + b.Pool.Put(s) +} + +// Get returns a byte slice from the pool. +func (b *bPool) Get() (s []byte) { + s = b.Pool.Get().([]byte) + if len(s) != b.sliceLen { + log.Panicf("wrong len=%d, want=%d", len(s), b.sliceLen) + } + return s +} diff --git a/internal/contentenc/content.go b/internal/contentenc/content.go index 9bc1c50..238683c 100644 --- a/internal/contentenc/content.go +++ b/internal/contentenc/content.go @@ -54,18 +54,19 @@ type ContentEnc struct { // Force decode even if integrity check fails (openSSL only) forceDecode bool // Ciphertext block pool. Always returns cipherBS-sized byte slices. - cBlockPool sync.Pool - // Ciphertext write pool. Always returns byte slices of size + cBlockPool bPool + // Ciphertext request data pool. Always returns byte slices of size // fuse.MAX_KERNEL_WRITE + overhead. - cWritePool sync.Pool - cWriteSize int + CReqPool bPool + // Plaintext block pool. Always returns plainBS-sized byte slices. + pBlockPool bPool } // New returns an initialized ContentEnc instance. func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEnc { cipherBS := plainBS + uint64(cc.IVLen) + cryptocore.AuthTagLen // Take IV and GHASH overhead into account. - cWriteSize := int(fuse.MAX_KERNEL_WRITE / plainBS * cipherBS) + cReqSize := int(fuse.MAX_KERNEL_WRITE / plainBS * cipherBS) if fuse.MAX_KERNEL_WRITE%plainBS != 0 { log.Panicf("unaligned MAX_KERNEL_WRITE=%d", fuse.MAX_KERNEL_WRITE) } @@ -76,22 +77,13 @@ func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEn allZeroBlock: make([]byte, cipherBS), allZeroNonce: make([]byte, cc.IVLen), forceDecode: forceDecode, - cWriteSize: cWriteSize, + cBlockPool: newBPool(int(cipherBS)), + CReqPool: newBPool(cReqSize), + pBlockPool: newBPool(int(plainBS)), } - c.cBlockPool.New = func() interface{} { return make([]byte, cipherBS) } - c.cWritePool.New = func() interface{} { return make([]byte, cWriteSize) } return c } -// CWritePut puts "buf" back into the cWritePool. -func (be *ContentEnc) CWritePut(buf []byte) { - buf = buf[:cap(buf)] - if len(buf) != be.cWriteSize { - log.Panicf("wrong len=%d, want=%d", len(buf), be.cWriteSize) - } - be.cWritePool.Put(buf) -} - // PlainBS returns the plaintext block size func (be *ContentEnc) PlainBS() uint64 { return be.plainBS @@ -119,6 +111,7 @@ func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, file } } pBuf.Write(pBlock) + be.pBlockPool.Put(pBlock) firstBlockNo++ } return pBuf.Bytes(), err @@ -158,7 +151,8 @@ func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileID []b ciphertext = ciphertext[be.cryptoCore.IVLen:] // Decrypt - var plaintext []byte + plaintext := be.pBlockPool.Get() + plaintext = plaintext[:0] aData := make([]byte, 8) aData = append(aData, fileID...) binary.BigEndian.PutUint64(aData, blockNo) @@ -210,16 +204,12 @@ func (be *ContentEnc) EncryptBlocks(plaintextBlocks [][]byte, firstBlockNo uint6 be.doEncryptBlocks(plaintextBlocks, ciphertextBlocks, firstBlockNo, fileID) } // Concatenate ciphertext into a single byte array. - tmp := be.cWritePool.Get().([]byte) + tmp := be.CReqPool.Get() out := bytes.NewBuffer(tmp[:0]) for _, v := range ciphertextBlocks { out.Write(v) // Return the memory to cBlockPool - cBlock := v[:cap(v)] - if len(cBlock) != int(be.cipherBS) { - log.Panicf("unexpected cBlock length: len=%d cipherBS=%d", len(cBlock), be.cipherBS) - } - be.cBlockPool.Put(cBlock) + be.cBlockPool.Put(v) } return out.Bytes() } @@ -268,7 +258,7 @@ func (be *ContentEnc) doEncryptBlock(plaintext []byte, blockNo uint64, fileID [] aData = append(aData, fileID...) // Get a cipherBS-sized block of memory, copy the nonce into it and truncate to // nonce length - cBlock := be.cBlockPool.Get().([]byte) + cBlock := be.cBlockPool.Get() copy(cBlock, nonce) cBlock = cBlock[0:len(nonce)] // Encrypt plaintext and append to nonce diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go index f70c9a5..277a71e 100644 --- a/internal/fusefrontend/file.go +++ b/internal/fusefrontend/file.go @@ -311,8 +311,8 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) { } // Write _, err = f.fd.WriteAt(ciphertext, cOff) - // Return memory to cWritePool - f.fs.contentEnc.CWritePut(ciphertext) + // Return memory to CReqPool + f.fs.contentEnc.CReqPool.Put(ciphertext) if err != nil { tlog.Warn.Printf("doWrite: Write failed: %s", err.Error()) return 0, fuse.ToStatus(err)