[apache-poi] fix for RHBZ#1138135 (CVE-2014-3574)

gil gil at fedoraproject.org
Sat Feb 14 15:51:54 UTC 2015


commit ad3ddf5cd39eb573dd7f31f61cf3b6fb22ea2662
Author: gil <puntogil at libero.it>
Date:   Sat Feb 14 16:51:19 2015 +0100

    fix for RHBZ#1138135 (CVE-2014-3574)

 apache-poi-CVE-2014-9527.patch |  182 ++++++++++++++++++++++++++++++++++++++++
 apache-poi.spec                |   46 +++++-----
 2 files changed, 205 insertions(+), 23 deletions(-)
---
diff --git a/apache-poi-CVE-2014-9527.patch b/apache-poi-CVE-2014-9527.patch
new file mode 100644
index 0000000..a4ef6d6
--- /dev/null
+++ b/apache-poi-CVE-2014-9527.patch
@@ -0,0 +1,182 @@
+diff -Nru poi-3.10.1/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java poi-3.10.1.CVE-2014-9527/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java
+--- poi-3.10.1/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java	2014-08-13 16:05:33.000000000 +0200
++++ poi-3.10.1.CVE-2014-9527/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java	2015-02-14 16:11:13.481868934 +0100
+@@ -20,16 +20,16 @@
+ import java.io.ByteArrayInputStream;
+ import java.io.ByteArrayOutputStream;
+ import java.io.FileInputStream;
+-import java.io.FileNotFoundException;
+ import java.io.IOException;
+ import java.io.InputStream;
+ import java.io.OutputStream;
+ import java.util.ArrayList;
+-import java.util.Arrays;
+ import java.util.HashMap;
+ import java.util.Hashtable;
+ import java.util.List;
+ import java.util.Map;
++import java.util.NavigableMap;
++import java.util.TreeMap;
+ 
+ import org.apache.poi.POIDocument;
+ import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
+@@ -81,7 +81,7 @@
+ 
+     // Embedded objects stored in storage records in the document stream, lazily populated.
+     private ObjectData[] _objects;
+-
++    
+     /**
+ 	 * Returns the underlying POIFSFileSystem for the document
+ 	 *  that is open.
+@@ -195,6 +195,9 @@
+ 		// Look for any other streams
+ 		readOtherStreams();
+ 	}
++	
++	
++	
+ 	/**
+ 	 * Constructs a new, empty, Powerpoint document.
+ 	 */
+@@ -269,41 +272,67 @@
+         _records = read(_docstream, (int)currentUser.getCurrentEditOffset());
+ 	}
+ 
+-    private Record[] read(byte[] docstream, int usrOffset){
+-        ArrayList<Integer> lst = new ArrayList<Integer>();
+-        HashMap<Integer,Integer> offset2id = new HashMap<Integer,Integer>();
++	private Record[] read(byte[] docstream, int usrOffset){
++        //sort found records by offset.
++        //(it is not necessary but SlideShow.findMostRecentCoreRecords() expects them sorted)
++	    NavigableMap<Integer,Record> records = new TreeMap<Integer,Record>(); // offset -> record
++        Map<Integer,Integer> persistIds = new HashMap<Integer,Integer>(); // offset -> persistId
++        initRecordOffsets(docstream, usrOffset, records, persistIds);
++        
++        for (Map.Entry<Integer,Record> entry : records.entrySet()) {
++            Integer offset = entry.getKey();
++            Record record = entry.getValue();
++            Integer persistId = persistIds.get(offset);
++            if (record == null) {
++                // all plain records have been already added,
++                // only new records need to be decrypted (tbd #35897)
++                record = Record.buildRecordAtOffset(docstream, offset);
++                entry.setValue(record);
++            }
++            
++            if (record instanceof PersistRecord) {
++                ((PersistRecord)record).setPersistId(persistId);
++            }            
++        }
++        
++        return records.values().toArray(new Record[records.size()]);
++    }
++
++    private void initRecordOffsets(byte[] docstream, int usrOffset, NavigableMap<Integer,Record> recordMap, Map<Integer,Integer> offset2id) {
+         while (usrOffset != 0){
+             UserEditAtom usr = (UserEditAtom) Record.buildRecordAtOffset(docstream, usrOffset);
+-            lst.add(usrOffset);
++            recordMap.put(usrOffset, usr);
++            
+             int psrOffset = usr.getPersistPointersOffset();
+-
+             PersistPtrHolder ptr = (PersistPtrHolder)Record.buildRecordAtOffset(docstream, psrOffset);
+-            lst.add(psrOffset);
+-            Hashtable<Integer,Integer> entries = ptr.getSlideLocationsLookup();
+-            for(Integer id : entries.keySet()) {
+-                Integer offset = entries.get(id);
+-                lst.add(offset);
++            recordMap.put(psrOffset, ptr);
++            
++            for(Map.Entry<Integer,Integer> entry : ptr.getSlideLocationsLookup().entrySet()) {
++                Integer offset = entry.getValue();
++                Integer id = entry.getKey();
++                recordMap.put(offset, null); // reserve a slot for the record
+                 offset2id.put(offset, id);
+             }
+-
++            
+             usrOffset = usr.getLastUserEditAtomOffset();
+-        }
+-        //sort found records by offset.
+-        //(it is not necessary but SlideShow.findMostRecentCoreRecords() expects them sorted)
+-        Integer a[] = lst.toArray(new Integer[lst.size()]);
+-        Arrays.sort(a);
+-        Record[] rec = new Record[lst.size()];
+-        for (int i = 0; i < a.length; i++) {
+-            Integer offset = a[i];
+-            rec[i] = Record.buildRecordAtOffset(docstream, offset.intValue());
+-            if(rec[i] instanceof PersistRecord) {
+-                PersistRecord psr = (PersistRecord)rec[i];
+-                Integer id = offset2id.get(offset);
+-                psr.setPersistId(id.intValue());
+-            }
+-        }
+ 
+-        return rec;
++            // check for corrupted user edit atom and try to repair it
++            // if the next user edit atom offset is already known, we would go into an endless loop
++            if (usrOffset > 0 && recordMap.containsKey(usrOffset)) {
++                // a user edit atom is usually located 36 byte before the smallest known record offset 
++                usrOffset = recordMap.firstKey()-36;
++                // check that we really are located on a user edit atom
++                int ver_inst = LittleEndian.getUShort(docstream, usrOffset);
++                int type = LittleEndian.getUShort(docstream, usrOffset+2);
++                int len = LittleEndian.getInt(docstream, usrOffset+4);
++                if (ver_inst == 0 && type == 4085 && (len == 0x1C || len == 0x20)) {
++                    logger.log(POILogger.WARN, "Repairing invalid user edit atom");
++                    usr.setLastUserEditAtomOffset(usrOffset);
++                } else {
++                    throw new CorruptPowerPointFileException("Powerpoint document contains invalid user edit atom");
++                }
++            }
++        }       
+     }
+ 
+ 	/**
+@@ -324,34 +353,30 @@
+ 	private void readOtherStreams() {
+ 		// Currently, there aren't any
+ 	}
+-
+ 	/**
+ 	 * Find and read in pictures contained in this presentation.
+ 	 * This is lazily called as and when we want to touch pictures.
+ 	 */
++    @SuppressWarnings("unused")
+ 	private void readPictures() throws IOException {
+         _pictures = new ArrayList<PictureData>();
+ 
+-		byte[] pictstream;
+-
+-		try {
+-			DocumentEntry entry = (DocumentEntry)directory.getEntry("Pictures");
+-			pictstream = new byte[entry.getSize()];
+-			DocumentInputStream is = directory.createDocumentInputStream("Pictures");
+-			is.read(pictstream);
+-		} catch (FileNotFoundException e){
+-			// Silently catch exceptions if the presentation doesn't
+-			//  contain pictures - will use a null set instead
+-			return;
+-		}
++        // if the presentation doesn't contain pictures - will use a null set instead
++        if (!directory.hasEntry("Pictures")) return;
++        
++		DocumentEntry entry = (DocumentEntry)directory.getEntry("Pictures");
++		byte[] pictstream = new byte[entry.getSize()];
++		DocumentInputStream is = directory.createDocumentInputStream(entry);
++		is.read(pictstream);
++		is.close();
+ 
++		
+         int pos = 0;
+ 		// An empty picture record (length 0) will take up 8 bytes
+         while (pos <= (pictstream.length-8)) {
+             int offset = pos;
+-
++            
+             // Image signature
+-            @SuppressWarnings("unused")
+             int signature = LittleEndian.getUShort(pictstream, pos);
+             pos += LittleEndian.SHORT_SIZE;
+             // Image type + 0xF018
diff --git a/apache-poi.spec b/apache-poi.spec
index 8a43a30..520a93f 100644
--- a/apache-poi.spec
+++ b/apache-poi.spec
@@ -3,14 +3,12 @@
 
 Name:           apache-poi
 Version:        3.10.1
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        The Java API for Microsoft Documents
-
-Group:          Development/Libraries
 License:        ASL 2.0
 URL:            http://poi.apache.org/
 Source0:        http://www.apache.org/dist/poi/release/src/poi-src-%{version}-%{reldate}.tar.gz
-#Source0:        http://www.apache.org/dist/poi/dev/src/poi-src-%{version}%{?rcver}-%{reldate}.tar.gz
+#Source0:        http://www.apache.org/dist/poi/dev/src/poi-src-%%{version}%%{?rcver}-%%{reldate}.tar.gz
 Source1:        http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%201st%20edition%20Part%204%20(PDF).zip
 Source2:        http://repo2.maven.org/maven2/org/apache/poi/poi/%{version}/poi-%{version}.pom
 Source3:        http://repo2.maven.org/maven2/org/apache/poi/poi-examples/%{version}/poi-examples-%{version}.pom
@@ -21,6 +19,8 @@ Source7:        http://repo2.maven.org/maven2/org/apache/poi/poi-scratchpad/%{ve
 #Force compile of xsds if disconnected
 Patch1:         %{name}-compile-xsds.patch
 Patch2:         %{name}-build.patch
+Patch3:         %{name}-CVE-2014-9527.patch
+
 BuildArch:      noarch
 
 BuildRequires:  jpackage-utils
@@ -32,14 +32,14 @@ BuildRequires:  junit
 #Fonts for testing
 BuildRequires:  fontconfig liberation-sans-fonts liberation-serif-fonts
 BuildRequires:  jacoco
-BuildRequires:  log4j
+BuildRequires:  log4j12
 BuildRequires:  xmlbeans
 
 Requires:       jpackage-utils
 Requires:       java >= 1:1.6.0
 Requires:       dom4j
 Requires:       apache-commons-logging
-Requires:       log4j
+Requires:       log4j12
 Requires:       xmlbeans
 
 %description
@@ -72,34 +72,29 @@ contributions.
 
 There are also projects for Visio (HDGF) and Publisher (HPBF). 
 
-
 %package javadoc
-Summary:        Javadocs for %{name}
-Group:          Documentation
-Requires:       jpackage-utils
+Summary:        Javadoc for %{name}
 
 %description javadoc
 This package contains the API documentation for %{name}.
 
-
 %package manual
 Summary:        Manual for %{name}
-Group:          Documentation
-Requires:       jpackage-utils
 Requires:       %{name}-javadoc = %{version}-%{release}
 
 %description manual
 The manual for %{name}.
 
-
 %prep
 %setup -q -n poi-%{version}%{?rcver}
 %patch1 -p1 -b .compile-xsds
 %patch2 -p1 -b .build
-find -name '*.class' -exec rm -f '{}' \;
-find -name '*.jar' -exec rm -f '{}' \;
+%patch3 -p1 -b .CVE-2014-9527
+find -name '*.class' -delete
+find -name '*.jar' -delete
 mkdir lib ooxml-lib
-build-jar-repository -s -p lib ant commons-codec commons-logging jacoco junit log4j
+build-jar-repository -s -p lib ant commons-codec commons-logging jacoco junit
+ln -sf $(build-classpath log4j-1.2.17) lib/log4j.jar
 build-jar-repository -s -p ooxml-lib dom4j xmlbeans/xbean
 #Unpack the XMLSchema
 pushd ooxml-lib
@@ -158,19 +153,24 @@ ant -propertyfile build.properties test || :
 
 
 %files -f build/dist/.mfiles
-%doc KEYS LICENSE NOTICE
+%doc KEYS
 %dir %{_javadir}/poi
- %{_javadir}/poi/apache-poi*.jar
-
+%{_javadir}/poi/apache-poi*.jar
+%license LICENSE NOTICE
+ 
 %files javadoc
-%doc LICENSE
+%license LICENSE NOTICE
 %{_javadocdir}/%{name}
 
 %files manual
-%doc LICENSE docs/*
-
+%doc docs/*
+%license LICENSE NOTICE
 
 %changelog
+* Wed Feb 11 2015 gil cattaneo <puntogil at libero.it> 3.10.1-2
+- fix for RHBZ#1138135 (CVE-2014-3574)
+- introduce license macro
+
 * Thu Sep 4 2014 Orion Poplawski <orion at cora.nwra.com> - 3.10.1-1
 - Update to 3.10.1 (Bug 1138135: CVE-2014-3574 CVE-2014-3529)
 


More information about the scm-commits mailing list