On Fri, Dec 25, 2020 at 09:04:41AM +0900, Michael Paquier wrote:
> Looks like the defense put in place by 6b1c5ca has allowed to catch up
> a bug here.  When base64 has been copied from encode.c to src/common/
> for SCRAM (newlines should not be handled by SCRAM, hence the copy),
> we have done the same.  The copied code just returns -1 for error
> paths.  For this case, I think that you should also prefix those
> functions with "pg_", and also include the encode part for
> completeness.

I now understand the wisdom of your suggestion.  Attached is a patch
that removes hex_decode from ecpg properly, and returns -1 from the
/common version.

-- 
  Bruce Momjian  <[email protected]>        https://momjian.us
  EnterpriseDB                             https://enterprisedb.com

  The usefulness of a cup is in its emptiness, Bruce Lee

diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c
new file mode 100644
index a6c65b1..4604e9b
*** a/src/backend/utils/adt/encode.c
--- b/src/backend/utils/adt/encode.c
*************** static const struct
*** 504,510 ****
  	{
  		"hex",
  		{
! 			hex_enc_len, hex_dec_len, hex_encode, hex_decode
  		}
  	},
  	{
--- 504,510 ----
  	{
  		"hex",
  		{
! 			hex_enc_len, hex_dec_len, hex_encode, pg_hex_decode
  		}
  	},
  	{
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
new file mode 100644
index 9300d19..60b02aa
*** a/src/backend/utils/adt/varlena.c
--- b/src/backend/utils/adt/varlena.c
*************** byteain(PG_FUNCTION_ARGS)
*** 307,313 ****
  
  		bc = (len - 2) / 2 + VARHDRSZ;	/* maximum possible length */
  		result = palloc(bc);
! 		bc = hex_decode(inputText + 2, len - 2, VARDATA(result));
  		SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */
  
  		PG_RETURN_BYTEA_P(result);
--- 307,313 ----
  
  		bc = (len - 2) / 2 + VARHDRSZ;	/* maximum possible length */
  		result = palloc(bc);
! 		bc = pg_hex_decode(inputText + 2, len - 2, VARDATA(result));
  		SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */
  
  		PG_RETURN_BYTEA_P(result);
diff --git a/src/common/hex_decode.c b/src/common/hex_decode.c
new file mode 100644
index 3ecdc73..ce17812
*** a/src/common/hex_decode.c
--- b/src/common/hex_decode.c
*************** get_hex(const char *cp)
*** 66,72 ****
  }
  
  uint64
! hex_decode(const char *src, size_t len, char *dst)
  {
  	const char *s,
  			   *srcend;
--- 66,72 ----
  }
  
  uint64
! pg_hex_decode(const char *src, size_t len, char *dst)
  {
  	const char *s,
  			   *srcend;
*************** hex_decode(const char *src, size_t len,
*** 89,96 ****
  		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),
--- 89,95 ----
  		if (s >= srcend)
  		{
  #ifdef FRONTEND
! 			return -1;
  #else
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
diff --git a/src/include/common/hex_decode.h b/src/include/common/hex_decode.h
new file mode 100644
index 1f99f06..ec210b6
*** a/src/include/common/hex_decode.h
--- b/src/include/common/hex_decode.h
***************
*** 10,16 ****
  #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 */
--- 10,16 ----
  #ifndef COMMON_HEX_DECODE_H
  #define COMMON_HEX_DECODE_H
  
! extern uint64 pg_hex_decode(const char *src, size_t len, char *dst);
  
  
  #endif							/* COMMON_HEX_DECODE_H */
diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c
new file mode 100644
index 6bc91ef..0bb43f1
*** a/src/interfaces/ecpg/ecpglib/data.c
--- b/src/interfaces/ecpg/ecpglib/data.c
***************
*** 5,10 ****
--- 5,11 ----
  
  #include <math.h>
  
+ #include "common/hex_decode.h"
  #include "ecpgerrno.h"
  #include "ecpglib.h"
  #include "ecpglib_extern.h"
*************** ecpg_hex_dec_len(unsigned srclen)
*** 136,192 ****
  	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)
  {
--- 137,142 ----
*************** ecpg_get_data(const PGresult *results, i
*** 532,538 ****
  						dst_size = ecpg_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);
  
  						if (dst_size < src_size)
  						{
--- 482,488 ----
  						dst_size = ecpg_hex_enc_len(varcharsize);
  						src_size = size - 2;	/* exclude backslash + 'x' */
  						dec_size = src_size < dst_size ? src_size : dst_size;
! 						variable->len = pg_hex_decode(pval + 2, dec_size, variable->arr);
  
  						if (dst_size < src_size)
  						{

Reply via email to