Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit cd694f6

Browse files
committed
Change pgcrypto to use the new ResourceOwner mechanism.
This is a nice example of how extensions can now use ResourceOwners to track extension-specific resource kinds Reviewed-by: Peter Eisentraut, Andres Freund Discussion: https://www.postgresql.org/message-id/d746cead-a1ef-7efe-fb47-933311e876a3%40iki.fi
1 parent 954e435 commit cd694f6

File tree

1 file changed

+78
-103
lines changed

1 file changed

+78
-103
lines changed

contrib/pgcrypto/openssl.c

Lines changed: 78 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -50,64 +50,48 @@
5050
*/
5151

5252
/*
53-
* To make sure we don't leak OpenSSL handles on abort, we keep OSSLDigest
54-
* objects in a linked list, allocated in TopMemoryContext. We use the
55-
* ResourceOwner mechanism to free them on abort.
53+
* To make sure we don't leak OpenSSL handles, we use the ResourceOwner
54+
* mechanism to free them on abort.
5655
*/
5756
typedef struct OSSLDigest
5857
{
5958
const EVP_MD *algo;
6059
EVP_MD_CTX *ctx;
6160

6261
ResourceOwner owner;
63-
struct OSSLDigest *next;
64-
struct OSSLDigest *prev;
6562
} OSSLDigest;
6663

67-
static OSSLDigest *open_digests = NULL;
68-
static bool digest_resowner_callback_registered = false;
64+
/* ResourceOwner callbacks to hold OpenSSL digest handles */
65+
static void ResOwnerReleaseOSSLDigest(Datum res);
6966

70-
static void
71-
free_openssl_digest(OSSLDigest *digest)
67+
static const ResourceOwnerDesc ossldigest_resowner_desc =
7268
{
73-
EVP_MD_CTX_destroy(digest->ctx);
74-
if (digest->prev)
75-
digest->prev->next = digest->next;
76-
else
77-
open_digests = digest->next;
78-
if (digest->next)
79-
digest->next->prev = digest->prev;
80-
pfree(digest);
69+
.name = "pgcrypto OpenSSL digest handle",
70+
.release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
71+
.release_priority = RELEASE_PRIO_FIRST,
72+
.ReleaseResource = ResOwnerReleaseOSSLDigest,
73+
.DebugPrint = NULL, /* default message is fine */
74+
};
75+
76+
/* Convenience wrappers over ResourceOwnerRemember/Forget */
77+
static inline void
78+
ResourceOwnerRememberOSSLDigest(ResourceOwner owner, OSSLDigest *digest)
79+
{
80+
ResourceOwnerRemember(owner, PointerGetDatum(digest), &ossldigest_resowner_desc);
81+
}
82+
static inline void
83+
ResourceOwnerForgetOSSLDigest(ResourceOwner owner, OSSLDigest *digest)
84+
{
85+
ResourceOwnerForget(owner, PointerGetDatum(digest), &ossldigest_resowner_desc);
8186
}
8287

83-
/*
84-
* Close any open OpenSSL handles on abort.
85-
*/
8688
static void
87-
digest_free_callback(ResourceReleasePhase phase,
88-
bool isCommit,
89-
bool isTopLevel,
90-
void *arg)
89+
free_openssl_digest(OSSLDigest *digest)
9190
{
92-
OSSLDigest *curr;
93-
OSSLDigest *next;
94-
95-
if (phase != RESOURCE_RELEASE_AFTER_LOCKS)
96-
return;
97-
98-
next = open_digests;
99-
while (next)
100-
{
101-
curr = next;
102-
next = curr->next;
103-
104-
if (curr->owner == CurrentResourceOwner)
105-
{
106-
if (isCommit)
107-
elog(WARNING, "pgcrypto digest reference leak: digest %p still referenced", curr);
108-
free_openssl_digest(curr);
109-
}
110-
}
91+
EVP_MD_CTX_destroy(digest->ctx);
92+
if (digest->owner != NULL)
93+
ResourceOwnerForgetOSSLDigest(digest->owner, digest);
94+
pfree(digest);
11195
}
11296

11397
static unsigned
@@ -188,16 +172,12 @@ px_find_digest(const char *name, PX_MD **res)
188172
OpenSSL_add_all_algorithms();
189173
}
190174

191-
if (!digest_resowner_callback_registered)
192-
{
193-
RegisterResourceReleaseCallback(digest_free_callback, NULL);
194-
digest_resowner_callback_registered = true;
195-
}
196-
197175
md = EVP_get_digestbyname(name);
198176
if (md == NULL)
199177
return PXE_NO_HASH;
200178

179+
ResourceOwnerEnlarge(CurrentResourceOwner);
180+
201181
/*
202182
* Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object.
203183
* The order is crucial, to make sure we don't leak anything on
@@ -221,9 +201,7 @@ px_find_digest(const char *name, PX_MD **res)
221201
digest->algo = md;
222202
digest->ctx = ctx;
223203
digest->owner = CurrentResourceOwner;
224-
digest->next = open_digests;
225-
digest->prev = NULL;
226-
open_digests = digest;
204+
ResourceOwnerRememberOSSLDigest(digest->owner, digest);
227205

228206
/* The PX_MD object is allocated in the current memory context. */
229207
h = palloc(sizeof(*h));
@@ -239,6 +217,17 @@ px_find_digest(const char *name, PX_MD **res)
239217
return 0;
240218
}
241219

220+
/* ResourceOwner callbacks for OSSLDigest */
221+
222+
static void
223+
ResOwnerReleaseOSSLDigest(Datum res)
224+
{
225+
OSSLDigest *digest = (OSSLDigest *) DatumGetPointer(res);
226+
227+
digest->owner = NULL;
228+
free_openssl_digest(digest);
229+
}
230+
242231
/*
243232
* Ciphers
244233
*
@@ -266,9 +255,8 @@ struct ossl_cipher
266255
* OSSLCipher contains the state for using a cipher. A separate OSSLCipher
267256
* object is allocated in each px_find_cipher() call.
268257
*
269-
* To make sure we don't leak OpenSSL handles on abort, we keep OSSLCipher
270-
* objects in a linked list, allocated in TopMemoryContext. We use the
271-
* ResourceOwner mechanism to free them on abort.
258+
* To make sure we don't leak OpenSSL handles, we use the ResourceOwner
259+
* mechanism to free them on abort.
272260
*/
273261
typedef struct OSSLCipher
274262
{
@@ -281,54 +269,39 @@ typedef struct OSSLCipher
281269
const struct ossl_cipher *ciph;
282270

283271
ResourceOwner owner;
284-
struct OSSLCipher *next;
285-
struct OSSLCipher *prev;
286272
} OSSLCipher;
287273

288-
static OSSLCipher *open_ciphers = NULL;
289-
static bool cipher_resowner_callback_registered = false;
274+
/* ResourceOwner callbacks to hold OpenSSL cipher state */
275+
static void ResOwnerReleaseOSSLCipher(Datum res);
290276

291-
static void
292-
free_openssl_cipher(OSSLCipher *od)
277+
static const ResourceOwnerDesc osslcipher_resowner_desc =
293278
{
294-
EVP_CIPHER_CTX_free(od->evp_ctx);
295-
if (od->prev)
296-
od->prev->next = od->next;
297-
else
298-
open_ciphers = od->next;
299-
if (od->next)
300-
od->next->prev = od->prev;
301-
pfree(od);
279+
.name = "pgcrypto OpenSSL cipher handle",
280+
.release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
281+
.release_priority = RELEASE_PRIO_FIRST,
282+
.ReleaseResource = ResOwnerReleaseOSSLCipher,
283+
.DebugPrint = NULL, /* default message is fine */
284+
};
285+
286+
/* Convenience wrappers over ResourceOwnerRemember/Forget */
287+
static inline void
288+
ResourceOwnerRememberOSSLCipher(ResourceOwner owner, OSSLCipher *od)
289+
{
290+
ResourceOwnerRemember(owner, PointerGetDatum(od), &osslcipher_resowner_desc);
291+
}
292+
static inline void
293+
ResourceOwnerForgetOSSLCipher(ResourceOwner owner, OSSLCipher *od)
294+
{
295+
ResourceOwnerForget(owner, PointerGetDatum(od), &osslcipher_resowner_desc);
302296
}
303297

304-
/*
305-
* Close any open OpenSSL cipher handles on abort.
306-
*/
307298
static void
308-
cipher_free_callback(ResourceReleasePhase phase,
309-
bool isCommit,
310-
bool isTopLevel,
311-
void *arg)
299+
free_openssl_cipher(OSSLCipher *od)
312300
{
313-
OSSLCipher *curr;
314-
OSSLCipher *next;
315-
316-
if (phase != RESOURCE_RELEASE_AFTER_LOCKS)
317-
return;
318-
319-
next = open_ciphers;
320-
while (next)
321-
{
322-
curr = next;
323-
next = curr->next;
324-
325-
if (curr->owner == CurrentResourceOwner)
326-
{
327-
if (isCommit)
328-
elog(WARNING, "pgcrypto cipher reference leak: cipher %p still referenced", curr);
329-
free_openssl_cipher(curr);
330-
}
331-
}
301+
EVP_CIPHER_CTX_free(od->evp_ctx);
302+
if (od->owner != NULL)
303+
ResourceOwnerForgetOSSLCipher(od->owner, od);
304+
pfree(od);
332305
}
333306

334307
/* Common routines for all algorithms */
@@ -782,11 +755,7 @@ px_find_cipher(const char *name, PX_Cipher **res)
782755
if (i->name == NULL)
783756
return PXE_NO_CIPHER;
784757

785-
if (!cipher_resowner_callback_registered)
786-
{
787-
RegisterResourceReleaseCallback(cipher_free_callback, NULL);
788-
cipher_resowner_callback_registered = true;
789-
}
758+
ResourceOwnerEnlarge(CurrentResourceOwner);
790759

791760
/*
792761
* Create an OSSLCipher object, an EVP_CIPHER_CTX object and a PX_Cipher.
@@ -806,9 +775,7 @@ px_find_cipher(const char *name, PX_Cipher **res)
806775

807776
od->evp_ctx = ctx;
808777
od->owner = CurrentResourceOwner;
809-
od->next = open_ciphers;
810-
od->prev = NULL;
811-
open_ciphers = od;
778+
ResourceOwnerRememberOSSLCipher(od->owner, od);
812779

813780
if (i->ciph->cipher_func)
814781
od->evp_ciph = i->ciph->cipher_func();
@@ -827,3 +794,11 @@ px_find_cipher(const char *name, PX_Cipher **res)
827794
*res = c;
828795
return 0;
829796
}
797+
798+
/* ResourceOwner callbacks for OSSLCipher */
799+
800+
static void
801+
ResOwnerReleaseOSSLCipher(Datum res)
802+
{
803+
free_openssl_cipher((OSSLCipher *) DatumGetPointer(res));
804+
}

0 commit comments

Comments
 (0)