Kaydet (Commit) b9d0199c authored tarafından Victor Stinner's avatar Victor Stinner

Issue #22637: avoid using a shell in uuid

Replace os.popen() with subprocess.Popen() in the uuid module.
üst 35cd53a9
import unittest import unittest.mock
from test import support from test import support
import builtins import builtins
import io import io
import os import os
import shutil import shutil
import subprocess
import uuid import uuid
def importable(name): def importable(name):
...@@ -361,28 +362,27 @@ class TestUUID(unittest.TestCase): ...@@ -361,28 +362,27 @@ class TestUUID(unittest.TestCase):
@unittest.skipUnless(os.name == 'posix', 'requires Posix') @unittest.skipUnless(os.name == 'posix', 'requires Posix')
def test_find_mac(self): def test_find_mac(self):
data = '''\ data = '''
fake hwaddr fake hwaddr
cscotun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 cscotun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
eth0 Link encap:Ethernet HWaddr 12:34:56:78:90:ab eth0 Link encap:Ethernet HWaddr 12:34:56:78:90:ab
''' '''
def mock_popen(cmd):
return io.StringIO(data) popen = unittest.mock.MagicMock()
popen.stdout = io.BytesIO(data.encode())
if shutil.which('ifconfig') is None:
path = os.pathsep.join(('/sbin', '/usr/sbin')) with unittest.mock.patch.object(shutil, 'which',
if shutil.which('ifconfig', path=path) is None: return_value='/sbin/ifconfig'):
self.skipTest('requires ifconfig') with unittest.mock.patch.object(subprocess, 'Popen',
return_value=popen):
with support.swap_attr(os, 'popen', mock_popen): mac = uuid._find_mac(
mac = uuid._find_mac( command='ifconfig',
command='ifconfig', arg='',
args='', hw_identifiers=[b'hwaddr'],
hw_identifiers=['hwaddr'], get_index=lambda x: x + 1,
get_index=lambda x: x + 1, )
)
self.assertEqual(mac, 0x1234567890ab) self.assertEqual(mac, 0x1234567890ab)
@unittest.skipUnless(importable('ctypes'), 'requires ctypes') @unittest.skipUnless(importable('ctypes'), 'requires ctypes')
def test_uuid1(self): def test_uuid1(self):
......
...@@ -304,8 +304,8 @@ class UUID(object): ...@@ -304,8 +304,8 @@ class UUID(object):
if self.variant == RFC_4122: if self.variant == RFC_4122:
return int((self.int >> 76) & 0xf) return int((self.int >> 76) & 0xf)
def _find_mac(command, args, hw_identifiers, get_index): def _find_mac(command, arg, hw_identifiers, get_index):
import os, shutil import os, shutil, subprocess
executable = shutil.which(command) executable = shutil.which(command)
if executable is None: if executable is None:
path = os.pathsep.join(('/sbin', '/usr/sbin')) path = os.pathsep.join(('/sbin', '/usr/sbin'))
...@@ -314,18 +314,26 @@ def _find_mac(command, args, hw_identifiers, get_index): ...@@ -314,18 +314,26 @@ def _find_mac(command, args, hw_identifiers, get_index):
return None return None
try: try:
# LC_ALL to ensure English output, 2>/dev/null to prevent output on # LC_ALL=C to ensure English output, stderr=DEVNULL to prevent output
# stderr (Note: we don't have an example where the words we search for # on stderr (Note: we don't have an example where the words we search
# are actually localized, but in theory some system could do so.) # for are actually localized, but in theory some system could do so.)
cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args) env = dict(os.environ)
with os.popen(cmd) as pipe: env['LC_ALL'] = 'C'
for line in pipe: cmd = [executable]
if arg:
cmd.append(arg)
proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
env=env)
with proc:
for line in proc.stdout:
words = line.lower().split() words = line.lower().split()
for i in range(len(words)): for i in range(len(words)):
if words[i] in hw_identifiers: if words[i] in hw_identifiers:
try: try:
return int( return int(
words[get_index(i)].replace(':', ''), 16) words[get_index(i)].replace(b':', b''), 16)
except (ValueError, IndexError): except (ValueError, IndexError):
# Virtual interfaces, such as those provided by # Virtual interfaces, such as those provided by
# VPNs, do not have a colon-delimited MAC address # VPNs, do not have a colon-delimited MAC address
...@@ -341,7 +349,7 @@ def _ifconfig_getnode(): ...@@ -341,7 +349,7 @@ def _ifconfig_getnode():
# This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes. # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.
for args in ('', '-a', '-av'): for args in ('', '-a', '-av'):
mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1) mac = _find_mac('ifconfig', args, [b'hwaddr', b'ether'], lambda i: i+1)
if mac: if mac:
return mac return mac
...@@ -349,12 +357,12 @@ def _ifconfig_getnode(): ...@@ -349,12 +357,12 @@ def _ifconfig_getnode():
ip_addr = socket.gethostbyname(socket.gethostname()) ip_addr = socket.gethostbyname(socket.gethostname())
# Try getting the MAC addr from arp based on our IP address (Solaris). # Try getting the MAC addr from arp based on our IP address (Solaris).
mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1) mac = _find_mac('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1)
if mac: if mac:
return mac return mac
# This might work on HP-UX. # This might work on HP-UX.
mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0) mac = _find_mac('lanscan', '-ai', [b'lan0'], lambda i: 0)
if mac: if mac:
return mac return mac
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment