Prevent data being truncated over persistent connection socket (#43885)

* Change how data is sent to the persistent connection socket.

We can't rely on readline(), so send the size of the data first. We can
then read that many bytes from the stream on the recieving end.

* Set pty to noncanonical mode before sending

* Now that we send data length, we don't need a sentinel anymore

* Copy socket changes to persistent, too

* Use os.write instead of fdopen()ing and using that.

* Follow pickle with sha1sum of pickle

* Swap order of vars and init being passed to ansible-connection
This commit is contained in:
Nathaniel Case
2018-08-10 09:26:58 -04:00
committed by GitHub
parent 77bff99f3c
commit f221105882
4 changed files with 77 additions and 56 deletions

View File

@@ -12,6 +12,7 @@ except Exception:
pass
import fcntl
import hashlib
import os
import signal
import socket
@@ -36,6 +37,23 @@ from ansible.utils.display import Display
from ansible.utils.jsonrpc import JsonRpcServer
def read_stream(byte_stream):
size = int(byte_stream.readline().strip())
data = byte_stream.read(size)
if len(data) < size:
raise Exception("EOF found before data was complete")
data_hash = to_text(byte_stream.readline().strip())
if data_hash != hashlib.sha1(data).hexdigest():
raise Exception("Read {0} bytes, but data did not match checksum".format(size))
# restore escaped loose \r characters
data = data.replace(br'\r', b'\r')
return data
@contextmanager
def file_lock(lock_path):
"""
@@ -204,25 +222,8 @@ def main():
try:
# read the play context data via stdin, which means depickling it
cur_line = stdin.readline()
init_data = b''
while cur_line.strip() != b'#END_INIT#':
if cur_line == b'':
raise Exception("EOF found before init data was complete")
init_data += cur_line
cur_line = stdin.readline()
cur_line = stdin.readline()
vars_data = b''
while cur_line.strip() != b'#END_VARS#':
if cur_line == b'':
raise Exception("EOF found before vars data was complete")
vars_data += cur_line
cur_line = stdin.readline()
# restore escaped loose \r characters
vars_data = vars_data.replace(br'\r', b'\r')
vars_data = read_stream(stdin)
init_data = read_stream(stdin)
if PY3:
pc_data = cPickle.loads(init_data, encoding='bytes')