mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
linux installer script: Do not use the filesystem to pass the downloaded tarball to tar as it is possible for malicuous code running on the users computer to alter the download file between signature verification and calling tar to extract the files.
This commit is contained in:
parent
893799249b
commit
10dfa877d2
@ -7,7 +7,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import sys, os, shutil, subprocess, re, platform, time, signal, tempfile, hashlib, errno
|
import sys, os, shutil, subprocess, re, platform, signal, tempfile, hashlib, errno
|
||||||
import ssl, socket
|
import ssl, socket
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
|
|
||||||
@ -241,14 +241,13 @@ def clean_cache(cache, fname):
|
|||||||
|
|
||||||
def check_signature(dest, signature):
|
def check_signature(dest, signature):
|
||||||
if not os.path.exists(dest):
|
if not os.path.exists(dest):
|
||||||
return False
|
return None
|
||||||
m = hashlib.sha512()
|
m = hashlib.sha512()
|
||||||
with open(dest, 'rb') as f:
|
with open(dest, 'rb') as f:
|
||||||
raw = True
|
raw = f.read()
|
||||||
while raw:
|
m.update(raw)
|
||||||
raw = f.read(1024*1024)
|
if m.hexdigest().encode('ascii') == signature:
|
||||||
m.update(raw)
|
return raw
|
||||||
return m.hexdigest().encode('ascii') == signature
|
|
||||||
|
|
||||||
class URLOpener(urllib.FancyURLopener):
|
class URLOpener(urllib.FancyURLopener):
|
||||||
|
|
||||||
@ -299,9 +298,10 @@ def download_tarball():
|
|||||||
os.makedirs(cache)
|
os.makedirs(cache)
|
||||||
clean_cache(cache, fname)
|
clean_cache(cache, fname)
|
||||||
dest = os.path.join(cache, fname)
|
dest = os.path.join(cache, fname)
|
||||||
if check_signature(dest, signature):
|
raw = check_signature(dest, signature)
|
||||||
|
if raw is not None:
|
||||||
print ('Using previously downloaded', fname)
|
print ('Using previously downloaded', fname)
|
||||||
return dest
|
return raw
|
||||||
cached_sigf = dest +'.signature'
|
cached_sigf = dest +'.signature'
|
||||||
cached_sig = None
|
cached_sig = None
|
||||||
if os.path.exists(cached_sigf):
|
if os.path.exists(cached_sigf):
|
||||||
@ -320,12 +320,13 @@ def download_tarball():
|
|||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
do_download(dest)
|
do_download(dest)
|
||||||
prints('Checking downloaded file integrity...')
|
prints('Checking downloaded file integrity...')
|
||||||
if not check_signature(dest, signature):
|
raw = check_signature(dest, signature)
|
||||||
|
if raw is None:
|
||||||
os.remove(dest)
|
os.remove(dest)
|
||||||
print ('The downloaded files\' signature does not match. '
|
print ('The downloaded files\' signature does not match. '
|
||||||
'Try the download again later.')
|
'Try the download again later.')
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
return dest
|
return raw
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# Get tarball signature securely {{{
|
# Get tarball signature securely {{{
|
||||||
@ -581,14 +582,16 @@ def get_https_resource_securely(url, timeout=60, max_redirects=5, ssl_version=No
|
|||||||
return response.read()
|
return response.read()
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def extract_tarball(tar, destdir):
|
def extract_tarball(raw, destdir):
|
||||||
prints('Extracting application files...')
|
prints('Extracting application files...')
|
||||||
if hasattr(tar, 'read'):
|
|
||||||
tar = tar.name
|
|
||||||
with open('/dev/null', 'w') as null:
|
with open('/dev/null', 'w') as null:
|
||||||
subprocess.check_call(['tar', 'xjof', tar, '-C', destdir], stdout=null,
|
p = subprocess.Popen(['tar', 'xjof', '-', '-C', destdir], stdout=null, stdin=subprocess.PIPE, close_fds=True,
|
||||||
preexec_fn=lambda:
|
preexec_fn=lambda:
|
||||||
signal.signal(signal.SIGPIPE, signal.SIG_DFL))
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL))
|
||||||
|
p.stdin.write(raw)
|
||||||
|
p.stdin.close()
|
||||||
|
if p.wait() != 0:
|
||||||
|
prints('Extracting of application files failed with error code: %s' % p.returncode)
|
||||||
|
|
||||||
def get_tarball_info():
|
def get_tarball_info():
|
||||||
global signature, calibre_version
|
global signature, calibre_version
|
||||||
@ -603,24 +606,14 @@ def get_tarball_info():
|
|||||||
|
|
||||||
def download_and_extract(destdir):
|
def download_and_extract(destdir):
|
||||||
get_tarball_info()
|
get_tarball_info()
|
||||||
try:
|
raw = download_tarball()
|
||||||
f = download_tarball()
|
|
||||||
except:
|
|
||||||
raise
|
|
||||||
print('Failed to download, retrying in 30 seconds...')
|
|
||||||
time.sleep(30)
|
|
||||||
try:
|
|
||||||
f = download_tarball()
|
|
||||||
except:
|
|
||||||
print('Failed to download, aborting')
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if os.path.exists(destdir):
|
if os.path.exists(destdir):
|
||||||
shutil.rmtree(destdir)
|
shutil.rmtree(destdir)
|
||||||
os.makedirs(destdir)
|
os.makedirs(destdir)
|
||||||
|
|
||||||
print('Extracting files to %s ...'%destdir)
|
print('Extracting files to %s ...'%destdir)
|
||||||
extract_tarball(f, destdir)
|
extract_tarball(raw, destdir)
|
||||||
|
|
||||||
def check_version():
|
def check_version():
|
||||||
global calibre_version
|
global calibre_version
|
||||||
|
Loading…
x
Reference in New Issue
Block a user