On Fri, Jan 01, 2021 at 03:06:13PM -0500, Bruce Momjian wrote: > Thanks. I had to learn how to squash my commits into a new branch and > then generate a format-patch on that: > > https://bugsdb.com/_en/debug/8b648ec395b86be32efa9629cb006d74 > > I wanted to see how the cfbot liked my original patch with the renames, > and it didn't, so now I know I have to use this method for the > commitfest. Patch attached.
There are many ways to do that, indeed. On my end, I use a local branch. and then apply a set of git reset --soft before recreating a single commit. > Let me get my patch building on the cfbot and then I will address each > of these. I am trying to do one stage at a time since I am still > learning the process. Thanks. No problem. On my end, this stuff has been itching me for a couple of days and I could not recall why.. Until I remembered that the design of the hex APIs in your patch is weak with overflow handling because we don't pass down to the function the size of the destination buffer. We have finished with a similar set of issues on the past with SCRAM and base64, with has led to CVE-2019-10164 and the improvements done in cfc40d3. So I think that we need to improve things in a safer way. Mapping with the design for base64, I have finished with the attached patch, and the following set: +extern int64 pg_hex_decode(const char *src, int64 len, char *dst, int64 dstlen); +extern int64 pg_hex_encode(const char *src, int64 len, char *dst, int64 dstlen); +extern int64 pg_hex_enc_len(int64 srclen); +extern int64 pg_hex_dec_len(int64 srclen); This ensures that the result never overflows, which explains the introduction of an error code for the encoding part, and does not use elog()/pg_log() so as external libraries can use them. ECPG uses long variables in a couple of places, explaining why it feels safer to use int64. int should give enough room to any caller of those APIs, but there is no drawback in using a 64-bit API either, and I don't think it is worth the risk to break ECPG either for long handling, even if I don't believe either that folks are going to work on strings larger than 2GB. Things get trickier for the bytea input/output because we want more generic error messages depending for invalid values or an incorrect number of digits, which is why I have left the copies in encode.c. This design could be easily extended with more types of error codes, though I am not sure if that's worth bothering. Even with that, this leads to much more sanity for hex buffer manipulation in backup manifests (I don't think that using PG_SHAXXX_DIGEST_STRING_LENGTH is a good idea either, I'd like to get rid of it in the long-term) and ECPG, so that's clearly a gain. I don't have a Windows host at hand, though I think that it should work there correctly. What do you think about the ideas in the attached patch? -- Michael
From 8952fb2d5e5a7a01799fe380408a17441a185436 Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Sat, 2 Jan 2021 14:00:22 +0900 Subject: [PATCH] Refactor the hex code --- src/include/common/hex.h | 23 +++ src/include/common/hex_decode.h | 16 -- src/include/utils/builtins.h | 1 + src/backend/replication/backup_manifest.c | 39 +++-- src/backend/utils/adt/encode.c | 60 ++++++- src/backend/utils/adt/varlena.c | 12 +- src/common/Makefile | 2 +- src/common/hex.c | 166 +++++++++++++++++++ src/common/hex_decode.c | 106 ------------ src/interfaces/ecpg/ecpglib/data.c | 92 +--------- src/interfaces/ecpg/ecpglib/ecpglib_extern.h | 3 - src/interfaces/ecpg/ecpglib/execute.c | 28 +++- src/interfaces/ecpg/include/ecpgerrno.h | 1 + src/tools/msvc/Mkvcbuild.pm | 2 +- 14 files changed, 321 insertions(+), 230 deletions(-) create mode 100644 src/include/common/hex.h create mode 100644 src/common/hex.c diff --git a/src/include/common/hex.h b/src/include/common/hex.h new file mode 100644 index 0000000000..cf36895ee4 --- /dev/null +++ b/src/include/common/hex.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------ + * + * hex.h + * Encoding and decoding routines for hex strings. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/hex.h + * + *------------------------------------------------------------------------ + */ + +#ifndef COMMON_HEX_H +#define COMMON_HEX_H + +extern int64 pg_hex_decode(const char *src, int64 len, char *dst, int64 dstlen); +extern int64 pg_hex_encode(const char *src, int64 len, char *dst, int64 dstlen); +extern int64 pg_hex_enc_len(int64 srclen); +extern int64 pg_hex_dec_len(int64 srclen); + +#endif /* COMMON_HEX_H */ diff --git a/src/include/common/hex_decode.h b/src/include/common/hex_decode.h index 1f99f069b2..e69de29bb2 100644 --- a/src/include/common/hex_decode.h +++ b/src/include/common/hex_decode.h @@ -1,16 +0,0 @@ -/* - * hex_decode.h - * hex decoding - * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/common/hex_decode.h - */ -#ifndef COMMON_HEX_DECODE_H -#define COMMON_HEX_DECODE_H - -extern uint64 hex_decode(const char *src, size_t len, char *dst); - - -#endif /* COMMON_HEX_DECODE_H */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 19271e0696..c3a0601ef5 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -32,6 +32,7 @@ extern int errdatatype(Oid datatypeOid); extern int errdomainconstraint(Oid datatypeOid, const char *conname); /* encode.c */ +extern uint64 hex_decode(const char *src, size_t len, char *dst); extern uint64 hex_encode(const char *src, size_t len, char *dst); /* int.c */ diff --git a/src/backend/replication/backup_manifest.c b/src/backend/replication/backup_manifest.c index c3f339c556..6c1250ab6c 100644 --- a/src/backend/replication/backup_manifest.c +++ b/src/backend/replication/backup_manifest.c @@ -13,11 +13,11 @@ #include "postgres.h" #include "access/timeline.h" +#include "common/hex.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" #include "mb/pg_wchar.h" #include "replication/backup_manifest.h" -#include "utils/builtins.h" #include "utils/json.h" static void AppendStringToManifest(backup_manifest_info *manifest, char *s); @@ -150,10 +150,17 @@ AddFileToBackupManifest(backup_manifest_info *manifest, const char *spcoid, } else { + int64 dstlen = pg_hex_enc_len(pathlen); + int64 res; + appendStringInfoString(&buf, "{ \"Encoded-Path\": \""); - enlargeStringInfo(&buf, 2 * pathlen); - buf.len += hex_encode(pathname, pathlen, - &buf.data[buf.len]); + enlargeStringInfo(&buf, dstlen); + res = pg_hex_encode(pathname, pathlen, + &buf.data[buf.len], dstlen); + if (res < 0) + elog(ERROR, "could not encode path \"%s\" in backup manifest", + pathname); + buf.len += res; appendStringInfoString(&buf, "\", "); } @@ -176,6 +183,8 @@ AddFileToBackupManifest(backup_manifest_info *manifest, const char *spcoid, { uint8 checksumbuf[PG_CHECKSUM_MAX_LENGTH]; int checksumlen; + int64 dstlen; + int64 res; checksumlen = pg_checksum_final(checksum_ctx, checksumbuf); if (checksumlen < 0) @@ -185,9 +194,14 @@ AddFileToBackupManifest(backup_manifest_info *manifest, const char *spcoid, appendStringInfo(&buf, ", \"Checksum-Algorithm\": \"%s\", \"Checksum\": \"", pg_checksum_type_name(checksum_ctx->type)); - enlargeStringInfo(&buf, 2 * checksumlen); - buf.len += hex_encode((char *) checksumbuf, checksumlen, - &buf.data[buf.len]); + dstlen = pg_hex_enc_len(checksumlen); + enlargeStringInfo(&buf, dstlen); + res = pg_hex_encode((char *) checksumbuf, checksumlen, + &buf.data[buf.len], dstlen); + if (res < 0) + elog(ERROR, "could not encode checksum algorithm of file \"%s\"", + pathname); + buf.len += res; appendStringInfoChar(&buf, '"'); } @@ -307,8 +321,9 @@ SendBackupManifest(backup_manifest_info *manifest) { StringInfoData protobuf; uint8 checksumbuf[PG_SHA256_DIGEST_LENGTH]; - char checksumstringbuf[PG_SHA256_DIGEST_STRING_LENGTH]; + char *checksumstringbuf; size_t manifest_bytes_done = 0; + int64 dstlen; if (!IsManifestEnabled(manifest)) return; @@ -328,8 +343,12 @@ SendBackupManifest(backup_manifest_info *manifest) if (pg_cryptohash_final(manifest->manifest_ctx, checksumbuf) < 0) elog(ERROR, "failed to finalize checksum of backup manifest"); AppendStringToManifest(manifest, "\"Manifest-Checksum\": \""); - hex_encode((char *) checksumbuf, sizeof checksumbuf, checksumstringbuf); - checksumstringbuf[PG_SHA256_DIGEST_STRING_LENGTH - 1] = '\0'; + dstlen = pg_hex_enc_len(PG_SHA256_DIGEST_LENGTH); + checksumstringbuf = palloc0(dstlen + 1); /* includes \0 */ + if (pg_hex_encode((char *) checksumbuf, sizeof checksumbuf, + checksumstringbuf, dstlen) < 0) + elog(ERROR, "could not encode SHA2 result in backup manifest"); + checksumstringbuf[dstlen] = '\0'; AppendStringToManifest(manifest, checksumstringbuf); AppendStringToManifest(manifest, "\"}\n"); diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c index a6c65b1657..4e8f673335 100644 --- a/src/backend/utils/adt/encode.c +++ b/src/backend/utils/adt/encode.c @@ -15,7 +15,6 @@ #include <ctype.h> -#include "common/hex_decode.h" #include "mb/pg_wchar.h" #include "utils/builtins.h" #include "utils/memutils.h" @@ -147,6 +146,17 @@ binary_decode(PG_FUNCTION_ARGS) static const char hextbl[] = "0123456789abcdef"; +static const int8 hexlookup[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + uint64 hex_encode(const char *src, size_t len, char *dst) { @@ -161,6 +171,54 @@ hex_encode(const char *src, size_t len, char *dst) return (uint64) len * 2; } +static inline char +get_hex(char c) +{ + int res = -1; + + if (c > 0 && c < 127) + res = hexlookup[(unsigned char) c]; + + if (res < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid hexadecimal digit: \"%c\"", c))); + + return (char) res; +} + +uint64 +hex_decode(const char *src, size_t len, char *dst) +{ + const char *s, + *srcend; + char v1, + v2, + *p; + + srcend = src + len; + s = src; + p = dst; + while (s < srcend) + { + if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') + { + s++; + continue; + } + v1 = get_hex(*s++) << 4; + if (s >= srcend) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid hexadecimal data: odd number of digits"))); + + v2 = get_hex(*s++); + *p++ = v1 | v2; + } + + return p - dst; +} + static uint64 hex_enc_len(const char *src, size_t srclen) { diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 9300d19e0c..35f0e78238 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -21,8 +21,8 @@ #include "catalog/pg_collation.h" #include "catalog/pg_type.h" #include "common/hashfn.h" +#include "common/hex.h" #include "common/int.h" -#include "common/hex_decode.h" #include "common/unicode_norm.h" #include "lib/hyperloglog.h" #include "libpq/pqformat.h" @@ -307,6 +307,11 @@ byteain(PG_FUNCTION_ARGS) bc = (len - 2) / 2 + VARHDRSZ; /* maximum possible length */ result = palloc(bc); + + /* + * Note that this does not use the hex implementation in src/common/ + * to get a proper error handling. + */ bc = hex_decode(inputText + 2, len - 2, VARDATA(result)); SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */ @@ -400,6 +405,11 @@ byteaout(PG_FUNCTION_ARGS) rp = result = palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1); *rp++ = '\\'; *rp++ = 'x'; + + /* + * Note that this does not use the hex implementation in src/common/ + * to get a proper error handling. + */ rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp); } else if (bytea_output == BYTEA_OUTPUT_ESCAPE) diff --git a/src/common/Makefile b/src/common/Makefile index f624977939..93eb27a2aa 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -58,7 +58,7 @@ OBJS_COMMON = \ file_perm.o \ file_utils.o \ hashfn.o \ - hex_decode.o \ + hex.o \ ip.o \ jsonapi.o \ keywords.o \ diff --git a/src/common/hex.c b/src/common/hex.c new file mode 100644 index 0000000000..1e16c3291c --- /dev/null +++ b/src/common/hex.c @@ -0,0 +1,166 @@ +/*------------------------------------------------------------------------- + * + * hex.c + * Encoding and decoding routines for hex. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/hex.c + * + *------------------------------------------------------------------------- + */ + + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/hex.h" +#include "mb/pg_wchar.h" + + +static const int8 hexlookup[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const char hextbl[] = "0123456789abcdef"; + +static inline char +get_hex(const char *cp) +{ + unsigned char c = (unsigned char) *cp; + int res = -1; + + if (c < 127) + res = hexlookup[c]; + + if (res < 0) + return -1; + + return (char) res; +} + +/* + * pg_hex_encode + * + * Encode into hex the given string. Returns the length of the encoded + * string, and -1 in the event of an error with the result buffer zeroed + * for safety. + */ +int64 +pg_hex_encode(const char *src, int64 len, char *dst, int64 dstlen) +{ + const char *end = src + len; + char *p; + + p = dst; + + while (src < end) + { + /* + * Leave if there is an overflow in the area allocated for the + * encoded string. + */ + if ((p - dst + 2) > dstlen) + goto error; + + *p++ = hextbl[(*src >> 4) & 0xF]; + *p++ = hextbl[*src & 0xF]; + src++; + } + return len * 2; + +error: + memset(dst, 0, dstlen); + return -1; +} + +/* + * pg_hex_decode + * + * Decode the given hex string. Returns the length of the decoded + * string on success, and -1 in the event of an error with the result + * buffer zeroed for safety. + */ +int64 +pg_hex_decode(const char *src, int64 len, char *dst, int64 dstlen) +{ + const char *s, + *srcend; + char v1, + v2, + *p; + + srcend = src + len; + s = src; + p = dst; + while (s < srcend) + { + if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') + { + s++; + continue; + } + v1 = get_hex(s) << 4; + s++; + + if (s >= srcend) + goto error; + + v2 = get_hex(s); + s++; + + /* overflow check */ + if ((p - dst + 1) > dstlen) + goto error; + + *p++ = v1 | v2; + } + + + Assert((p - dst) <= dstlen); + return p - dst; + +error: + memset(dst, 0, dstlen); + return -1; +} + +/* + * pg_hex_enc_len + * + * Returns to caller the length of the string if it were encoded with + * hex based on the length provided by caller. This is useful to* estimate + * how large a buffer allocation needs to be done before doing the actual + * encoding. + */ +int64 +pg_hex_enc_len(int64 srclen) +{ + return (srclen << 1); +} + +/* + * pg_hex_dec_len + * + * Returns to caller the length of the string if it were to be decoded + * with hex, based on the length given by caller. This is useful to + * estimate how large a buffer allocation needs to be done before doing + * the actual decoding. + */ +int64 +pg_hex_dec_len(int64 srclen) +{ + return (srclen >> 1); +} diff --git a/src/common/hex_decode.c b/src/common/hex_decode.c index 3ecdc73b5c..e69de29bb2 100644 --- a/src/common/hex_decode.c +++ b/src/common/hex_decode.c @@ -1,106 +0,0 @@ -/*------------------------------------------------------------------------- - * - * hex_decode.c - * hex decoding - * - * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/common/hex_decode.c - * - *------------------------------------------------------------------------- - */ - - -#ifndef FRONTEND -#include "postgres.h" -#else -#include "postgres_fe.h" -#endif - -#ifdef FRONTEND -#include "common/logging.h" -#else -#include "mb/pg_wchar.h" -#endif -#include "common/hex_decode.h" - - -static const int8 hexlookup[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -}; - -static inline char -get_hex(const char *cp) -{ - unsigned char c = (unsigned char) *cp; - int res = -1; - - if (c < 127) - res = hexlookup[c]; - - if (res < 0) - { -#ifdef FRONTEND - pg_log_fatal("invalid hexadecimal digit"); - exit(EXIT_FAILURE); -#else - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid hexadecimal digit: \"%.*s\"", - pg_mblen(cp), cp))); -#endif - } - - return (char) res; -} - -uint64 -hex_decode(const char *src, size_t len, char *dst) -{ - const char *s, - *srcend; - char v1, - v2, - *p; - - srcend = src + len; - s = src; - p = dst; - while (s < srcend) - { - if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') - { - s++; - continue; - } - v1 = get_hex(s) << 4; - s++; - if (s >= srcend) - { -#ifdef FRONTEND - pg_log_fatal("invalid hexadecimal data: odd number of digits"); - exit(EXIT_FAILURE); -#else - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid hexadecimal data: odd number of digits"))); -#endif - } - v2 = get_hex(s); - s++; - *p++ = v1 | v2; - } - - return p - dst; -} diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c index 6bc91ef7eb..7b79a6a5de 100644 --- a/src/interfaces/ecpg/ecpglib/data.c +++ b/src/interfaces/ecpg/ecpglib/data.c @@ -5,6 +5,7 @@ #include <math.h> +#include "common/hex.h" #include "ecpgerrno.h" #include "ecpglib.h" #include "ecpglib_extern.h" @@ -122,86 +123,6 @@ check_special_value(char *ptr, double *retval, char **endptr) return false; } -/* imported from src/backend/utils/adt/encode.c */ - -unsigned -ecpg_hex_enc_len(unsigned srclen) -{ - return srclen << 1; -} - -unsigned -ecpg_hex_dec_len(unsigned srclen) -{ - return srclen >> 1; -} - -static inline char -get_hex(char c) -{ - static const int8 hexlookup[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - }; - int res = -1; - - if (c > 0 && c < 127) - res = hexlookup[(unsigned char) c]; - - return (char) res; -} - -static unsigned -hex_decode(const char *src, unsigned len, char *dst) -{ - const char *s, - *srcend; - char v1, - v2, - *p; - - srcend = src + len; - s = src; - p = dst; - while (s < srcend) - { - if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') - { - s++; - continue; - } - v1 = get_hex(*s++) << 4; - if (s >= srcend) - return -1; - - v2 = get_hex(*s++); - *p++ = v1 | v2; - } - - return p - dst; -} - -unsigned -ecpg_hex_encode(const char *src, unsigned len, char *dst) -{ - static const char hextbl[] = "0123456789abcdef"; - const char *end = src + len; - - while (src < end) - { - *dst++ = hextbl[(*src >> 4) & 0xF]; - *dst++ = hextbl[*src & 0xF]; - src++; - } - return len * 2; -} - bool ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, enum ECPGttype type, enum ECPGttype ind_type, @@ -529,14 +450,19 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, src_size, dec_size; - dst_size = ecpg_hex_enc_len(varcharsize); + dst_size = pg_hex_enc_len(varcharsize); src_size = size - 2; /* exclude backslash + 'x' */ dec_size = src_size < dst_size ? src_size : dst_size; - variable->len = hex_decode(pval + 2, dec_size, variable->arr); + variable->len = pg_hex_decode(pval + 2, dec_size, variable->arr, dst_size); + + if (variable->len < 0) + ecpg_raise(lineno, ECPG_OVERFLOW, + ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, + NULL); if (dst_size < src_size) { - long rcv_size = ecpg_hex_dec_len(size - 2); + long rcv_size = pg_hex_dec_len(size - 2); /* truncation */ switch (ind_type) diff --git a/src/interfaces/ecpg/ecpglib/ecpglib_extern.h b/src/interfaces/ecpg/ecpglib/ecpglib_extern.h index 1a98dea1b5..cdde4903ec 100644 --- a/src/interfaces/ecpg/ecpglib/ecpglib_extern.h +++ b/src/interfaces/ecpg/ecpglib/ecpglib_extern.h @@ -215,9 +215,6 @@ struct sqlda_compat *ecpg_build_compat_sqlda(int, PGresult *, int, enum COMPAT_M void ecpg_set_compat_sqlda(int, struct sqlda_compat **, const PGresult *, int, enum COMPAT_MODE); struct sqlda_struct *ecpg_build_native_sqlda(int, PGresult *, int, enum COMPAT_MODE); void ecpg_set_native_sqlda(int, struct sqlda_struct **, const PGresult *, int, enum COMPAT_MODE); -unsigned ecpg_hex_dec_len(unsigned srclen); -unsigned ecpg_hex_enc_len(unsigned srclen); -unsigned ecpg_hex_encode(const char *src, unsigned len, char *dst); #ifdef ENABLE_NLS extern char *ecpg_gettext(const char *msgid) pg_attribute_format_arg(1); diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index 930b6adbe4..5b16f5ed2c 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -19,6 +19,7 @@ #include <math.h> #include "catalog/pg_type_d.h" +#include "common/hex.h" #include "ecpgerrno.h" #include "ecpglib.h" #include "ecpglib_extern.h" @@ -491,16 +492,18 @@ static char * convert_bytea_to_string(char *from_data, int from_len, int lineno) { char *to_data; - int to_len = ecpg_hex_enc_len(from_len) + 4 + 1; /* backslash + 'x' + - * quote + quote */ + int dstlen = pg_hex_enc_len(from_len); + int to_len = dstlen + 4 + 1; /* backslash + 'x' + + * quote + quote */ to_data = ecpg_alloc(to_len, lineno); if (!to_data) return NULL; strcpy(to_data, "'\\x"); - ecpg_hex_encode(from_data, from_len, to_data + 3); - strcpy(to_data + 3 + ecpg_hex_enc_len(from_len), "\'"); + if (pg_hex_encode(from_data, from_len, to_data + 3, dstlen) < 0) + return NULL; + strcpy(to_data + 3 + pg_hex_enc_len(from_len), "\'"); return to_data; } @@ -1087,12 +1090,21 @@ print_param_value(char *value, int len, int is_binary, int lineno, int nth) value_s = value; else { - value_s = ecpg_alloc(ecpg_hex_enc_len(len) + 1, lineno); + int dstlen = pg_hex_enc_len(len); + + value_s = ecpg_alloc(dstlen + 1, lineno); if (value_s != NULL) { - ecpg_hex_encode(value, len, value_s); - value_s[ecpg_hex_enc_len(len)] = '\0'; - malloced = true; + if (pg_hex_encode(value, len, value_s, dstlen) >= 0) + { + value_s[dstlen] = '\0'; + malloced = true; + } + else + { + ecpg_free(value_s); + value_s = "error when encoding parameter"; + } } else value_s = "no memory for logging of parameter"; diff --git a/src/interfaces/ecpg/include/ecpgerrno.h b/src/interfaces/ecpg/include/ecpgerrno.h index c4bc526463..ee88740035 100644 --- a/src/interfaces/ecpg/include/ecpgerrno.h +++ b/src/interfaces/ecpg/include/ecpgerrno.h @@ -32,6 +32,7 @@ #define ECPG_NO_ARRAY -214 #define ECPG_DATA_NOT_ARRAY -215 #define ECPG_ARRAY_INSERT -216 +#define ECPG_OVERFLOW -217 #define ECPG_NO_CONN -220 #define ECPG_NOT_CONN -221 diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 7f014a12c9..60b216cce0 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -121,7 +121,7 @@ sub mkvcbuild our @pgcommonallfiles = qw( archive.c base64.c checksum_helper.c config_info.c controldata_utils.c d2s.c encnames.c exec.c - f2s.c file_perm.c file_utils.c hashfn.c hex_decode.c ip.c jsonapi.c + f2s.c file_perm.c file_utils.c hashfn.c hex.c ip.c jsonapi.c keywords.c kwlookup.c link-canary.c md5_common.c pg_get_line.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c -- 2.30.0
signature.asc
Description: PGP signature