summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBo Bayles <bbayles@gmail.com>2018-01-24 13:27:14 (GMT)
committerBarry Warsaw <barry@python.org>2018-01-24 13:27:14 (GMT)
commitd69794f4df81de731cc66dc82136e28bee691e1e (patch)
tree208cb2263bc1fa139ca7b2bbbe057ba93b641b4e
parent8e230e1eb3d38ad557b5dc5c31166afa35c01ff3 (diff)
downloadcpython-d69794f4df81de731cc66dc82136e28bee691e1e.zip
cpython-d69794f4df81de731cc66dc82136e28bee691e1e.tar.gz
cpython-d69794f4df81de731cc66dc82136e28bee691e1e.tar.bz2
[3.6] bpo-32502: Discard 64-bit (and other invalid) hardware addresses (GH-5254) (#5290)
* [3.6] bpo-32502: Discard 64-bit (and other invalid) hardware addresses (GH-5254). (cherry picked from commit 6b273f7f4056f8276f61a97c789d6bb4425e653c)
-rw-r--r--Lib/test/test_uuid.py26
-rw-r--r--Lib/uuid.py13
-rw-r--r--Misc/NEWS.d/next/Library/2018-01-20-17-15-34.bpo-32502.OXJfn7.rst2
3 files changed, 37 insertions, 4 deletions
diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py
index 4373fba..aa3de74 100644
--- a/Lib/test/test_uuid.py
+++ b/Lib/test/test_uuid.py
@@ -304,6 +304,32 @@ 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
+ with unittest.mock.patch.multiple(
+ uuid,
+ _node=None, # Ignore any cached node value.
+ _NODE_GETTERS_WIN32=[too_large_getter],
+ _NODE_GETTERS_UNIX=[too_large_getter],
+ ):
+ node = uuid.getnode()
+ 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 36c956e..3cd67fc 100644
--- a/Lib/uuid.py
+++ b/Lib/uuid.py
@@ -540,6 +540,11 @@ def _random_getnode():
_node = None
+_NODE_GETTERS_WIN32 = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
+
+_NODE_GETTERS_UNIX = [_unixdll_getnode, _ifconfig_getnode, _ip_getnode,
+ _arp_getnode, _lanscan_getnode, _netstat_getnode]
+
def getnode():
"""Get the hardware address as a 48-bit positive integer.
@@ -555,18 +560,18 @@ 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, _ip_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 0000000..8338632
--- /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.