From 35f72c6e7cb50b9518b7f18cbf4aa1f9364aa3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Arboleda?= Date: Tue, 25 Aug 2020 15:31:11 -0500 Subject: [PATCH] src: create helper for reading Uint32BE Fixes: https://github.com/nodejs/node/issues/34827 PR-URL: https://github.com/nodejs/node/pull/34944 Reviewed-By: Anna Henningsen --- node.gyp | 1 + src/base64-inl.h | 98 ++++++++++++++++++++++++++++++++++++++++++++ src/base64.h | 78 ++--------------------------------- src/cares_wrap.cc | 18 +++----- src/node_sockaddr.cc | 3 +- 5 files changed, 110 insertions(+), 88 deletions(-) create mode 100644 src/base64-inl.h diff --git a/node.gyp b/node.gyp index da55779b1bbb44..a685f50ae4de5e 100644 --- a/node.gyp +++ b/node.gyp @@ -669,6 +669,7 @@ 'src/base_object.h', 'src/base_object-inl.h', 'src/base64.h', + 'src/base64-inl.h', 'src/callback_queue.h', 'src/callback_queue-inl.h', 'src/connect_wrap.h', diff --git a/src/base64-inl.h b/src/base64-inl.h new file mode 100644 index 00000000000000..9132faa614ea2b --- /dev/null +++ b/src/base64-inl.h @@ -0,0 +1,98 @@ +#ifndef SRC_BASE64_INL_H_ +#define SRC_BASE64_INL_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include "util.h" + +namespace node { + +extern const int8_t unbase64_table[256]; + + +inline static int8_t unbase64(uint8_t x) { + return unbase64_table[x]; +} + + +inline uint32_t ReadUint32BE(const unsigned char* p) { + return static_cast(p[0] << 24U) | + static_cast(p[1] << 16U) | + static_cast(p[2] << 8U) | + static_cast(p[3]); +} + + +template +bool base64_decode_group_slow(char* const dst, const size_t dstlen, + const TypeName* const src, const size_t srclen, + size_t* const i, size_t* const k) { + uint8_t hi; + uint8_t lo; +#define V(expr) \ + for (;;) { \ + const uint8_t c = src[*i]; \ + lo = unbase64(c); \ + *i += 1; \ + if (lo < 64) \ + break; /* Legal character. */ \ + if (c == '=' || *i >= srclen) \ + return false; /* Stop decoding. */ \ + } \ + expr; \ + if (*i >= srclen) \ + return false; \ + if (*k >= dstlen) \ + return false; \ + hi = lo; + V(/* Nothing. */); + V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); + V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); + V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); +#undef V + return true; // Continue decoding. +} + + +template +size_t base64_decode_fast(char* const dst, const size_t dstlen, + const TypeName* const src, const size_t srclen, + const size_t decoded_size) { + const size_t available = dstlen < decoded_size ? dstlen : decoded_size; + const size_t max_k = available / 3 * 3; + size_t max_i = srclen / 4 * 4; + size_t i = 0; + size_t k = 0; + while (i < max_i && k < max_k) { + const unsigned char txt[] = { + static_cast(unbase64(src[i + 0])), + static_cast(unbase64(src[i + 1])), + static_cast(unbase64(src[i + 2])), + static_cast(unbase64(src[i + 3])), + }; + + const uint32_t v = ReadUint32BE(txt); + // If MSB is set, input contains whitespace or is not valid base64. + if (v & 0x80808080) { + if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k)) + return k; + max_i = i + (srclen - i) / 4 * 4; // Align max_i again. + } else { + dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); + dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); + dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F); + i += 4; + k += 3; + } + } + if (i < srclen && k < dstlen) { + base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k); + } + return k; +} + +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_BASE64_INL_H_ diff --git a/src/base64.h b/src/base64.h index 1cb90bdeba75b0..24fc57e1d60385 100644 --- a/src/base64.h +++ b/src/base64.h @@ -4,6 +4,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "util.h" +#include "base64-inl.h" #include #include @@ -20,6 +21,8 @@ static inline constexpr size_t base64_decoded_size_fast(size_t size) { return size > 1 ? (size / 4) * 3 + (size % 4 + 1) / 2 : 0; } +inline uint32_t ReadUint32BE(const unsigned char* p); + template size_t base64_decoded_size(const TypeName* src, size_t size) { // 1-byte input cannot be decoded @@ -34,81 +37,6 @@ size_t base64_decoded_size(const TypeName* src, size_t size) { return base64_decoded_size_fast(size); } - -extern const int8_t unbase64_table[256]; - - -inline static int8_t unbase64(uint8_t x) { - return unbase64_table[x]; -} - - -template -bool base64_decode_group_slow(char* const dst, const size_t dstlen, - const TypeName* const src, const size_t srclen, - size_t* const i, size_t* const k) { - uint8_t hi; - uint8_t lo; -#define V(expr) \ - for (;;) { \ - const uint8_t c = src[*i]; \ - lo = unbase64(c); \ - *i += 1; \ - if (lo < 64) \ - break; /* Legal character. */ \ - if (c == '=' || *i >= srclen) \ - return false; /* Stop decoding. */ \ - } \ - expr; \ - if (*i >= srclen) \ - return false; \ - if (*k >= dstlen) \ - return false; \ - hi = lo; - V(/* Nothing. */); - V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); - V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); - V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); -#undef V - return true; // Continue decoding. -} - - -template -size_t base64_decode_fast(char* const dst, const size_t dstlen, - const TypeName* const src, const size_t srclen, - const size_t decoded_size) { - const size_t available = dstlen < decoded_size ? dstlen : decoded_size; - const size_t max_k = available / 3 * 3; - size_t max_i = srclen / 4 * 4; - size_t i = 0; - size_t k = 0; - while (i < max_i && k < max_k) { - const uint32_t v = - unbase64(src[i + 0]) << 24 | - unbase64(src[i + 1]) << 16 | - unbase64(src[i + 2]) << 8 | - unbase64(src[i + 3]); - // If MSB is set, input contains whitespace or is not valid base64. - if (v & 0x80808080) { - if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k)) - return k; - max_i = i + (srclen - i) / 4 * 4; // Align max_i again. - } else { - dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); - dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); - dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F); - i += 4; - k += 3; - } - } - if (i < srclen && k < dstlen) { - base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k); - } - return k; -} - - template size_t base64_decode(char* const dst, const size_t dstlen, const TypeName* const src, const size_t srclen) { diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 73a0ac6b334345..defe1ef37497b2 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -22,6 +22,7 @@ #define CARES_STATICLIB #include "ares.h" #include "async_wrap-inl.h" +#include "base64-inl.h" #include "env-inl.h" #include "memory_tracker-inl.h" #include "node.h" @@ -79,13 +80,6 @@ inline uint16_t cares_get_16bit(const unsigned char* p) { return static_cast(p[0] << 8U) | (static_cast(p[1])); } -inline uint32_t cares_get_32bit(const unsigned char* p) { - return static_cast(p[0] << 24U) | - static_cast(p[1] << 16U) | - static_cast(p[2] << 8U) | - static_cast(p[3]); -} - const int ns_t_cname_or_a = -1; #define DNS_ESETSRVPENDING -1000 @@ -1127,11 +1121,11 @@ int ParseSoaReply(Environment* env, return ARES_EBADRESP; } - const unsigned int serial = cares_get_32bit(ptr + 0 * 4); - const unsigned int refresh = cares_get_32bit(ptr + 1 * 4); - const unsigned int retry = cares_get_32bit(ptr + 2 * 4); - const unsigned int expire = cares_get_32bit(ptr + 3 * 4); - const unsigned int minttl = cares_get_32bit(ptr + 4 * 4); + const unsigned int serial = ReadUint32BE(ptr + 0 * 4); + const unsigned int refresh = ReadUint32BE(ptr + 1 * 4); + const unsigned int retry = ReadUint32BE(ptr + 2 * 4); + const unsigned int expire = ReadUint32BE(ptr + 3 * 4); + const unsigned int minttl = ReadUint32BE(ptr + 4 * 4); Local soa_record = Object::New(env->isolate()); soa_record->Set(context, diff --git a/src/node_sockaddr.cc b/src/node_sockaddr.cc index 58d03eefa6e6e6..8d7c93255b0d81 100644 --- a/src/node_sockaddr.cc +++ b/src/node_sockaddr.cc @@ -1,5 +1,6 @@ #include "node_sockaddr-inl.h" // NOLINT(build/include) #include "env-inl.h" +#include "base64-inl.h" #include "base_object-inl.h" #include "memory_tracker-inl.h" #include "uv.h" @@ -302,7 +303,7 @@ bool in_network_ipv6_ipv4( return false; ptr += sizeof(mask); - uint32_t check = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; + uint32_t check = ReadUint32BE(ptr); return (check & m) == (htonl(net_in->sin_addr.s_addr) & m); }