From 80d420fb541aef1c51e03eb7b165bef3bf7ea518 Mon Sep 17 00:00:00 2001
From: KeithMnemonic <keith.berger@suse.com>
Date: Tue, 24 Mar 2020 11:39:54 -0400
Subject: [PATCH 3/3] Apply patch to resolve CVE-2019-0201

Should not allow to read ACL when not authorized to read node
---
 .../server/FinalRequestProcessor.java         | 11 +++++
 .../org/apache/zookeeper/test/ACLTest.java    | 45 +++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java b/src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java
index 65f7ac03..fbce46bb 100644
--- a/src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java
+++ b/src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java
@@ -309,6 +309,17 @@ public void processRequest(Request request) {
                 GetACLRequest getACLRequest = new GetACLRequest();
                 ByteBufferInputStream.byteBuffer2Record(request.request,
                         getACLRequest);
+		DataNode n = zks.getZKDatabase().getNode(getACLRequest.getPath());
+		if (n == null) {
+	            throw new KeeperException.NoNodeException();
+		}
+		Long aclL;
+		synchronized(n) {
+	            aclL = n.acl;
+	        }
+                PrepRequestProcessor.checkACL(zks, zks.getZKDatabase().aclForNode(n),
+	                ZooDefs.Perms.READ,
+	                request.authInfo);
                 Stat stat = new Stat();
                 List<ACL> acl = 
                     zks.getZKDatabase().getACL(getACLRequest.getPath(), stat);
diff --git a/src/java/test/org/apache/zookeeper/test/ACLTest.java b/src/java/test/org/apache/zookeeper/test/ACLTest.java
index 793265c5..0438b7f7 100644
--- a/src/java/test/org/apache/zookeeper/test/ACLTest.java
+++ b/src/java/test/org/apache/zookeeper/test/ACLTest.java
@@ -28,6 +28,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.PortAssignment;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
@@ -35,8 +36,10 @@
 import org.apache.zookeeper.ZooKeeper;
 import org.apache.zookeeper.Watcher.Event.KeeperState;
 import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooDefs.Perms;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Id;
+import org.apache.zookeeper.data.Stat;
 import org.apache.zookeeper.server.ServerCnxnFactory;
 import org.apache.zookeeper.server.SyncRequestProcessor;
 import org.apache.zookeeper.server.ZooKeeperServer;
@@ -77,6 +80,48 @@ public void testDisconnectedAddAuth() throws Exception {
                             ClientBase.CONNECTION_TIMEOUT));
         }
     }
+    
+    /**
+     * Verify that getAcl should fail when there is not
+     * read permission to that node
+     */
+    @Test
+    public void testAclReadPermission() throws Exception {
+        File tmpDir = ClientBase.createTmpDir();
+        ClientBase.setupTestEnv();
+        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);
+        SyncRequestProcessor.setSnapCount(1000);
+        final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]);
+        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);
+        f.startup(zks);
+        ZooKeeper zk;
+        String path = "/node1";
+        boolean readPermLimitWorks = false;
+        try {
+            LOG.info("starting up the zookeeper server .. waiting");
+            Assert.assertTrue("waiting for server being up",
+                    ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));
+            zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);            
+            Id id = new Id("ip", "127.0.0.1");
+            ArrayList<ACL> acl = new ArrayList<ACL>(); // Not set read permission
+            acl.add(new ACL(Perms.CREATE, id));
+            acl.add(new ACL(Perms.DELETE, id));
+            acl.add(new ACL(Perms.WRITE, id));
+            acl.add(new ACL(Perms.ADMIN, id));
+            zk.create(path, path.getBytes(), acl, CreateMode.PERSISTENT);            
+            Stat stat = new Stat();
+            zk.getACL(path, stat);  // Should cause exception without read permission
+        } catch (KeeperException.NoAuthException e) {
+            readPermLimitWorks = true;
+        } finally {
+            f.shutdown();
+            Assert.assertTrue("waiting for server down",
+                    ClientBase.waitForServerDown(HOSTPORT, CONNECTION_TIMEOUT));
+        }
+        if (!readPermLimitWorks) {
+            Assert.fail("Should not reach here as ACL has no read permission");
+        }
+    }
 
     /**
      * Verify that acl optimization of storing just
-- 
2.25.1

