[powerpc-utils-python] Resolves: rhbz#1190597 - CVE-2014-8165 powerpc-utils-python: arbitrary code execution due to unpickl

jcajka jcajka at fedoraproject.org
Mon Mar 16 14:25:51 UTC 2015


commit 45db563ec81a0174ed4f8f741f8dd1c0fb9f807d
Author: Jakub Čajka <jcajka at redhat.com>
Date:   Mon Mar 16 15:24:27 2015 +0100

    Resolves: rhbz#1190597 - CVE-2014-8165 powerpc-utils-python: arbitrary code execution due to unpickling untrusted input

 amsnet.patch              | 249 ++++++++++++++++++++++++++++++++++++++++++++++
 powerpc-utils-python.spec |  10 +-
 2 files changed, 258 insertions(+), 1 deletion(-)
---
diff --git a/amsnet.patch b/amsnet.patch
new file mode 100644
index 0000000..a50fd51
--- /dev/null
+++ b/amsnet.patch
@@ -0,0 +1,249 @@
+diff --git a/scripts/amsvis/powerpcAMS/amsnet.py b/scripts/amsvis/powerpcAMS/amsnet.py
+index 288160a..ed460f9 100644
+--- a/scripts/amsvis/powerpcAMS/amsnet.py
++++ b/scripts/amsvis/powerpcAMS/amsnet.py
+@@ -1,43 +1,50 @@
+-"""Network client/server for transmitting pickled data.
++"""Network client/server for transmitting json data.
+ """
+ 
+ __author__ = "Robert Jennings rcj at linux.vnet.ibm.com"
+ __copyright__ = "Copyright (c) 2008 IBM Corporation"
+ __license__ = "Common Public License v1.0"
+ 
+-__version__ = "$Revision: 1.3 $"
+-__date__ = "$Date: 2009/01/16 16:39:10 $"
+-# $Source: /cvsroot/powerpc-utils/powerpc-utils-papr/scripts/amsvis/powerpcAMS/amsnet.py,v $
+-
+ import socket
+-import sys
+-import os
+ import types
+ import logging
+-import cPickle as pickle
+-from optparse import OptionParser
++import json
+ 
+-from powerpcAMS.amsdata import *
++from powerpcAMS.amsdata import gather_all_data, gather_system_data
+ 
+-cmd_GET_ALL_DATA = 0
+-cmd_GET_SYS_DATA = 1
+-cmd_MAX = 1
+-data_methods = (gather_all_data, gather_system_data)
++CMD_GET_ALL_DATA = 0
++CMD_GET_SYS_DATA = 1
++CMD_MAX = 1
++DATA_METHODS = (gather_all_data, gather_system_data)
+ 
+-# Update cmdvers each time a new method is added to data_methods.
++# Update CMDVERS each time a new method is added to DATA_METHODS.
+ # The update should increment the digits to the right of the decimal point.
+ # The digits to the left of the decimal point should be increased when
+ # backwards compatibility is broken.
+-cmdvers = 1.0000000
++CMDVERS = 1.0000000
++
++def send_json_message(socket, message):
++    json_message = json.dumps(message)
++    socket.send("%d\n" % len(json_message))
++    socket.sendall(json_message)
++
++def receive_json_message(socket):
++    len_str = ''
++    while True:
++        c = socket.recv(1)
++        if c == '\n': break
++        len_str += c
++    mesg_len = int(len_str)
++    return json.loads(socket.recv(mesg_len))
+ 
+ def send_data_loop(port):
+-    """Send pickled data to any client that connects to a given network port.
++    """Send json data to any client that connects to a given network port.
+ 
+     Keyword arguments:
+     port -- network port number to use for this server
+     """
+ 
+-    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM);
++    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+     try:
+         sock.bind(('', port))
+@@ -46,7 +53,6 @@ def send_data_loop(port):
+         logging.error("Network error: (%d) " % errno + errstr)
+         return 1
+ 
+-    sockfile = None
+     conn = None
+ 
+     try:
+@@ -54,7 +60,6 @@ def send_data_loop(port):
+             sock.listen(1)
+             (conn, addr) = sock.accept()
+             logging.debug("Client connected from " + repr(addr))
+-            sockfile = conn.makefile('rwb',0)
+ 
+             result = "success"
+             data = None
+@@ -64,7 +69,7 @@ def send_data_loop(port):
+             # request data version we can change what the server will
+             # send in the future.
+             try:
+-                client_data = pickle.Unpickler(sockfile).load()
++                client_data = receive_json_message(conn)
+             except:
+                 logging.debug("Unable to parse client request.")
+                 logging.info("Bad client request, ignoring.")
+@@ -74,46 +79,41 @@ def send_data_loop(port):
+             # Currently the server only expects a dictionary from the client
+             # with the following values to send AMS data:
+             # {"command":0, "version":1.0}
+-            if (result is not "error" and 
++            if (result is not "error" and
+                  ("version" not in client_data or
+-                  client_data["version"] > cmdvers or
+-                  int(client_data["version"]) != int(cmdvers))):
++                  client_data["version"] > CMDVERS or
++                  int(client_data["version"]) != int(CMDVERS))):
+                 logging.debug("Unsupported client request version, ignoring.")
+                 result = "error"
+-                data = "Unsupported version, server is %f" % cmdvers
++                data = "Unsupported version, server is %f" % CMDVERS
+ 
+             if (result is not "error" and
+                  ("command" not in client_data or
+                   client_data["command"] < 0 or
+-                  client_data["command"] > cmd_MAX)):
++                  client_data["command"] > CMD_MAX)):
+                 logging.debug("Unsupported request from client, ignoring.")
+                 result = "error"
+                 data = "Unsupported request"
+ 
+             if result is not "error":
+-                data_method = data_methods[client_data["command"]]
++                data_method = DATA_METHODS[client_data["command"]]
+ 
+-                # Gather system data and send pickled objects to the client
++                # Gather system data and send json objects to the client
+                 data = data_method()
+                 if data is None:
+                     result = "error"
+                     data = "Unspecified data gathering error, check server log."
+-                logging.debug("Sending %d data objects to client." % len(data))
++                logging.debug("Sending %d data objects to client.", len(data))
+ 
+-            response = {"result":result, "data":data}
+-            sockfile.writelines(pickle.dumps(response, -1))
++            response = {"result": result, "data": data}
+ 
++            send_json_message(conn, response)
+             # Clean up
+-            sockfile.close()
+-            sockfile = None
+-
+             conn.close()
+             conn = None
+ 
+     # Catch a keyboard interrupt by cleaning up the socket
+     except KeyboardInterrupt:
+-        if sockfile:
+-            sockfile.close()
+         if conn:
+             conn.close()
+         sock.close()
+@@ -122,8 +122,6 @@ def send_data_loop(port):
+ 
+     # Catch a network error and clean up, return 1 to indicate an error
+     except socket.error, msg:
+-        if sockfile:
+-            sockfile.close()
+         if conn:
+             conn.close()
+         sock.close()
+@@ -133,17 +131,16 @@ def send_data_loop(port):
+ 
+     # Give the user something slightly helpful for any other error
+     except:
+-        if sockfile:
+-            sockfile.close()
+         if conn:
+             conn.close()
+         sock.close()
+         logging.error("Unknown error while sending data.")
+         raise
+ 
++
+ # Client
+-def net_get_data(host="localhost", port=50000, cmd=cmd_GET_ALL_DATA):
+-    """Get pickled data from a simple network server.
++def net_get_data(host="localhost", port=50000, cmd=CMD_GET_ALL_DATA):
++    """Get json data from a simple network server.
+ 
+     Keywork arguments:
+     host -- server host name (default localhost)
+@@ -154,42 +151,48 @@ def net_get_data(host="localhost", port=50000, cmd=cmd_GET_ALL_DATA):
+     """
+     data = {}
+ 
+-    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
++    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+     try:
+-        sock.connect((host,port))
++        sock.connect((host, port))
+     except socket.error, msg:
+         (errno, errstr) = msg.args
+         logging.error("Network error: (%d) " % errno + errstr)
+-        return {"result":"error","data":"Client: Is the server still running?"}
+-
+-    sockfile = sock.makefile('rwb',0) # read/write, unbuffered
++        return {
++            "result": "error",
++            "data": "Client: Is the server still running?",
++        }
+ 
+     # By sending a request to the server, including a version for the data
+     # request, we can change the data sent by the server in the future.
+-    if type(cmd) is types.IntType and cmd >= 0 and cmd <= cmd_MAX:
+-        client_request = {"command":cmd, "version":cmdvers}
+-        logging.debug("Sending request for %s (ver:%f)" %
+-                      (client_request["command"], client_request["version"]))
++    if type(cmd) is types.IntType and cmd >= 0 and cmd <= CMD_MAX:
++        client_request = {"command": cmd, "version": CMDVERS}
++        logging.debug("Sending request for %s (ver:%f)",
++                      client_request["command"],
++                      client_request["version"])
+     else:
+         logging.error("BUG: Unknown command request for network client.")
+         print type(cmd)
+         print repr(cmd)
+-        return {"result":"error","data":"Client: Bad request."}
++        return {
++            "result": "error",
++            "data": "Client: Bad request.",
++        }
+ 
+-    sockfile.writelines(pickle.dumps(client_request, -1))
++    send_json_message(sock, client_request)
+ 
+     # Get server response
+-    pickler = pickle.Unpickler(sockfile)
+     try:
+-        data = pickler.load()
++        data = receive_json_message(sock)
+     except EOFError:
+         pass
+-    sockfile.close()
+     sock.close()
+ 
+     if type(data) is not types.DictType or "result" not in data:
+-        data = {"result":"error", "data":"Unknown server error"}
++        data = {
++            "result": "error",
++            "data": "Unknown server error",
++        }
+ 
+     logging.debug("Data returned to client: " + repr(data))
+ 
diff --git a/powerpc-utils-python.spec b/powerpc-utils-python.spec
index 2ca876b..8a81cbb 100644
--- a/powerpc-utils-python.spec
+++ b/powerpc-utils-python.spec
@@ -2,7 +2,7 @@
 
 Name:           powerpc-utils-python
 Version:        1.2.1
-Release:        6%{?dist}
+Release:        7%{?dist}
 Summary:        Python utilities for PowerPC platforms
 
 Group:          System Environment/Base
@@ -10,6 +10,9 @@ License:        CPL
 URL:            http://sourceforge.net/projects/powerpc-utils
 Source0:        http://sourceforge.net/projects/powerpc-utils/files/%{name}/%{name}-%{version}.tar.gz
 
+# BZ#1190597 
+Patch0:         amsnet.patch
+
 BuildRequires:  python-devel
 Requires:       pygtk2 >= 2.0
 
@@ -22,6 +25,8 @@ Python based utilities for maintaining and servicing PowerPC systems.
 %prep
 %setup -q
 
+%patch0 -p1 -b .amsnet
+
 %build
 make
 
@@ -38,6 +43,9 @@ make install DESTDIR=%{buildroot} FILES=""
 %doc README COPYRIGHT
 
 %changelog
+* Mon Mar 16 2015 Jakub Čajka <jcajka at redhat.com> - 1.2.1-7
+- Resolves: rhbz#1190597 - CVE-2014-8165 powerpc-utils-python: arbitrary code execution due to unpickling untrusted input
+
 * Sat Jun 07 2014 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 1.2.1-6
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
 


More information about the scm-commits mailing list