Skip to content

Commit

Permalink
uuid: relax UUID value validation
Browse files Browse the repository at this point in the history
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 tarantool#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
  • Loading branch information
igormunkin authored and Buristan committed Jul 9, 2024
1 parent 462b20d commit b0b32bf
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 30 deletions.
4 changes: 4 additions & 0 deletions changelogs/unreleased/gh-5444-relax-uuid-validation.md
Original file line number Diff line number Diff line change
@@ -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).
3 changes: 1 addition & 2 deletions src/box/sql/mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 0 additions & 5 deletions src/lib/core/mp_uuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}

Expand Down
3 changes: 0 additions & 3 deletions src/lib/core/tt_uuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
13 changes: 1 addition & 12 deletions src/lib/core/tt_uuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}

/**
Expand Down
46 changes: 46 additions & 0 deletions test/app-luatest/gh_5444_relax_uuid_validation_test.lua
Original file line number Diff line number Diff line change
@@ -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
8 changes: 0 additions & 8 deletions tools/tarantool-gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,6 @@ def decode_uuid(cls, data, len): # uuid_unpack
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
Expand Down Expand Up @@ -998,12 +996,6 @@ class Uuid:
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'],
Expand Down

0 comments on commit b0b32bf

Please sign in to comment.