Skip to content

Commit d382099

Browse files
committed
Issue #22637: avoid using a shell in uuid
Replace os.popen() with subprocess.Popen() in the uuid module.
1 parent da16e6e commit d382099

File tree

2 files changed

+39
-31
lines changed

2 files changed

+39
-31
lines changed

Lib/test/test_uuid.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import unittest
1+
import unittest.mock
22
from test import support
33
import builtins
44
import io
55
import os
66
import shutil
7+
import subprocess
78
import uuid
89

910
def importable(name):
@@ -361,28 +362,27 @@ def test_getnode(self):
361362

362363
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
363364
def test_find_mac(self):
364-
data = '''\
365-
365+
data = '''
366366
fake hwaddr
367367
cscotun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
368368
eth0 Link encap:Ethernet HWaddr 12:34:56:78:90:ab
369369
'''
370-
def mock_popen(cmd):
371-
return io.StringIO(data)
372-
373-
if shutil.which('ifconfig') is None:
374-
path = os.pathsep.join(('/sbin', '/usr/sbin'))
375-
if shutil.which('ifconfig', path=path) is None:
376-
self.skipTest('requires ifconfig')
377-
378-
with support.swap_attr(os, 'popen', mock_popen):
379-
mac = uuid._find_mac(
380-
command='ifconfig',
381-
args='',
382-
hw_identifiers=['hwaddr'],
383-
get_index=lambda x: x + 1,
384-
)
385-
self.assertEqual(mac, 0x1234567890ab)
370+
371+
popen = unittest.mock.MagicMock()
372+
popen.stdout = io.BytesIO(data.encode())
373+
374+
with unittest.mock.patch.object(shutil, 'which',
375+
return_value='/sbin/ifconfig'):
376+
with unittest.mock.patch.object(subprocess, 'Popen',
377+
return_value=popen):
378+
mac = uuid._find_mac(
379+
command='ifconfig',
380+
arg='',
381+
hw_identifiers=[b'hwaddr'],
382+
get_index=lambda x: x + 1,
383+
)
384+
385+
self.assertEqual(mac, 0x1234567890ab)
386386

387387
@unittest.skipUnless(importable('ctypes'), 'requires ctypes')
388388
def test_uuid1(self):

Lib/uuid.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,8 @@ def version(self):
304304
if self.variant == RFC_4122:
305305
return int((self.int >> 76) & 0xf)
306306

307-
def _find_mac(command, args, hw_identifiers, get_index):
308-
import os, shutil
307+
def _find_mac(command, arg, hw_identifiers, get_index):
308+
import os, shutil, subprocess
309309
executable = shutil.which(command)
310310
if executable is None:
311311
path = os.pathsep.join(('/sbin', '/usr/sbin'))
@@ -314,18 +314,26 @@ def _find_mac(command, args, hw_identifiers, get_index):
314314
return None
315315

316316
try:
317-
# LC_ALL to ensure English output, 2>/dev/null to prevent output on
318-
# stderr (Note: we don't have an example where the words we search for
319-
# are actually localized, but in theory some system could do so.)
320-
cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args)
321-
with os.popen(cmd) as pipe:
322-
for line in pipe:
317+
# LC_ALL=C to ensure English output, stderr=DEVNULL to prevent output
318+
# on stderr (Note: we don't have an example where the words we search
319+
# for are actually localized, but in theory some system could do so.)
320+
env = dict(os.environ)
321+
env['LC_ALL'] = 'C'
322+
cmd = [executable]
323+
if arg:
324+
cmd.append(arg)
325+
proc = subprocess.Popen(cmd,
326+
stdout=subprocess.PIPE,
327+
stderr=subprocess.DEVNULL,
328+
env=env)
329+
with proc:
330+
for line in proc.stdout:
323331
words = line.lower().split()
324332
for i in range(len(words)):
325333
if words[i] in hw_identifiers:
326334
try:
327335
return int(
328-
words[get_index(i)].replace(':', ''), 16)
336+
words[get_index(i)].replace(b':', b''), 16)
329337
except (ValueError, IndexError):
330338
# Virtual interfaces, such as those provided by
331339
# VPNs, do not have a colon-delimited MAC address
@@ -341,20 +349,20 @@ def _ifconfig_getnode():
341349

342350
# This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.
343351
for args in ('', '-a', '-av'):
344-
mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1)
352+
mac = _find_mac('ifconfig', args, [b'hwaddr', b'ether'], lambda i: i+1)
345353
if mac:
346354
return mac
347355

348356
import socket
349357
ip_addr = socket.gethostbyname(socket.gethostname())
350358

351359
# Try getting the MAC addr from arp based on our IP address (Solaris).
352-
mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1)
360+
mac = _find_mac('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1)
353361
if mac:
354362
return mac
355363

356364
# This might work on HP-UX.
357-
mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0)
365+
mac = _find_mac('lanscan', '-ai', [b'lan0'], lambda i: 0)
358366
if mac:
359367
return mac
360368

0 commit comments

Comments
 (0)