From d919c60e6936f853ad15040017f2c0bce0f027f8 Mon Sep 17 00:00:00 2001 From: Chih-Hsuan Yen Date: Wed, 12 Sep 2018 04:54:57 +0800 Subject: [PATCH] [2.7] bpo-32502: Discard 64-bit (and other invalid) hardware addresses (GH-9125) (cherry picked from commit 6b273f7f4056f8276f61a97c789d6bb4425e653c) Co-authored-by: Bo Bayles --- Lib/test/test_uuid.py | 33 +++++++++++++++++++ Lib/uuid.py | 14 +++++--- .../2018-01-20-17-15-34.bpo-32502.OXJfn7.rst | 2 ++ 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-01-20-17-15-34.bpo-32502.OXJfn7.rst diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 3749564c930..6cd2c392932 100644 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -287,6 +287,39 @@ class TestUUID(unittest.TestCase): node2 = uuid.getnode() self.assertEqual(node1, node2, '%012x != %012x' % (node1, node2)) + # bpo-32502: UUID1 requires a 48-bit identifier, but hardware identifiers + # need not necessarily be 48 bits (e.g., EUI-64). + def test_uuid1_eui64(self): + # Confirm that uuid.getnode ignores hardware addresses larger than 48 + # bits. Mock out each platform's *_getnode helper functions to return + # something just larger than 48 bits to test. This will cause + # uuid.getnode to fall back on uuid._random_getnode, which will + # generate a valid value. + too_large_getter = lambda: 1 << 48 + + uuid_real__node = uuid._node + uuid_real__NODE_GETTERS_WIN32 = uuid._NODE_GETTERS_WIN32 + uuid_real__NODE_GETTERS_UNIX = uuid._NODE_GETTERS_UNIX + uuid._node = None + uuid._NODE_GETTERS_WIN32 = [too_large_getter] + uuid._NODE_GETTERS_UNIX = [too_large_getter] + try: + node = uuid.getnode() + finally: + uuid._node = uuid_real__node + uuid._NODE_GETTERS_WIN32 = uuid_real__NODE_GETTERS_WIN32 + uuid._NODE_GETTERS_UNIX = uuid_real__NODE_GETTERS_UNIX + + self.assertTrue(0 < node < (1 << 48), '%012x' % node) + + # Confirm that uuid1 can use the generated node, i.e., the that + # uuid.getnode fell back on uuid._random_getnode() rather than using + # the value from too_large_getter above. + try: + uuid.uuid1(node=node) + except ValueError as e: + self.fail('uuid1 was given an invalid node ID') + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_uuid1(self): equal = self.assertEqual diff --git a/Lib/uuid.py b/Lib/uuid.py index 973013c0063..80d33c0bd83 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -522,6 +522,11 @@ def _random_getnode(): _node = None +_NODE_GETTERS_WIN32 = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] + +_NODE_GETTERS_UNIX = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode, + _lanscan_getnode, _netstat_getnode] + def getnode(): """Get the hardware address as a 48-bit positive integer. @@ -537,18 +542,19 @@ def getnode(): import sys if sys.platform == 'win32': - getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] + getters = _NODE_GETTERS_WIN32 else: - getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode, - _lanscan_getnode, _netstat_getnode] + getters = _NODE_GETTERS_UNIX for getter in getters + [_random_getnode]: try: _node = getter() except: continue - if _node is not None: + if (_node is not None) and (0 <= _node < (1 << 48)): return _node + assert False, '_random_getnode() returned invalid value: {}'.format(_node) + _last_timestamp = None diff --git a/Misc/NEWS.d/next/Library/2018-01-20-17-15-34.bpo-32502.OXJfn7.rst b/Misc/NEWS.d/next/Library/2018-01-20-17-15-34.bpo-32502.OXJfn7.rst new file mode 100644 index 00000000000..8338632aa2c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-01-20-17-15-34.bpo-32502.OXJfn7.rst @@ -0,0 +1,2 @@ +uuid.uuid1 no longer raises an exception if a 64-bit hardware address is +encountered.