From b0b32bff022caeffd64ca687baab908f25fa2fcb Mon Sep 17 00:00:00 2001 From: Igor Munkin <imun@tarantool.org> Date: Thu, 24 Aug 2023 17:07:19 +0300 Subject: [PATCH] uuid: relax UUID value validation This patch completely relaxes UUID checks and accepts an arbitrary 128-bit sequence as an UUID for binary data. String representations still should match the grammars in RFC 4122, Section 3 [1] and RFC 9562, Section 4 [2]. [1]: https://datatracker.ietf.org/doc/html/rfc4122#section-3 [2]: https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-format Closes #5444 @TarantoolBot document Title: uuid: relaxed UUID validation [The UUID module documentation][1] mentions that Tarantool generates UUIDs following the rules for RFC 4122,[version 4, variant 1][2]. It is worth mentioning that the user can store an arbitrary 128-bit sequence as an UUID for binary data. String representations still should match the grammars in RFC 4122, [Section 3][3], and RFC 9562, [Section 4][4]. [1]: https://www.tarantool.io/en/doc/latest/reference/reference_lua/uuid/ [2]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random) [3]: https://datatracker.ietf.org/doc/html/rfc4122#section-3 [4]: https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-format --- .../gh-5444-relax-uuid-validation.md | 4 ++ src/box/sql/mem.c | 3 +- src/lib/core/mp_uuid.c | 5 -- src/lib/core/tt_uuid.c | 3 -- src/lib/core/tt_uuid.h | 13 +----- .../gh_5444_relax_uuid_validation_test.lua | 46 +++++++++++++++++++ tools/tarantool-gdb.py | 8 ---- 7 files changed, 52 insertions(+), 30 deletions(-) create mode 100644 changelogs/unreleased/gh-5444-relax-uuid-validation.md create mode 100644 test/app-luatest/gh_5444_relax_uuid_validation_test.lua diff --git a/changelogs/unreleased/gh-5444-relax-uuid-validation.md b/changelogs/unreleased/gh-5444-relax-uuid-validation.md new file mode 100644 index 0000000000..43ae497064 --- /dev/null +++ b/changelogs/unreleased/gh-5444-relax-uuid-validation.md @@ -0,0 +1,4 @@ +## feature/core + +* Any 128-byte sequence is considered as a valid UUID value to support all + RFC 9562 UUID versions (gh-5444). diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index 67f87ce644..86fc2bf9bf 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -812,8 +812,7 @@ static inline int bin_to_uuid(struct Mem *mem) { assert(mem->type == MEM_TYPE_BIN); - if (mem->n != UUID_LEN || - tt_uuid_validate((struct tt_uuid *)mem->z) != 0) + if (mem->n != UUID_LEN) return -1; mem_set_uuid(mem, (struct tt_uuid *)mem->z); return 0; diff --git a/src/lib/core/mp_uuid.c b/src/lib/core/mp_uuid.c index b2341ae365..9dcb6fd09a 100644 --- a/src/lib/core/mp_uuid.c +++ b/src/lib/core/mp_uuid.c @@ -55,7 +55,6 @@ uuid_pack(char *data, const struct tt_uuid *uuid) struct tt_uuid * uuid_unpack(const char **data, uint32_t len, struct tt_uuid *uuid) { - const char *const svp = *data; if (len != UUID_PACKED_LEN) return NULL; uuid->time_low = mp_load_u32(data); @@ -66,10 +65,6 @@ uuid_unpack(const char **data, uint32_t len, struct tt_uuid *uuid) for (int i = 0; i < 6; i++) uuid->node[i] = mp_load_u8(data); - if (tt_uuid_validate(uuid) != 0) { - *data = svp; - return NULL; - } return uuid; } diff --git a/src/lib/core/tt_uuid.c b/src/lib/core/tt_uuid.c index d92376650c..a0a6279b67 100644 --- a/src/lib/core/tt_uuid.c +++ b/src/lib/core/tt_uuid.c @@ -65,9 +65,6 @@ tt_uuid_create(struct tt_uuid *uu) } #endif -extern inline int -tt_uuid_validate(struct tt_uuid *uu); - extern inline int tt_uuid_from_string(const char *in, struct tt_uuid *uu); diff --git a/src/lib/core/tt_uuid.h b/src/lib/core/tt_uuid.h index 70c3b98b10..2c58768c4d 100644 --- a/src/lib/core/tt_uuid.h +++ b/src/lib/core/tt_uuid.h @@ -62,16 +62,6 @@ struct tt_uuid { void tt_uuid_create(struct tt_uuid *uu); -inline int -tt_uuid_validate(struct tt_uuid *uu) -{ - /* Check variant (NCS, RFC4122, MSFT) */ - uint8_t n = uu->clock_seq_hi_and_reserved; - if ((n & 0x80) != 0x00 && (n & 0xc0) != 0x80 && (n & 0xe0) != 0xc0) - return 1; - return 0; -} - /** * \brief Parse UUID from string. * \param in string @@ -88,8 +78,7 @@ tt_uuid_from_string(const char *in, struct tt_uuid *uu) &uu->node[0], &uu->node[1], &uu->node[2], &uu->node[3], &uu->node[4], &uu->node[5]) != 11) return 1; - - return tt_uuid_validate(uu); + return 0; } /** diff --git a/test/app-luatest/gh_5444_relax_uuid_validation_test.lua b/test/app-luatest/gh_5444_relax_uuid_validation_test.lua new file mode 100644 index 0000000000..636405fcda --- /dev/null +++ b/test/app-luatest/gh_5444_relax_uuid_validation_test.lua @@ -0,0 +1,46 @@ +local uuid = require('uuid') +local msgpack = require('msgpack') +local t = require('luatest') + +local group_versions = t.group('group_versions', { + -- UUID examples taken from the RFC 9562 edition: + -- https://datatracker.ietf.org/doc/html/rfc9562#name-test-vectors + + -- The v2 implementation is not specified. Thus, it is + -- omitted here. + {version = 'v1', uuid = 'c232ab00-9414-11ec-b3c8-9f6bdeced846'}, + {version = 'v3', uuid = '5df41881-3aed-3515-88a7-2f4a814cf09e'}, + {version = 'v4', uuid = '919108f7-52d1-4320-9bac-f847db4148a8'}, + {version = 'v5', uuid = '2ed6657d-e927-568b-95e1-2665a8aea6a2'}, + {version = 'v6', uuid = '1ec9414c-232a-6b00-b3c8-9f6bdeced846'}, + {version = 'v7', uuid = '017f22e2-79b0-7cc3-98c4-dc0c0c07398f'}, + {version = 'v8_time_based', uuid = '2489e9ad-2ee2-8e00-8ec9-32d5f69181c0'}, + {version = 'v8_name_based', uuid = '5c146b14-3c52-8afd-938a-375d0df1fbf6'}, +}) + +-- Base test. +group_versions.test_version = function(cg) + local version = cg.params.version + local u = cg.params.uuid + t.assert(uuid.fromstr(u), + ('UUID %s value (%s) failed to parse'):format(version, u)) +end + +local group_gh_5444 = t.group('group_gh_5444', { + {uuid = 'bea80698-e07d-11ea-fe85-00155d373b0c'}, + {uuid = 'bee815b2-e07d-11ea-fe85-00155d373b0c'}, + {uuid = '4429d312-18d4-11eb-94f6-77e22d44915a'}, + {uuid = '64ecacb4-18d4-11eb-94f6-cbb989f20a7e'}, + {uuid = '64ecacb5-18d4-11eb-94f6-cf778123fd70'}, + {uuid = '00000000-0000-0000-e000-000000000000'}, + {uuid = '98c0cfc3-2b03-461d-b662-9a869bf46c75'}, +}) + +-- Test all examples from gh-5444. +group_gh_5444.test_all_examples = function(cg) + local u = cg.params.uuid + local uuid_cdata = uuid.fromstr(u) + t.assert(uuid_cdata, ('UUID value (%s) failed to parse'):format(u)) + t.assert(msgpack.decode(msgpack.encode(uuid_cdata)), + ('UUID value (%s) failed to be decoded in msgpack'):format(u)) +end diff --git a/tools/tarantool-gdb.py b/tools/tarantool-gdb.py index dc924af63d..e0f5d328c1 100644 --- a/tools/tarantool-gdb.py +++ b/tools/tarantool-gdb.py @@ -544,8 +544,6 @@ class TtMsgPack(MsgPack): clock_seq_low = data.read_u8(), node = [ data.read_u8() for _ in range(0, 6) ], )) - if not uuid.is_valid(): - return uuid, "uuid_unpack: invalid uuid" return uuid, None @classmethod @@ -998,12 +996,6 @@ if find_type('struct tt_uuid') is not None: def __init__(self, val): self.val = val - def is_valid(self): # tt_uuid_validate - n = self.val['clock_seq_hi_and_reserved'] - if (n & 0x80) != 0x00 and (n & 0xc0) != 0x80 and (n & 0xe0) != 0xc0: - return False - return True - def __str__(self): # tt_uuid_to_string return '{:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}'.format( self.val['time_low'], self.val['time_mid'], self.val['time_hi_and_version'], -- GitLab