michelp / pgsodium

Modern cryptography for PostgreSQL using libsodium.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Wrong memory space allocated

ioguix opened this issue · comments

Hi,

I have a memory warning when using PostgreSQL 15.1 compiled with --enabled-cassert (enables MEMORY_CONTEXT_CHECKING) and current HEAD of pgsodium. See:

nacl=# SELECT convert_from(
    pgsodium.crypto_aead_det_decrypt(
        decode('TA3aB8kpo4tZFbonlD6UPS3WeOMD6QxiAMDfWZ0bu+nkMtZQ', 'base64'), 
        '', 
        'acf73c9c-a1f3-473b-ae3a-9daff68f05fa'::uuid, 
        NULL::bytea), 
    'utf8'::name
);
WARNING:  problem in alloc set ExprContext: detected write past chunk end in block 0x20b29c0, chunk 0x20b2a10
WARNING:  problem in alloc set ExprContext: detected write past chunk end in block 0x20b29c0, chunk 0x20b2a10
 convert_from 
--------------
 blah
(1 row)

I might be wrong, but I suspect some missing header size or something related when allocating space in pgsodium_crypto_aead_det_encrypt_by_id and other equivalent funcs. Which means more data are written to in the allocated space than asked when the data AND its header are written there.

By the way, note that if I give NULL as additional data, it just crash:

nacl=# SELECT convert_from(
    pgsodium.crypto_aead_det_decrypt(
        decode('TA3aB8kpo4tZFbonlD6UPS3WeOMD6QxiAMDfWZ0bu+nkMtZQ', 'base64'), 
        NULL, 
        'acf73c9c-a1f3-473b-ae3a-9daff68f05fa'::uuid, 
        NULL::bytea), 
    'utf8'::name
);
server closed the connection unexpectedly
	This probably means the server terminated abnormally
	before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.
The connection to the server was lost. Attempting reset: Failed.

The backtrace:

(gdb) bt
#0  0x0000000000b35976 in pg_detoast_datum (datum=0x0) at fmgr.c:1710
#1  0x00007fd48dd8d0df in pgsodium_crypto_aead_det_decrypt_by_id (fcinfo=0x2090440) at src/aead.c:304
[...]

The source code being:

pgsodium_crypto_aead_det_decrypt_by_id (PG_FUNCTION_ARGS)
{
	bytea      *ciphertext = PG_GETARG_BYTEA_P (0);
	bytea      *additional = PG_GETARG_BYTEA_P (1); // <- 304

Regards,

commented

This is same as supabase/vault#3, interesting thing is it is only on macOS, not on Linux.

Well, the case I describe here is under linux.

I think it comes from the size allocated in pgsodium_crypto_aead_det_decrypt_by_id. It should include the header size of varlena fields:

- 	result = _pgsodium_zalloc_bytea (result_len);
+ 	result = _pgsodium_zalloc_bytea (result_len + VARHDRSZ);

Note that this varlena header size is include at the end of function when setting the variable size:

	SET_VARSIZE (result, VARHDRSZ + result_len);

A test with this patch removes the warning on my side.

A quick glance at other functions around shows htere's some more places that need to be fixed as well.

Well snap, I thought I caught these cases but must have missed a couple, I'm adding a debug build to my test runner so that it compiles with --enabled-cassert and I'll push a fix today. Thank you @ioguix !

Yep clearly some confusion going on all this time on my part on the varlen headers. Using the stock upstream dockerfile as an expedient was clearly the too lazy approach, so I've added a debug dockerfile that enables cassert and gdb and turns off optimizations etc, and some others, I've got a branch up here

https://github.com/michelp/pgsodium/compare/fix/bad-varlena-size#diff-dd2c0eb6ea5cfc6c4bd4eac30934e2d5746747af48fef6da689e85b752f39557R19

and I'm working my way through these in the tests one by one. Feel free to comment on this approach if you have any suggestions.

Fixed with #46