diff -Nru tomcat7-7.0.68/debian/changelog tomcat7-7.0.68/debian/changelog --- tomcat7-7.0.68/debian/changelog 2016-06-27 18:15:07.000000000 +0000 +++ tomcat7-7.0.68/debian/changelog 2018-10-24 18:59:54.000000000 +0000 @@ -1,3 +1,76 @@ +tomcat7 (7.0.68-1ubuntu0.3) xenial-security; urgency=medium + + * SECURITY UPDATE: Timing attack can determine valid user names. + - debian/patches/CVE-2016-0762.patch: fix in the Realm + implementation. + - CVE-2016-0762 + * SECURITY UPDATE: privilege escalation via insecure init script + - debian/tomcat7.init: don't follow symlinks when handling the + catalina.out file. + - CVE-2016-1240 + * SECURITY UPDATE: SecurityManager bypass via a utility method. + - debian/patches/CVE-2016-5018.patch: remove unnecessary code in + java/org/apache/jasper/compiler/JspRuntimeContext.java, + java/org/apache/jasper/runtime/JspRuntimeLibrary.java, + java/org/apache/jasper/security/SecurityClassLoad.java. + - debian/patches/CVE-2016-5018-part2.patch: fix a regression when + using Jasper with SecurityManager enabled. + - CVE-2016-5018 + * SECURITY UPDATE: system properties read SecurityManager bypass + - debian/patches/CVE-2016-6794.patch: extend SecurityManager + protection to the system property replacement feature of the + digester in java/org/apache/catalina/loader/WebappClassLoader.java, + java/org/apache/tomcat/util/digester/Digester.java, + java/org/apache/tomcat/util/security/PermissionCheck.java. + - CVE-2016-6794 + * SECURITY UPDATE: SecurityManager bypass via JSP Servlet configuration + parameters. + - debian/patches/CVE-2016-6796.patch: ignore some JSP options when + running under a SecurityManager in conf/web.xml, + java/org/apache/jasper/EmbeddedServletOptions.java, + java/org/apache/jasper/resources/LocalStrings.properties, + java/org/apache/jasper/servlet/JspServlet.java, + webapps/docs/jasper-howto.xml. + - CVE-2016-6796 + * SECURITY UPDATE: web application global JNDI resource access + - debian/patches/CVE-2016-6797.patch: ensure that the global resource + is only visible via the ResourceLinkFactory when it is meant to be + in java/org/apache/catalina/core/NamingContextListener.java, + java/org/apache/naming/factory/ResourceLinkFactory.java, + test/org/apache/naming/TestNamingContext.java. + - CVE-2016-6797 + * SECURITY UPDATE: HTTP response injection via invalid characters + - debian/patches/CVE-2016-6816.patch: add additional checks for valid + characters in + java/org/apache/coyote/http11/AbstractInputBuffer.java, + java/org/apache/coyote/http11/AbstractNioInputBuffer.java, + java/org/apache/coyote/http11/InternalAprInputBuffer.java, + java/org/apache/coyote/http11/InternalInputBuffer.java, + java/org/apache/coyote/http11/LocalStrings.properties, + java/org/apache/tomcat/util/http/parser/HttpParser.java. + - CVE-2016-6816 + * SECURITY UPDATE: remote code execution via JmxRemoteLifecycleListener + - debian/patches/CVE-2016-8735.patch: explicitly configure allowed + credential types in + java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java. + - CVE-2016-8735 + * SECURITY UPDATE: information leakage between requests + - debian/patches/CVE-2016-8745.patch: properly handle cache when + unable to complete sendfile request in + java/org/apache/tomcat/util/net/NioEndpoint.java. + - CVE-2016-8745 + * SECURITY UPDATE: privilege escalation during package upgrade + - debian/rules, debian/tomcat7.postinst: properly set permissions on + /etc/tomcat7/Catalina/localhost. + - CVE-2016-9774 + * SECURITY UPDATE: privilege escalation during package removal + - debian/tomcat7.postrm.in: don't reset permissions before removing + user. + - CVE-2016-9775 + * debian/tomcat7.init: further hardening. + + -- Eduardo Barretto Fri, 19 Oct 2018 10:46:37 -0300 + tomcat7 (7.0.68-1ubuntu0.1) xenial-security; urgency=medium * SECURITY UPDATE: denial of service in FileUpload Binary files /tmp/tmpKZJ977/geB1gyrq2Q/tomcat7-7.0.68/debian/keystores/localhost-copy1.jks and /tmp/tmpKZJ977/nuanN8WRhd/tomcat7-7.0.68/debian/keystores/localhost-copy1.jks differ Binary files /tmp/tmpKZJ977/geB1gyrq2Q/tomcat7-7.0.68/debian/keystores/localhost.jks and /tmp/tmpKZJ977/nuanN8WRhd/tomcat7-7.0.68/debian/keystores/localhost.jks differ Binary files /tmp/tmpKZJ977/geB1gyrq2Q/tomcat7-7.0.68/debian/keystores/user1.jks and /tmp/tmpKZJ977/nuanN8WRhd/tomcat7-7.0.68/debian/keystores/user1.jks differ diff -Nru tomcat7-7.0.68/debian/patches/0027-update-certs.patch tomcat7-7.0.68/debian/patches/0027-update-certs.patch --- tomcat7-7.0.68/debian/patches/0027-update-certs.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/0027-update-certs.patch 2018-10-23 15:47:37.000000000 +0000 @@ -0,0 +1,211 @@ +From cef7ed761003e8ca4d3f98dc502f449ee5d0de3d Mon Sep 17 00:00:00 2001 +From: Eduardo Barretto +Date: Mon, 22 Oct 2018 16:14:13 -0300 +Subject: [PATCH] update-certs + +--- + .../apache/tomcat/util/net/localhost-cert.pem | 116 +++++++++--------- + .../apache/tomcat/util/net/localhost-key.pem | 52 ++++---- + 5 files changed, 84 insertions(+), 84 deletions(-) + +diff --git a/test/org/apache/tomcat/util/net/localhost-cert.pem b/test/org/apache/tomcat/util/net/localhost-cert.pem +index 2fb4596..4d7ab1d 100644 +--- a/test/org/apache/tomcat/util/net/localhost-cert.pem ++++ b/test/org/apache/tomcat/util/net/localhost-cert.pem +@@ -1,79 +1,79 @@ + Certificate: + Data: + Version: 3 (0x2) +- Serial Number: 4102 (0x1006) +- Signature Algorithm: sha1WithRSAEncryption ++ Serial Number: 4109 (0x100d) ++ Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, CN=ca-test.tomcat.apache.org + Validity +- Not Before: Feb 28 16:57:14 2015 GMT +- Not After : Feb 27 16:57:14 2017 GMT ++ Not Before: Feb 27 23:25:29 2017 GMT ++ Not After : Feb 27 23:25:29 2019 GMT + Subject: C=US, CN=localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: +- 00:e7:6f:79:3f:18:87:91:dd:27:98:34:24:79:58: +- 47:f9:c2:69:2b:d8:5b:c0:e0:bb:4a:57:d6:00:b5: +- bb:6a:b0:66:84:5c:b8:f0:12:0a:27:27:32:9c:82: +- 2a:2f:0f:69:77:a6:e9:0d:df:64:31:51:c0:41:1e: +- dc:d4:74:51:9c:a3:b8:51:13:58:73:ee:21:9c:f9: +- 63:82:1b:c2:2c:49:c3:09:70:ff:a9:f3:af:a2:0c: +- 0b:60:2f:6a:db:a5:01:45:3e:34:90:8e:67:69:eb: +- 45:f3:34:29:85:db:39:8a:99:c2:0f:72:15:21:fd: +- 54:35:a6:7b:a7:30:cb:1e:4d:3d:32:24:c6:4b:84: +- 4f:5f:60:ff:64:5e:68:ca:d8:fa:de:98:7d:40:04: +- 60:b7:ae:50:ec:c8:8c:ae:dd:94:81:41:18:5b:03: +- 63:0f:2b:02:63:0a:95:6a:ed:7e:68:e6:b6:d5:56: +- e9:4e:60:ea:1d:95:58:33:be:a2:12:55:cb:7f:9c: +- c4:97:0b:db:c0:94:09:2a:b3:9f:e1:6b:78:0d:63: +- 1a:41:d5:6b:db:d8:48:59:04:88:d1:11:d5:e7:45: +- 28:0e:7c:1b:78:75:20:7d:ff:7f:e1:d6:ea:e4:c5: +- 51:77:41:42:30:4b:ff:29:33:3d:89:58:94:69:5b: +- 70:27 ++ 00:ba:d6:b2:32:de:10:53:1f:5d:af:da:d4:3f:64: ++ b3:22:37:fd:4e:16:a3:f0:d6:9e:6e:d3:ee:47:ec: ++ 15:b4:b3:0d:80:bf:fc:21:96:8b:1d:40:16:6d:89: ++ 35:03:8a:45:8c:c6:6e:2b:66:67:0f:1c:19:cf:62: ++ d5:e6:08:48:a8:df:10:da:4c:47:79:7c:02:97:54: ++ f9:a8:e9:59:50:33:cd:a0:72:fd:e1:e7:5e:3a:43: ++ 5c:ff:0c:69:9e:f6:c2:86:71:07:a5:eb:b5:c7:61: ++ f9:e9:fe:3f:26:55:2c:f4:04:7c:c0:bd:cd:2b:88: ++ 9c:69:4d:ce:3c:1e:ad:2e:18:96:aa:a0:eb:72:2b: ++ 95:99:47:16:90:b5:59:ed:f1:78:cc:8b:01:33:40: ++ c4:e9:b0:3f:ec:89:04:13:5c:9b:22:01:cc:25:cf: ++ 40:c1:40:fa:04:a0:b9:b7:f7:d8:73:91:7f:b8:7e: ++ e9:82:20:1f:e9:9c:89:25:28:b5:fa:6f:b7:4a:88: ++ 28:68:59:d5:30:52:f9:e4:5b:a6:b4:f8:e4:ed:2f: ++ 03:d8:50:61:9a:53:86:1f:ad:aa:0d:5f:f8:52:b5: ++ 27:dd:05:82:25:13:a0:d0:10:3c:dd:c0:70:15:24: ++ 63:89:22:0e:f0:5a:9a:fa:b0:75:56:06:aa:7f:b0: ++ f7:9b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate +- X509v3 Subject Key Identifier: +- 30:DB:AB:70:94:34:CA:FD:75:46:AB:CE:E2:4A:A9:9E:74:BC:69:BB ++ X509v3 Subject Key Identifier: ++ 0B:37:2F:D6:48:9C:11:2F:28:AE:DC:47:E6:5E:3A:1D:24:12:0F:1A + X509v3 Authority Key Identifier: + keyid:B0:3B:BC:C9:FA:28:5F:3E:04:1F:9B:6C:C7:8B:68:D8:01:B0:F8:3D + +- Signature Algorithm: sha1WithRSAEncryption +- ac:e9:89:a0:fd:83:a7:aa:39:0b:08:f2:89:bc:64:e4:fa:3f: +- 7d:7a:5e:6d:79:98:34:31:19:ec:fb:e3:07:2b:ff:ab:2f:58: +- 7f:49:33:ca:d1:bb:36:9c:bd:3d:e2:3b:39:e9:a9:c2:b7:9e: +- 58:7d:5c:f4:9f:02:80:0b:e2:e2:d8:b8:3a:c0:76:c7:3b:33: +- 29:2a:61:02:ac:e0:23:aa:3e:a7:0d:0a:e9:8b:2d:4d:2a:ed: +- 59:0c:05:2d:40:86:ed:63:ad:fd:3c:a0:5e:4e:77:a6:f5:fe: +- 16:19:e5:bf:66:2f:c0:a3:21:25:65:a8:30:0b:25:9e:b4:67: +- ad:9d:7a:33:c2:c7:c0:18:80:ef:f0:ea:1f:33:6b:f5:d6:b6: +- 7c:47:8d:99:b5:be:77:cd:61:ba:27:11:a0:8e:19:0f:8b:2d: +- 3d:70:ac:44:b3:f7:f5:a1:a7:a9:36:93:89:e4:63:cc:89:50: +- ea:cc:c0:5a:c1:a7:41:7b:2f:64:c3:1e:e2:7f:62:72:3a:a1: +- d5:9f:8d:83:bf:f4:10:5f:3b:e3:48:fd:2c:7c:55:7f:81:e2: +- e3:2f:95:53:67:20:40:97:2a:cf:cf:f2:e0:13:0d:02:fe:9f: +- 43:93:01:55:22:5b:d9:b6:fd:a6:55:6c:c8:68:dc:3c:73:e7: +- 29:14:78:29 ++ Signature Algorithm: sha256WithRSAEncryption ++ 3b:0a:ad:f2:27:26:d4:db:bc:97:e7:4e:52:8b:6c:08:4d:7b: ++ e7:66:ec:81:0b:0c:04:f8:b9:92:35:12:c9:b9:ed:d2:5e:b7: ++ ac:89:67:72:7e:2b:4f:5b:e3:3a:d1:09:fe:e8:cf:33:ac:a5: ++ 84:95:7f:48:4d:af:59:87:0b:4c:6f:6a:bf:6b:07:af:33:13: ++ 19:fd:70:0d:fc:1c:92:04:be:05:b9:96:46:d5:82:a4:f8:3b: ++ b0:11:2d:f0:19:25:ba:d6:ce:1c:7a:17:76:c6:80:d2:73:a0: ++ 1a:01:48:d6:0b:12:a9:3f:50:66:81:1b:e9:9f:1e:5b:6f:d1: ++ 19:12:14:70:d3:de:4c:ab:d3:83:d6:e5:4f:bb:b3:e5:c6:87: ++ 16:47:f7:59:4d:9d:52:9d:00:f0:24:7a:1e:6e:14:01:0d:07: ++ 0c:b6:f7:4e:c0:40:77:65:fd:ac:c7:aa:73:77:f0:44:b1:30: ++ ad:65:83:1a:cc:bd:fa:9d:80:29:61:e9:b3:26:e8:3b:55:c7: ++ 12:79:3e:4d:31:f1:21:d0:4e:5f:1f:73:c3:9f:ce:f9:6c:7e: ++ 8e:11:10:8e:f6:60:d2:11:ae:0f:24:6e:10:71:42:05:ed:ea: ++ 4b:41:86:86:84:26:74:ed:46:81:48:34:16:40:e6:df:64:c9: ++ c2:7d:6b:1b + -----BEGIN CERTIFICATE----- +-MIIDSTCCAjGgAwIBAgICEAYwDQYJKoZIhvcNAQEFBQAwMTELMAkGA1UEBhMCVVMx +-IjAgBgNVBAMTGWNhLXRlc3QudG9tY2F0LmFwYWNoZS5vcmcwHhcNMTUwMjI4MTY1 +-NzE0WhcNMTcwMjI3MTY1NzE0WjAhMQswCQYDVQQGEwJVUzESMBAGA1UEAxMJbG9j +-YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5295PxiHkd0n +-mDQkeVhH+cJpK9hbwOC7SlfWALW7arBmhFy48BIKJycynIIqLw9pd6bpDd9kMVHA +-QR7c1HRRnKO4URNYc+4hnPljghvCLEnDCXD/qfOvogwLYC9q26UBRT40kI5naetF +-8zQphds5ipnCD3IVIf1UNaZ7pzDLHk09MiTGS4RPX2D/ZF5oytj63ph9QARgt65Q +-7MiMrt2UgUEYWwNjDysCYwqVau1+aOa21VbpTmDqHZVYM76iElXLf5zElwvbwJQJ +-KrOf4Wt4DWMaQdVr29hIWQSI0RHV50UoDnwbeHUgff9/4dbq5MVRd0FCMEv/KTM9 +-iViUaVtwJwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVu +-U1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUMNurcJQ0yv11RqvO +-4kqpnnS8abswHwYDVR0jBBgwFoAUsDu8yfooXz4EH5tsx4to2AGw+D0wDQYJKoZI +-hvcNAQEFBQADggEBAKzpiaD9g6eqOQsI8om8ZOT6P316Xm15mDQxGez74wcr/6sv +-WH9JM8rRuzacvT3iOznpqcK3nlh9XPSfAoAL4uLYuDrAdsc7MykqYQKs4COqPqcN +-CumLLU0q7VkMBS1Ahu1jrf08oF5Od6b1/hYZ5b9mL8CjISVlqDALJZ60Z62dejPC +-x8AYgO/w6h8za/XWtnxHjZm1vnfNYbonEaCOGQ+LLT1wrESz9/Whp6k2k4nkY8yJ +-UOrMwFrBp0F7L2TDHuJ/YnI6odWfjYO/9BBfO+NI/Sx8VX+B4uMvlVNnIECXKs/P +-8uATDQL+n0OTAVUiW9m2/aZVbMho3Dxz5ykUeCk= ++MIIDSTCCAjGgAwIBAgICEA0wDQYJKoZIhvcNAQELBQAwMTELMAkGA1UEBhMCVVMx ++IjAgBgNVBAMMGWNhLXRlc3QudG9tY2F0LmFwYWNoZS5vcmcwHhcNMTcwMjI3MjMy ++NTI5WhcNMTkwMjI3MjMyNTI5WjAhMQswCQYDVQQGEwJVUzESMBAGA1UEAxMJbG9j ++YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAutayMt4QUx9d ++r9rUP2SzIjf9Thaj8NaebtPuR+wVtLMNgL/8IZaLHUAWbYk1A4pFjMZuK2ZnDxwZ ++z2LV5ghIqN8Q2kxHeXwCl1T5qOlZUDPNoHL94edeOkNc/wxpnvbChnEHpeu1x2H5 ++6f4/JlUs9AR8wL3NK4icaU3OPB6tLhiWqqDrciuVmUcWkLVZ7fF4zIsBM0DE6bA/ ++7IkEE1ybIgHMJc9AwUD6BKC5t/fYc5F/uH7pgiAf6ZyJJSi1+m+3SogoaFnVMFL5 ++5FumtPjk7S8D2FBhmlOGH62qDV/4UrUn3QWCJROg0BA83cBwFSRjiSIO8Fqa+rB1 ++Vgaqf7D3mwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVu ++U1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUCzcv1kicES8ortxH ++5l46HSQSDxowHwYDVR0jBBgwFoAUsDu8yfooXz4EH5tsx4to2AGw+D0wDQYJKoZI ++hvcNAQELBQADggEBADsKrfInJtTbvJfnTlKLbAhNe+dm7IELDAT4uZI1Esm57dJe ++t6yJZ3J+K09b4zrRCf7ozzOspYSVf0hNr1mHC0xvar9rB68zExn9cA38HJIEvgW5 ++lkbVgqT4O7ARLfAZJbrWzhx6F3bGgNJzoBoBSNYLEqk/UGaBG+mfHltv0RkSFHDT ++3kyr04PW5U+7s+XGhxZH91lNnVKdAPAkeh5uFAENBwy2907AQHdl/azHqnN38ESx ++MK1lgxrMvfqdgClh6bMm6DtVxxJ5Pk0x8SHQTl8fc8Ofzvlsfo4REI72YNIRrg8k ++bhBxQgXt6ktBhoaEJnTtRoFINBZA5t9kycJ9axs= + -----END CERTIFICATE----- +diff --git a/test/org/apache/tomcat/util/net/localhost-key.pem b/test/org/apache/tomcat/util/net/localhost-key.pem +index 911476d..527f77c 100644 +--- a/test/org/apache/tomcat/util/net/localhost-key.pem ++++ b/test/org/apache/tomcat/util/net/localhost-key.pem +@@ -1,28 +1,28 @@ + -----BEGIN PRIVATE KEY----- +-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDnb3k/GIeR3SeY +-NCR5WEf5wmkr2FvA4LtKV9YAtbtqsGaEXLjwEgonJzKcgiovD2l3pukN32QxUcBB +-HtzUdFGco7hRE1hz7iGc+WOCG8IsScMJcP+p86+iDAtgL2rbpQFFPjSQjmdp60Xz +-NCmF2zmKmcIPchUh/VQ1pnunMMseTT0yJMZLhE9fYP9kXmjK2PremH1ABGC3rlDs +-yIyu3ZSBQRhbA2MPKwJjCpVq7X5o5rbVVulOYOodlVgzvqISVct/nMSXC9vAlAkq +-s5/ha3gNYxpB1Wvb2EhZBIjREdXnRSgOfBt4dSB9/3/h1urkxVF3QUIwS/8pMz2J +-WJRpW3AnAgMBAAECggEBALfaj6h3NSPEW7MHIT6gyjT4o5IoQ+O65C6QDrrrpCKC +-Vj6qZmSZACXQdt1sblSKWs+p8hSKNc8UUbWp7eZ9LWRRj5gg1TDrqRpJ6CoxIRUL +-1/wFH6WEqC8EgHj90lcBAzxdyWZZKoAzXpNxCdeDq3eW5Fpe17jzxdUFF9Be6816 +-LbxTlrMisLp0u39v1GnE/vd2nemKUWY7uNSRRrtTi8mjAmXcnogxBmAyN7wjqVHt +-KKBYkyTRPCh8K6R+t/dqbZsv1k8fdS1/csXoiU2nJ86pdbSHOQ7aZMWXTZmAE5wb +-G4Oe9X61Hg5xgTDO/nEd8q2Sl6mMSx9L5IjdTm+WVRkCgYEA/CaXCzlUPUtVbkih +-bkDCQbYVarrRo90PskL2mgUQDUBgFOzSQXrJ6qEEYXy5PdOBhiaK3385wSXBX+nF +-7LOANzrgN9k+6Vt3fe20HrYltoc5e0lxvk4rdNSyrpe+E5bz8LtASlMBj2o6W6Md +-NkCAEKRp7wC2gb3MPeWhCpiJrLsCgYEA6vfthWHjL+yr6hFro/IsHnQdYSn4QPgn +-+WrOg6gGwhS5ZqJLK5jB95RFvgGhNBxh8nMCP0VnJYmM1pQtzR/YE7PU7SlRyAd/ +-DVkyO8NRQTzA6z/mPoeGx4dtTwaye10c7KZxmZCXq1tB4D6gTDJUQF5gt8tbx4C8 +-1mul1xQ0aYUCgYAFovMzbAenCx0QxwzcwxPUljZqWVzAVfu412hdzwkp0quTLCwT +-DKSg2xKW/0vAxw6ZKhlmn5hx6d8lvrsO7IBMO8OxW+jdHI9SQFMLcLTtHJ67U8v4 +-HhU4mlyYLIoyM+imE/l+79YUF6LQU5gek1iJhrNbhV+PDOgY5h4wd3J0awKBgBfF +-OSwzOO6SPNoTJRaS20/BY29+9XRtJm4fFgFPsE9WFWOCq6Qfcg//2gZc19gTvvzu +-EZ4hAUxU3AChQPjtbcigerv7YCCiUYIiMejF26SD5uhlsH9G6qWo17AU911vkAuI +-0xk7/XwCYWm0LDdJKCjS42n0krZeGbx/a2mUy7CZAoGAGXq2r3INg0xiZa8mSeJB +-MeZswgGKxN7MHlKKcpELEWg97ev4NvTq4T+PEl+1miRtlyzcFgMXKe3oBU0Ru7Qu +-O2u3kfLTOPGHmo+KpFNJHE8g+PwoOheNis2JZkd3T9fX7JRRYCiBeW4nMYzP2yGS +-nlaUqPewhh5/1fRCmF36TyU= ++MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC61rIy3hBTH12v ++2tQ/ZLMiN/1OFqPw1p5u0+5H7BW0sw2Av/whlosdQBZtiTUDikWMxm4rZmcPHBnP ++YtXmCEio3xDaTEd5fAKXVPmo6VlQM82gcv3h5146Q1z/DGme9sKGcQel67XHYfnp ++/j8mVSz0BHzAvc0riJxpTc48Hq0uGJaqoOtyK5WZRxaQtVnt8XjMiwEzQMTpsD/s ++iQQTXJsiAcwlz0DBQPoEoLm399hzkX+4fumCIB/pnIklKLX6b7dKiChoWdUwUvnk ++W6a0+OTtLwPYUGGaU4YfraoNX/hStSfdBYIlE6DQEDzdwHAVJGOJIg7wWpr6sHVW ++Bqp/sPebAgMBAAECggEANW/iV5oboSp/aSR1QAxVD5xj3kmrad54QcprhDaJnrz3 ++R7OhMRoVf7AsufdcKj8J1VGLgO4w26l12FK0Sq5j2aiy8TyP1LcbJp0vKphS6xVl ++4lYBNvMtiAxsNKYgL070I+9/+HyJ6RSkncAR36zMxp3h8F5Yp/LSiWuvaJJ9hYkU ++sH+svdnh3nvgNAnKHMEMRs+++CFZ5QL1Iv4WANTRyO3+ylDrwmWlNjzcwae1/789 ++EaP5RX08E/yGJFwCFbpK04mZjwQZV3PS5V+TPCnVXLyAGFhBY8a5Faya9uNLItJ/ ++oRJhqqMiUgUk3E6dpbSkM6SL0YHMv6jQuGXISDblgQKBgQD4ZBONARsaedr5jKPH ++HOCBSq2D2ROiv43DDl9a8LLjEHTwt5vjB7jYI5G1vGXXNOSYxNtBvtl6Jhzralmx ++TA282lV0Kr2xidZjpsbJb0Nwvw/bRS5GzwLv3eHt675zl9R2GJpqxnTxT2qyxHql ++RUJrCOwi6dmRMnCfBR72OccNYwKBgQDAj+qbVYybIaNq660T+9qKW1mkJE5SQxbg ++buPwK5V4Sl6ItxUEhZ0BtAO4gM76Qm2S6uJU7CkEJidNvPbrhv0fSgFbgwXmTlnr ++OtDzLs3MX7N4RQGhWXZvMMhWzFJGsfNYO7ReUjUuLPWkvR4ag5Y58dUfn5y0icj0 ++kKAE73++aQKBgEzYESBXTj5DopX/h4+LBH2bT9DxcFyyLDZDFQb6Xi1XIwZxlz2G ++Xw4m+uYhcdRBXdNRW4+cboWWku3VygfKwplBZpx4uJTbUsMjjm41CMUxpsMsROPN ++GViB6WqEuzfhqe4bMHKGERmyewzxMgw9QA4DBaLLe+6qjyLzH6AHQeiHAoGANvWc ++f0M2g1xhePXVC1wZrt2NwzR9iisNz3a25eh6m7+WJa0jeYvtGPxZB4L0ECd/gKw7 ++dwOEXWPKWfyx+N0pR5Hmu0i1GVuJfILn+lCEem1iGtSPN48CJ5Ajzeo5HWZSzv8T ++ZsxN02UPozo66lRePyGPs5vprPmaensAwQfeTOkCgYBaaJ6LC9slX4vEw28fO3xU ++4UbRKik4A3EbUlklXBXPY1eCDzI9r5IuiXD3aM/V3qeO7PGBUwW75Glu+fmmKXP8 ++5R8beykoudKtiRTLIaEZHRfTNnaGmThDI0RrjkmKHt7AC5MBDTwajVL89T1H6Y0H ++tlo5AYv9klQDtpadOUZbhg== + -----END PRIVATE KEY----- diff -Nru tomcat7-7.0.68/debian/patches/CVE-2016-0762.patch tomcat7-7.0.68/debian/patches/CVE-2016-0762.patch --- tomcat7-7.0.68/debian/patches/CVE-2016-0762.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/CVE-2016-0762.patch 2018-10-19 14:31:11.000000000 +0000 @@ -0,0 +1,196 @@ +From: Markus Koschany +Date: Fri, 4 Nov 2016 00:05:38 +0100 +Subject: CVE-2016-0762 + +Origin: https://svn.apache.org/r1758502 +--- + .../catalina/realm/DataSourceRealm.java | 33 +++++++++++---- + java/org/apache/catalina/realm/JDBCRealm.java | 11 +++++ + .../apache/catalina/realm/MemoryRealm.java | 23 ++++++++--- + java/org/apache/catalina/realm/RealmBase.java | 41 +++++++++++++++---- + 4 files changed, 88 insertions(+), 20 deletions(-) + +diff --git a/java/org/apache/catalina/realm/DataSourceRealm.java b/java/org/apache/catalina/realm/DataSourceRealm.java +index 8fe0e34..b277739 100644 +--- a/java/org/apache/catalina/realm/DataSourceRealm.java ++++ b/java/org/apache/catalina/realm/DataSourceRealm.java +@@ -318,22 +318,41 @@ public class DataSourceRealm + String username, + String credentials) { + ++ // No user or no credentials ++ // Can't possibly authenticate, don't bother the database then ++ if (username == null || credentials == null) { ++ if (containerLog.isTraceEnabled()) ++ containerLog.trace(sm.getString("dataSourceRealm.authenticateFailure", ++ username)); ++ return null; ++ } ++ + String dbCredentials = getPassword(dbConnection, username); + ++ if (dbCredentials == null) { ++ // User was not found in the database. ++ // Waste a bit of time as not to reveal that the user does not exist. ++ compareCredentials(credentials, getClass().getName()); ++ ++ if (containerLog.isTraceEnabled()) ++ containerLog.trace(sm.getString("dataSourceRealm.authenticateFailure", ++ username)); ++ return null; ++ } ++ + // Validate the user's credentials + boolean validated = compareCredentials(credentials, dbCredentials); + + if (validated) { + if (containerLog.isTraceEnabled()) +- containerLog.trace( +- sm.getString("dataSourceRealm.authenticateSuccess", +- username)); ++ containerLog.trace(sm.getString("dataSourceRealm.authenticateSuccess", ++ username)); + } else { + if (containerLog.isTraceEnabled()) +- containerLog.trace( +- sm.getString("dataSourceRealm.authenticateFailure", +- username)); +- return (null); ++ containerLog.trace(sm.getString("dataSourceRealm.authenticateFailure", ++ username)); ++ ++ return null; + } + + ArrayList list = getRoles(dbConnection, username); +diff --git a/java/org/apache/catalina/realm/JDBCRealm.java b/java/org/apache/catalina/realm/JDBCRealm.java +index f8139ea..c20798a 100644 +--- a/java/org/apache/catalina/realm/JDBCRealm.java ++++ b/java/org/apache/catalina/realm/JDBCRealm.java +@@ -405,6 +405,17 @@ public class JDBCRealm + // Look up the user's credentials + String dbCredentials = getPassword(username); + ++ if (dbCredentials == null) { ++ // User was not found in the database. ++ // Waste a bit of time as not to reveal that the user does not exist. ++ compareCredentials(credentials, getClass().getName()); ++ ++ if (containerLog.isTraceEnabled()) ++ containerLog.trace(sm.getString("jdbcRealm.authenticateFailure", ++ username)); ++ return null; ++ } ++ + // Validate the user's credentials + boolean validated = compareCredentials(credentials, dbCredentials); + +diff --git a/java/org/apache/catalina/realm/MemoryRealm.java b/java/org/apache/catalina/realm/MemoryRealm.java +index 0baf646..6c13b23 100644 +--- a/java/org/apache/catalina/realm/MemoryRealm.java ++++ b/java/org/apache/catalina/realm/MemoryRealm.java +@@ -139,15 +139,28 @@ public class MemoryRealm extends RealmBase { + @Override + public Principal authenticate(String username, String credentials) { + ++ // No user or no credentials ++ // Can't possibly authenticate, don't bother the database then ++ if (username == null || credentials == null) { ++ if (log.isDebugEnabled()) ++ log.debug(sm.getString("memoryRealm.authenticateFailure", username)); ++ return null; ++ } ++ + GenericPrincipal principal = principals.get(username); + +- boolean validated; +- if (principal == null) { +- validated = false; +- } else { +- validated = compareCredentials(credentials, principal.getPassword()); ++ if (principal == null || principal.getPassword() == null) { ++ // User was not found in the database or the password was null ++ // Waste a bit of time as not to reveal that the user does not exist. ++ compareCredentials(credentials, getClass().getName()); ++ ++ if (log.isDebugEnabled()) ++ log.debug(sm.getString("memoryRealm.authenticateFailure", username)); ++ return null; + } + ++ boolean validated = compareCredentials(credentials, principal.getPassword()); ++ + if (validated) { + if (log.isDebugEnabled()) + log.debug(sm.getString("memoryRealm.authenticateSuccess", username)); +diff --git a/java/org/apache/catalina/realm/RealmBase.java b/java/org/apache/catalina/realm/RealmBase.java +index 04c563a..5f2f0e0 100644 +--- a/java/org/apache/catalina/realm/RealmBase.java ++++ b/java/org/apache/catalina/realm/RealmBase.java +@@ -59,6 +59,8 @@ import org.ietf.jgss.GSSContext; + import org.ietf.jgss.GSSCredential; + import org.ietf.jgss.GSSException; + import org.ietf.jgss.GSSName; ++import java.util.Arrays; ++import org.apache.tomcat.util.codec.binary.Base64; + + /** + * Simple implementation of Realm that reads an XML file to configure +@@ -377,23 +379,46 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm { + */ + @Override + public Principal authenticate(String username, String credentials) { ++ // No user or no credentials ++ // Can't possibly authenticate, don't bother doing anything. ++ if(username == null || credentials == null) { ++ if (containerLog.isTraceEnabled()) { ++ containerLog.trace(sm.getString("realmBase.authenticateFailure", ++ username)); ++ } ++ return null; ++ } + ++ // Look up the user's credentials + String serverCredentials = getPassword(username); + ++ if (serverCredentials == null) { ++ // User was not found ++ // Waste a bit of time as not to reveal that the user does not exist. ++ compareCredentials(credentials, getClass().getName()); ++ ++ if (containerLog.isTraceEnabled()) { ++ containerLog.trace(sm.getString("realmBase.authenticateFailure", ++ username)); ++ } ++ return null; ++ } ++ + boolean validated = compareCredentials(credentials, serverCredentials); +- if (!validated) { ++ ++ if (validated) { + if (containerLog.isTraceEnabled()) { +- containerLog.trace(sm.getString("realmBase.authenticateFailure", ++ containerLog.trace(sm.getString("realmBase.authenticateSuccess", + username)); + } ++ return getPrincipal(username); ++ } else { ++ if (containerLog.isTraceEnabled()) { ++ containerLog.trace(sm.getString("realmBase.authenticateFailure", ++ username)); ++ } + return null; + } +- if (containerLog.isTraceEnabled()) { +- containerLog.trace(sm.getString("realmBase.authenticateSuccess", +- username)); +- } +- +- return getPrincipal(username); + } + + +-- +2.17.1 + diff -Nru tomcat7-7.0.68/debian/patches/CVE-2016-5018-part2.patch tomcat7-7.0.68/debian/patches/CVE-2016-5018-part2.patch --- tomcat7-7.0.68/debian/patches/CVE-2016-5018-part2.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/CVE-2016-5018-part2.patch 2018-10-18 15:47:10.000000000 +0000 @@ -0,0 +1,36 @@ +From: Markus Koschany +Date: Mon, 5 Dec 2016 21:38:15 +0100 +Subject: CVE-2016-5018 part2 + +--- + java/org/apache/jasper/compiler/JspRuntimeContext.java | 2 -- + java/org/apache/jasper/security/SecurityClassLoad.java | 3 --- + 2 files changed, 5 deletions(-) + +diff --git a/java/org/apache/jasper/compiler/JspRuntimeContext.java b/java/org/apache/jasper/compiler/JspRuntimeContext.java +index 893541a..7468192 100644 +--- a/java/org/apache/jasper/compiler/JspRuntimeContext.java ++++ b/java/org/apache/jasper/compiler/JspRuntimeContext.java +@@ -91,8 +91,6 @@ public final class JspRuntimeContext { + factory.getClass().getClassLoader().loadClass( basePackage + + "runtime.JspRuntimeLibrary"); + factory.getClass().getClassLoader().loadClass( basePackage + +- "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper"); +- factory.getClass().getClassLoader().loadClass( basePackage + + "runtime.ServletResponseWrapperInclude"); + factory.getClass().getClassLoader().loadClass( basePackage + + "servlet.JspServletWrapper"); +diff --git a/java/org/apache/jasper/security/SecurityClassLoad.java b/java/org/apache/jasper/security/SecurityClassLoad.java +index a066dfb..a96d7ba 100644 +--- a/java/org/apache/jasper/security/SecurityClassLoad.java ++++ b/java/org/apache/jasper/security/SecurityClassLoad.java +@@ -47,9 +47,6 @@ public final class SecurityClassLoad { + loader.loadClass( basePackage + + "runtime.JspRuntimeLibrary"); + loader.loadClass( basePackage + +- "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper"); +- +- loader.loadClass( basePackage + + "runtime.ServletResponseWrapperInclude"); + loader.loadClass( basePackage + + "runtime.TagHandlerPool"); diff -Nru tomcat7-7.0.68/debian/patches/CVE-2016-5018.patch tomcat7-7.0.68/debian/patches/CVE-2016-5018.patch --- tomcat7-7.0.68/debian/patches/CVE-2016-5018.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/CVE-2016-5018.patch 2018-10-18 15:47:00.000000000 +0000 @@ -0,0 +1,107 @@ +From: Markus Koschany +Date: Thu, 3 Nov 2016 16:37:46 +0100 +Subject: CVE-2016-5018 + +Origin: http://svn.apache.org/r1754902 +--- + .../apache/jasper/runtime/JspRuntimeLibrary.java | 59 +--------------------- + 1 file changed, 1 insertion(+), 58 deletions(-) + +diff --git a/java/org/apache/jasper/runtime/JspRuntimeLibrary.java b/java/org/apache/jasper/runtime/JspRuntimeLibrary.java +index 9fb6e55..73ea608 100644 +--- a/java/org/apache/jasper/runtime/JspRuntimeLibrary.java ++++ b/java/org/apache/jasper/runtime/JspRuntimeLibrary.java +@@ -14,7 +14,6 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +- + package org.apache.jasper.runtime; + + import java.beans.PropertyEditor; +@@ -23,9 +22,6 @@ import java.io.ByteArrayOutputStream; + import java.io.IOException; + import java.io.OutputStreamWriter; + import java.lang.reflect.Method; +-import java.security.AccessController; +-import java.security.PrivilegedActionException; +-import java.security.PrivilegedExceptionAction; + import java.util.Enumeration; + + import javax.servlet.RequestDispatcher; +@@ -37,7 +33,6 @@ import javax.servlet.jsp.JspWriter; + import javax.servlet.jsp.PageContext; + import javax.servlet.jsp.tagext.BodyContent; + +-import org.apache.jasper.Constants; + import org.apache.jasper.JasperException; + import org.apache.jasper.compiler.Localizer; + import org.apache.jasper.util.ExceptionUtils; +@@ -56,36 +51,6 @@ import org.apache.jasper.util.ExceptionUtils; + */ + public class JspRuntimeLibrary { + +- protected static class PrivilegedIntrospectHelper +- implements PrivilegedExceptionAction { +- +- private Object bean; +- private String prop; +- private String value; +- private ServletRequest request; +- private String param; +- private boolean ignoreMethodNF; +- +- PrivilegedIntrospectHelper(Object bean, String prop, +- String value, ServletRequest request, +- String param, boolean ignoreMethodNF) +- { +- this.bean = bean; +- this.prop = prop; +- this.value = value; +- this.request = request; +- this.param = param; +- this.ignoreMethodNF = ignoreMethodNF; +- } +- +- @Override +- public Void run() throws JasperException { +- internalIntrospecthelper( +- bean,prop,value,request,param,ignoreMethodNF); +- return null; +- } +- } +- + /** + * Returns the value of the javax.servlet.error.exception request + * attribute value, if present, otherwise the value of the +@@ -290,29 +255,7 @@ public class JspRuntimeLibrary { + public static void introspecthelper(Object bean, String prop, + String value, ServletRequest request, + String param, boolean ignoreMethodNF) +- throws JasperException +- { +- if( Constants.IS_SECURITY_ENABLED ) { +- try { +- PrivilegedIntrospectHelper dp = +- new PrivilegedIntrospectHelper( +- bean,prop,value,request,param,ignoreMethodNF); +- AccessController.doPrivileged(dp); +- } catch( PrivilegedActionException pe) { +- Exception e = pe.getException(); +- throw (JasperException)e; +- } +- } else { +- internalIntrospecthelper( +- bean,prop,value,request,param,ignoreMethodNF); +- } +- } +- +- private static void internalIntrospecthelper(Object bean, String prop, +- String value, ServletRequest request, +- String param, boolean ignoreMethodNF) +- throws JasperException +- { ++ throws JasperException { + Method method = null; + Class type = null; + Class propertyEditorClass = null; diff -Nru tomcat7-7.0.68/debian/patches/CVE-2016-6794.patch tomcat7-7.0.68/debian/patches/CVE-2016-6794.patch --- tomcat7-7.0.68/debian/patches/CVE-2016-6794.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/CVE-2016-6794.patch 2018-10-18 16:00:27.000000000 +0000 @@ -0,0 +1,153 @@ +From: Markus Koschany +Date: Thu, 3 Nov 2016 16:36:01 +0100 +Subject: CVE-2016-6794 + +Origin: http://svn.apache.org/r1754728 +--- + .../loader/WebappClassLoaderBase.java | 24 ++++++++++- + .../apache/tomcat/util/digester/Digester.java | 10 +++++ + .../tomcat/util/security/PermissionCheck.java | 43 +++++++++++++++++++ + 3 files changed, 76 insertions(+), 1 deletion(-) + create mode 100644 java/org/apache/tomcat/util/security/PermissionCheck.java + +diff --git a/java/org/apache/catalina/loader/WebappClassLoaderBase.java b/java/org/apache/catalina/loader/WebappClassLoaderBase.java +index c87fb53..3bb41e2 100644 +--- a/java/org/apache/catalina/loader/WebappClassLoaderBase.java ++++ b/java/org/apache/catalina/loader/WebappClassLoaderBase.java +@@ -85,6 +85,7 @@ import org.apache.tomcat.util.IntrospectionUtils; + import org.apache.tomcat.util.compat.JreCompat; + import org.apache.tomcat.util.compat.JreVendor; + import org.apache.tomcat.util.res.StringManager; ++import org.apache.tomcat.util.security.PermissionCheck; + + /** + * Specialized web application class loader. +@@ -133,7 +134,7 @@ import org.apache.tomcat.util.res.StringManager; + * @author Craig R. McClanahan + */ + public abstract class WebappClassLoaderBase extends URLClassLoader +- implements Lifecycle, InstrumentableClassLoader { ++ implements Lifecycle, InstrumentableClassLoader, PermissionCheck { + + private static final org.apache.juli.logging.Log log = + org.apache.juli.logging.LogFactory.getLog(WebappClassLoaderBase.class); +@@ -1902,6 +1903,27 @@ public abstract class WebappClassLoaderBase extends URLClassLoader + } + + ++ @Override ++ public boolean check(Permission permission) { ++ if (!Globals.IS_SECURITY_ENABLED) { ++ return true; ++ } ++ Policy currentPolicy = Policy.getPolicy(); ++ if (currentPolicy != null) { ++ ResourceEntry entry = findResourceInternal("/", "/", false); ++ if (entry != null) { ++ CodeSource cs = new CodeSource( ++ entry.codeBase, (java.security.cert.Certificate[]) null); ++ PermissionCollection pc = currentPolicy.getPermissions(cs); ++ if (pc.implies(permission)) { ++ return true; ++ } ++ } ++ } ++ return false; ++ } ++ ++ + /** + * Returns the search path of URLs for loading classes and resources. + * This includes the original list of URLs specified to the constructor, +diff --git a/java/org/apache/tomcat/util/digester/Digester.java b/java/org/apache/tomcat/util/digester/Digester.java +index dca07b5..087227f 100644 +--- a/java/org/apache/tomcat/util/digester/Digester.java ++++ b/java/org/apache/tomcat/util/digester/Digester.java +@@ -26,11 +26,13 @@ import java.io.Reader; + import java.lang.reflect.InvocationTargetException; + import java.net.URI; + import java.net.URISyntaxException; ++import java.security.Permission; + import java.util.EmptyStackException; + import java.util.HashMap; + import java.util.Iterator; + import java.util.List; + import java.util.Map; ++import java.util.PropertyPermission; + + import javax.xml.parsers.ParserConfigurationException; + import javax.xml.parsers.SAXParser; +@@ -40,6 +42,7 @@ import org.apache.juli.logging.Log; + import org.apache.juli.logging.LogFactory; + import org.apache.tomcat.util.ExceptionUtils; + import org.apache.tomcat.util.IntrospectionUtils; ++import org.apache.tomcat.util.security.PermissionCheck; + import org.xml.sax.Attributes; + import org.xml.sax.EntityResolver; + import org.xml.sax.ErrorHandler; +@@ -81,6 +84,13 @@ public class Digester extends DefaultHandler2 { + implements IntrospectionUtils.PropertySource { + @Override + public String getProperty( String key ) { ++ ClassLoader cl = Thread.currentThread().getContextClassLoader(); ++ if (cl instanceof PermissionCheck) { ++ Permission p = new PropertyPermission(key, "read"); ++ if (!((PermissionCheck) cl).check(p)) { ++ return null; ++ } ++ } + return System.getProperty(key); + } + } +diff --git a/java/org/apache/tomcat/util/security/PermissionCheck.java b/java/org/apache/tomcat/util/security/PermissionCheck.java +new file mode 100644 +index 0000000..ba2bdd3 +--- /dev/null ++++ b/java/org/apache/tomcat/util/security/PermissionCheck.java +@@ -0,0 +1,43 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.tomcat.util.security; ++ ++import java.security.Permission; ++ ++/** ++ * This interface is implemented by components to enable privileged code to ++ * check whether the component has a given permission. ++ * This is typically used when a privileged component (e.g. the container) is ++ * performing an action on behalf of an untrusted component (e.g. a web ++ * application) without the current thread having passed through a code source ++ * provided by the untrusted component. Because the current thread has not ++ * passed through a code source provided by the untrusted component the ++ * SecurityManager assumes the code is trusted so the standard checking ++ * mechanisms can't be used. ++ */ ++public interface PermissionCheck { ++ ++ /** ++ * Does this component have the given permission? ++ * ++ * @param permission The permission to test ++ * ++ * @return {@code false} if a SecurityManager is enabled and the component ++ * does not have the given permission, otherwise {@code false} ++ */ ++ boolean check(Permission permission); ++} +-- +2.17.1 + diff -Nru tomcat7-7.0.68/debian/patches/CVE-2016-6796.patch tomcat7-7.0.68/debian/patches/CVE-2016-6796.patch --- tomcat7-7.0.68/debian/patches/CVE-2016-6796.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/CVE-2016-6796.patch 2018-10-18 16:19:11.000000000 +0000 @@ -0,0 +1,111 @@ +From: Markus Koschany +Date: Thu, 3 Nov 2016 16:27:56 +0100 +Subject: CVE-2016-6796 + +Origin: http://svn.apache.org/r1758495 +--- + conf/web.xml | 4 ++++ + java/org/apache/jasper/EmbeddedServletOptions.java | 4 ++++ + java/org/apache/jasper/resources/LocalStrings.properties | 1 + + java/org/apache/jasper/servlet/JspServlet.java | 9 +++++++-- + webapps/docs/jasper-howto.xml | 4 ++-- + 5 files changed, 18 insertions(+), 4 deletions(-) + +diff --git a/conf/web.xml b/conf/web.xml +index 2482d93..9126d54 100644 +--- a/conf/web.xml ++++ b/conf/web.xml +@@ -158,6 +158,8 @@ + + + ++ ++ + + + +@@ -219,6 +221,8 @@ + + + ++ ++ + + + +diff --git a/java/org/apache/jasper/EmbeddedServletOptions.java b/java/org/apache/jasper/EmbeddedServletOptions.java +index 6c5ddbd..05c6fe6 100644 +--- a/java/org/apache/jasper/EmbeddedServletOptions.java ++++ b/java/org/apache/jasper/EmbeddedServletOptions.java +@@ -640,6 +640,10 @@ public final class EmbeddedServletOptions implements Options { + * scratchdir + */ + String dir = config.getInitParameter("scratchdir"); ++ if (dir != null && Constants.IS_SECURITY_ENABLED) { ++ log.info(Localizer.getMessage("jsp.info.ignoreSetting", "scratchdir", dir)); ++ dir = null; ++ } + if (dir != null) { + scratchDir = new File(dir); + } else { +diff --git a/java/org/apache/jasper/resources/LocalStrings.properties b/java/org/apache/jasper/resources/LocalStrings.properties +index 4b67a9c..5cd0657 100644 +--- a/java/org/apache/jasper/resources/LocalStrings.properties ++++ b/java/org/apache/jasper/resources/LocalStrings.properties +@@ -455,6 +455,7 @@ jsp.error.unbalanced.endtag=The end tag \"</{0}\" is unbalanced + jsp.error.invalid.bean=The value for the useBean class attribute {0} is invalid. + jsp.error.prefix.use_before_dcl=The prefix {0} specified in this tag directive has been previously used by an action in file {1} line {2}. + jsp.error.lastModified=Unable to determine last modified date for file [{0}] ++jsp.info.ignoreSetting=Ignored setting for [{0}] of [{1}] because a SecurityManager was enabled + + jsp.exception=An exception occurred processing JSP page {0} at line {1} + +diff --git a/java/org/apache/jasper/servlet/JspServlet.java b/java/org/apache/jasper/servlet/JspServlet.java +index 289b9e9..4e253e3 100644 +--- a/java/org/apache/jasper/servlet/JspServlet.java ++++ b/java/org/apache/jasper/servlet/JspServlet.java +@@ -71,8 +71,8 @@ public class JspServlet extends HttpServlet implements PeriodicEventListener { + private ServletConfig config; + private transient Options options; + private transient JspRuntimeContext rctxt; +- //jspFile for a jsp configured explicitly as a servlet, in environments where this configuration is +- //translated into an init-param for this servlet. ++ // jspFile for a jsp configured explicitly as a servlet, in environments where this ++ // configuration is translated into an init-param for this servlet. + private String jspFile; + + +@@ -90,6 +90,11 @@ public class JspServlet extends HttpServlet implements PeriodicEventListener { + // Check for a custom Options implementation + String engineOptionsName = + config.getInitParameter("engineOptionsClass"); ++ if (Constants.IS_SECURITY_ENABLED && engineOptionsName != null) { ++ log.info(Localizer.getMessage( ++ "jsp.info.ignoreSetting", "engineOptionsClass", engineOptionsName)); ++ engineOptionsName = null; ++ } + if (engineOptionsName != null) { + // Instantiate the indicated Options implementation + try { +diff --git a/webapps/docs/jasper-howto.xml b/webapps/docs/jasper-howto.xml +index 826c051..fb9b28e 100644 +--- a/webapps/docs/jasper-howto.xml ++++ b/webapps/docs/jasper-howto.xml +@@ -127,7 +127,7 @@ default true. + +
  • engineOptionsClass - Allows specifying the Options class + used to configure Jasper. If not present, the default EmbeddedServletOptions +-will be used. ++will be used. This option is ignored if running under a SecurityManager. +
  • + +
  • errorOnUseBeanInvalidClassAttribute - Should Jasper issue +@@ -180,7 +180,7 @@ may be expensive and could lead to excessive resource usage.
  • + +
  • scratchdir - What scratch directory should we use when + compiling JSP pages? Default is the work directory for the current web +-application.
  • ++application. This option is ignored if running under a SecurityManager. + +
  • suppressSmap - Should the generation of SMAP info for JSR45 + debugging be suppressed? true or false, default diff -Nru tomcat7-7.0.68/debian/patches/CVE-2016-6797.patch tomcat7-7.0.68/debian/patches/CVE-2016-6797.patch --- tomcat7-7.0.68/debian/patches/CVE-2016-6797.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/CVE-2016-6797.patch 2018-10-18 16:41:43.000000000 +0000 @@ -0,0 +1,265 @@ +From: Markus Koschany +Date: Sun, 18 Dec 2016 15:08:38 +0100 +Subject: CVE-2016-6797 part2 + +Debian-Bug: https://bugs.debian.org/845425 +--- + .../catalina/core/NamingContextListener.java | 19 ++++ + .../naming/factory/ResourceLinkFactory.java | 66 +++++++++++++- + test/org/apache/naming/TestNamingContext.java | 87 +++++++++++++++++++ + 3 files changed, 171 insertions(+), 1 deletion(-) + create mode 100644 test/org/apache/naming/TestNamingContext.java + +diff --git a/java/org/apache/catalina/core/NamingContextListener.java b/java/org/apache/catalina/core/NamingContextListener.java +index 707a183..79789d0 100644 +--- a/java/org/apache/catalina/core/NamingContextListener.java ++++ b/java/org/apache/catalina/core/NamingContextListener.java +@@ -41,6 +41,7 @@ import org.apache.catalina.Container; + import org.apache.catalina.ContainerEvent; + import org.apache.catalina.ContainerListener; + import org.apache.catalina.Context; ++import org.apache.catalina.Engine; + import org.apache.catalina.Host; + import org.apache.catalina.Lifecycle; + import org.apache.catalina.LifecycleEvent; +@@ -68,6 +69,7 @@ import org.apache.naming.ResourceLinkRef; + import org.apache.naming.ResourceRef; + import org.apache.naming.ServiceRef; + import org.apache.naming.TransactionRef; ++import org.apache.naming.factory.ResourceLinkFactory; + import org.apache.tomcat.util.modeler.Registry; + import org.apache.tomcat.util.res.StringManager; + +@@ -344,6 +346,11 @@ public class NamingContextListener + registry.unregisterComponent(objectName); + } + } ++ ++ javax.naming.Context global = getGlobalNamingContext(); ++ if (global != null) { ++ ResourceLinkFactory.deregisterGlobalResourceAccess(global); ++ } + } finally { + objectNames.clear(); + +@@ -1167,6 +1174,17 @@ public class NamingContextListener + logger.error(sm.getString("naming.bindFailed", e)); + } + ++ ResourceLinkFactory.registerGlobalResourceAccess( ++ getGlobalNamingContext(), resourceLink.getName(), resourceLink.getGlobal()); ++ } ++ ++ ++ private javax.naming.Context getGlobalNamingContext() { ++ if (container instanceof Context) { ++ Engine e = (Engine) ((Context) container).getParent().getParent(); ++ return e.getService().getServer().getGlobalNamingContext(); ++ } ++ return null; + } + + +@@ -1270,6 +1288,7 @@ public class NamingContextListener + logger.error(sm.getString("naming.unbindFailed", e)); + } + ++ ResourceLinkFactory.deregisterGlobalResourceAccess(getGlobalNamingContext(), name); + } + + +diff --git a/java/org/apache/naming/factory/ResourceLinkFactory.java b/java/org/apache/naming/factory/ResourceLinkFactory.java +index 8606a8f..c5efa5d 100644 +--- a/java/org/apache/naming/factory/ResourceLinkFactory.java ++++ b/java/org/apache/naming/factory/ResourceLinkFactory.java +@@ -18,7 +18,10 @@ + + package org.apache.naming.factory; + ++import java.util.HashMap; + import java.util.Hashtable; ++import java.util.Map; ++import java.util.concurrent.ConcurrentHashMap; + + import javax.naming.Context; + import javax.naming.Name; +@@ -49,7 +52,9 @@ public class ResourceLinkFactory + * Global naming context. + */ + private static Context globalContext = null; +- ++ ++ private static Map> globalResourceRegistrations = ++ new ConcurrentHashMap>(); + + // --------------------------------------------------------- Public Methods + +@@ -69,6 +74,59 @@ public class ResourceLinkFactory + } + + ++ public static void registerGlobalResourceAccess(Context globalContext, String localName, ++ String globalName) { ++ validateGlobalContext(globalContext); ++ ClassLoader cl = Thread.currentThread().getContextClassLoader(); ++ Map registrations = globalResourceRegistrations.get(cl); ++ if (registrations == null) { ++ // Web application initialization is single threaded so this is ++ // safe. ++ registrations = new HashMap(); ++ globalResourceRegistrations.put(cl, registrations); ++ } ++ registrations.put(localName, globalName); ++ } ++ ++ ++ public static void deregisterGlobalResourceAccess(Context globalContext, String localName) { ++ validateGlobalContext(globalContext); ++ ClassLoader cl = Thread.currentThread().getContextClassLoader(); ++ Map registrations = globalResourceRegistrations.get(cl); ++ if (registrations != null) { ++ registrations.remove(localName); ++ } ++ } ++ ++ ++ public static void deregisterGlobalResourceAccess(Context globalContext) { ++ validateGlobalContext(globalContext); ++ ClassLoader cl = Thread.currentThread().getContextClassLoader(); ++ globalResourceRegistrations.remove(cl); ++ } ++ ++ ++ private static void validateGlobalContext(Context globalContext) { ++ if (ResourceLinkFactory.globalContext != null && ++ ResourceLinkFactory.globalContext != globalContext) { ++ throw new SecurityException("Caller provided invalid global context"); ++ } ++ } ++ ++ ++ private static boolean validateGlobalResourceAccess(String globalName) { ++ ClassLoader cl = Thread.currentThread().getContextClassLoader(); ++ while (cl != null) { ++ Map registrations = globalResourceRegistrations.get(cl); ++ if (registrations != null && registrations.containsValue(globalName)) { ++ return true; ++ } ++ cl = cl.getParent(); ++ } ++ return false; ++ } ++ ++ + // -------------------------------------------------- ObjectFactory Methods + + +@@ -93,6 +151,12 @@ public class ResourceLinkFactory + RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME); + if (refAddr != null) { + globalName = refAddr.getContent().toString(); ++ // When running under a security manager confirm that the current ++ // web application has really been configured to access the specified ++ // global resource ++ if (!validateGlobalResourceAccess(globalName)) { ++ return null; ++ } + Object result = null; + result = globalContext.lookup(globalName); + // FIXME: Check type +diff --git a/test/org/apache/naming/TestNamingContext.java b/test/org/apache/naming/TestNamingContext.java +new file mode 100644 +index 0000000..f108893 +--- /dev/null ++++ b/test/org/apache/naming/TestNamingContext.java +@@ -0,0 +1,87 @@ ++package org.apache.naming; ++ ++import javax.naming.Context; ++import javax.naming.NamingException; ++ ++import org.apache.catalina.deploy.ContextEnvironment; ++import org.apache.catalina.deploy.ContextResourceLink; ++import org.apache.catalina.startup.Tomcat; ++import org.apache.catalina.startup.TomcatBaseTest; ++import org.apache.naming.factory.ResourceLinkFactory; ++import org.junit.Assert; ++import org.junit.Test; ++ ++public class TestNamingContext extends TomcatBaseTest { ++ ++ private static final String COMP_ENV = "comp/env"; ++ private static final String GLOBAL_NAME = "global"; ++ private static final String LOCAL_NAME = "local"; ++ private static final String DATA = "Cabbage"; ++ ++ ++ @Test ++ public void testGlobalNaming() throws Exception { ++ Tomcat tomcat = getTomcatInstance(); ++ tomcat.enableNaming(); ++ ++ org.apache.catalina.Context ctx = tomcat.addContext("", null); ++ ++ tomcat.start(); ++ ++ Context webappInitial = ContextBindings.getContext(ctx); ++ ++ // Nothing added at the moment so should be null ++ Object obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME); ++ Assert.assertNull(obj); ++ ++ ContextEnvironment ce = new ContextEnvironment(); ++ ce.setName(GLOBAL_NAME); ++ ce.setValue(DATA); ++ ce.setType(DATA.getClass().getName()); ++ ++ tomcat.getServer().getGlobalNamingResources().addEnvironment(ce); ++ ++ // No link so still should be null ++ obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME); ++ Assert.assertNull(obj); ++ ++ // Now add a resource link to the context ++ ContextResourceLink crl = new ContextResourceLink(); ++ crl.setGlobal(GLOBAL_NAME); ++ crl.setName(LOCAL_NAME); ++ crl.setType(DATA.getClass().getName()); ++ ctx.getNamingResources().addResourceLink(crl); ++ ++ // Link exists so should be OK now ++ obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME); ++ Assert.assertEquals(DATA, obj); ++ ++ // Try shortcut ++ ResourceLinkFactory factory = new ResourceLinkFactory(); ++ ResourceLinkRef rlr = new ResourceLinkRef(DATA.getClass().getName(), GLOBAL_NAME, null, null); ++ obj = factory.getObjectInstance(rlr, null, null, null); ++ Assert.assertEquals(DATA, obj); ++ ++ // Remove the link ++ ctx.getNamingResources().removeResourceLink(LOCAL_NAME); ++ ++ // No link so should be null ++ obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME); ++ Assert.assertNull(obj); ++ ++ // Shortcut should fail too ++ obj = factory.getObjectInstance(rlr, null, null, null); ++ Assert.assertNull(obj); ++ } ++ ++ ++ private Object doLookup(Context context, String name) { ++ Object result = null; ++ try { ++ result = context.lookup(name); ++ } catch (NamingException nnfe) { ++ // Ignore ++ } ++ return result; ++ } ++} +-- +2.17.1 + diff -Nru tomcat7-7.0.68/debian/patches/CVE-2016-6816.patch tomcat7-7.0.68/debian/patches/CVE-2016-6816.patch --- tomcat7-7.0.68/debian/patches/CVE-2016-6816.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/CVE-2016-6816.patch 2018-10-23 23:22:42.000000000 +0000 @@ -0,0 +1,931 @@ +From 5e54be0deb70359fa9486356fc2a362282dadf73 Mon Sep 17 00:00:00 2001 +From: Eduardo Barretto +Date: Thu, 18 Oct 2018 16:58:52 -0300 +Subject: [PATCH 2/5] CVE-2016-6816 + +--- + .../coyote/http11/AbstractInputBuffer.java | 54 +--------- + .../coyote/http11/InternalAprInputBuffer.java | 54 +++++----- + .../coyote/http11/InternalInputBuffer.java | 44 ++++----- + .../coyote/http11/InternalNioInputBuffer.java | 79 +++++++-------- + .../coyote/http11/LocalStrings.properties | 4 +- + .../tomcat/util/http/parser/HttpParser.java | 98 ++++++++++++++----- + 6 files changed, 170 insertions(+), 163 deletions(-) + +diff --git a/java/org/apache/coyote/http11/AbstractInputBuffer.java b/java/org/apache/coyote/http11/AbstractInputBuffer.java +index 7a56846..1efa906 100644 +--- a/java/org/apache/coyote/http11/AbstractInputBuffer.java ++++ b/java/org/apache/coyote/http11/AbstractInputBuffer.java +@@ -28,62 +28,10 @@ import org.apache.tomcat.util.res.StringManager; + + public abstract class AbstractInputBuffer implements InputBuffer{ + +- protected static final boolean[] HTTP_TOKEN_CHAR = new boolean[128]; +- + /** + * The string manager for this package. + */ +- protected static final StringManager sm = +- StringManager.getManager(Constants.Package); +- +- +- static { +- for (int i = 0; i < 128; i++) { +- if (i < 32) { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == 127) { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '(') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ')') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '<') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '>') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '@') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ',') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ';') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ':') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '\\') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '\"') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '/') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '[') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ']') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '?') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '=') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '{') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '}') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ' ') { +- HTTP_TOKEN_CHAR[i] = false; +- } else { +- HTTP_TOKEN_CHAR[i] = true; +- } +- } +- } ++ protected static final StringManager sm = StringManager.getManager(Constants.Package); + + + /** +diff --git a/java/org/apache/coyote/http11/InternalAprInputBuffer.java b/java/org/apache/coyote/http11/InternalAprInputBuffer.java +index d764207..84a3ecf 100644 +--- a/java/org/apache/coyote/http11/InternalAprInputBuffer.java ++++ b/java/org/apache/coyote/http11/InternalAprInputBuffer.java +@@ -30,6 +30,7 @@ import org.apache.tomcat.jni.Socket; + import org.apache.tomcat.jni.Status; + import org.apache.tomcat.util.buf.ByteChunk; + import org.apache.tomcat.util.buf.MessageBytes; ++import org.apache.tomcat.util.http.parser.HttpParser; + import org.apache.tomcat.util.net.AbstractEndpoint; + import org.apache.tomcat.util.net.SocketWrapper; + +@@ -70,7 +71,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + + parsingHeader = true; + swallowInput = true; +- ++ + } + + +@@ -93,7 +94,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + // --------------------------------------------------------- Public Methods + + /** +- * Recycle the input buffer. This should be called when closing the ++ * Recycle the input buffer. This should be called when closing the + * connection. + */ + @Override +@@ -105,14 +106,14 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + + + /** +- * Read the request line. This function is meant to be used during the +- * HTTP request header parsing. Do NOT attempt to read the request body ++ * Read the request line. This function is meant to be used during the ++ * HTTP request header parsing. Do NOT attempt to read the request body + * using it. + * + * @throws IOException If an exception occurs during the underlying socket + * read operations, or if the given buffer is not big enough to accommodate + * the whole line. +- * @return true if data is properly fed; false if no data is available ++ * @return true if data is properly fed; false if no data is available + * immediately and thread should be freed + */ + @Override +@@ -181,6 +182,8 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + request.method().setBytes(buf, start, pos - start); ++ } else if (!HttpParser.isToken(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidmethod")); + } + + pos++; +@@ -224,15 +227,16 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + end = pos; +- } else if ((buf[pos] == Constants.CR) ++ } else if ((buf[pos] == Constants.CR) + || (buf[pos] == Constants.LF)) { + // HTTP/0.9 style request + eol = true; + space = true; + end = pos; +- } else if ((buf[pos] == Constants.QUESTION) +- && (questionPos == -1)) { ++ } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) { + questionPos = pos; ++ } else if (HttpParser.isNotRequestTarget(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); + } + + pos++; +@@ -241,7 +245,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + + request.unparsedURI().setBytes(buf, start, end - start); + if (questionPos >= 0) { +- request.queryString().setBytes(buf, questionPos + 1, ++ request.queryString().setBytes(buf, questionPos + 1, + end - questionPos - 1); + request.requestURI().setBytes(buf, start, questionPos - start); + } else { +@@ -269,7 +273,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + + // + // Reading the protocol +- // Protocol is always US-ASCII ++ // Protocol is always "HTTP/" DIGIT "." DIGIT + // + + while (!eol) { +@@ -286,6 +290,8 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + if (end == 0) + end = pos; + eol = true; ++ } else if (!HttpParser.isHttpProtocol(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); + } + + pos++; +@@ -297,7 +303,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + } else { + request.protocol().setString(""); + } +- ++ + return true; + + } +@@ -326,7 +332,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + + /** + * Parse an HTTP header. +- * ++ * + * @return false after reading a blank line (which indicates that the + * HTTP header parsing is done + */ +@@ -384,7 +390,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + if (buf[pos] == Constants.COLON) { + colon = true; + headerValue = headers.addValue(buf, start, pos - start); +- } else if (!HTTP_TOKEN_CHAR[buf[pos]]) { ++ } else if (!HttpParser.isToken(buf[pos])) { + // If a non-token header is detected, skip the line and + // ignore the header + skipLine(start); +@@ -490,14 +496,14 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + + } + +- ++ + private void skipLine(int start) throws IOException { + boolean eol = false; + int lastRealByte = start; + if (pos - 1 > start) { + lastRealByte = pos - 1; + } +- ++ + while (!eol) { + + // Read new bytes if needed +@@ -521,8 +527,8 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + lastRealByte - start + 1, Charset.forName("ISO-8859-1")))); + } + } +- +- ++ ++ + // ---------------------------------------------------- InputBuffer Methods + + +@@ -530,7 +536,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + * Read some bytes. + */ + @Override +- public int doRead(ByteChunk chunk, Request req) ++ public int doRead(ByteChunk chunk, Request req) + throws IOException { + + if (lastActiveFilter == -1) +@@ -558,11 +564,11 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + // Ignore the block parameter and just call fill + return fill(); + } +- +- ++ ++ + /** + * Fill the internal buffer using data from the underlying input stream. +- * ++ * + * @return false if at end of stream + */ + protected boolean fill() +@@ -594,7 +600,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + } else { + + if (buf.length - end < 4500) { +- // In this case, the request header was really large, so we allocate a ++ // In this case, the request header was really large, so we allocate a + // brand new one; the old one will get GCed when subsequent requests + // clear all references + buf = new byte[buf.length]; +@@ -640,7 +646,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + * This class is an input buffer which will read its data from an input + * stream. + */ +- protected class SocketInputBuffer ++ protected class SocketInputBuffer + implements InputBuffer { + + +@@ -648,7 +654,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer { + * Read bytes into the specified chunk. + */ + @Override +- public int doRead(ByteChunk chunk, Request req ) ++ public int doRead(ByteChunk chunk, Request req ) + throws IOException { + + if (pos >= lastValid) { +diff --git a/java/org/apache/coyote/http11/InternalInputBuffer.java b/java/org/apache/coyote/http11/InternalInputBuffer.java +index e1501c9..b3ab417 100644 +--- a/java/org/apache/coyote/http11/InternalInputBuffer.java ++++ b/java/org/apache/coyote/http11/InternalInputBuffer.java +@@ -28,6 +28,7 @@ import org.apache.juli.logging.Log; + import org.apache.juli.logging.LogFactory; + import org.apache.tomcat.util.buf.ByteChunk; + import org.apache.tomcat.util.buf.MessageBytes; ++import org.apache.tomcat.util.http.parser.HttpParser; + import org.apache.tomcat.util.net.AbstractEndpoint; + import org.apache.tomcat.util.net.SocketWrapper; + +@@ -69,10 +70,10 @@ public class InternalInputBuffer extends AbstractInputBuffer { + + } + +- ++ + /** +- * Read the request line. This function is meant to be used during the +- * HTTP request header parsing. Do NOT attempt to read the request body ++ * Read the request line. This function is meant to be used during the ++ * HTTP request header parsing. Do NOT attempt to read the request body + * using it. + * + * @throws IOException If an exception occurs during the underlying socket +@@ -81,7 +82,7 @@ public class InternalInputBuffer extends AbstractInputBuffer { + */ + @Override + public boolean parseRequestLine(boolean useAvailableDataOnly) +- ++ + throws IOException { + + int start = 0; +@@ -126,15 +127,12 @@ public class InternalInputBuffer extends AbstractInputBuffer { + throw new EOFException(sm.getString("iib.eof.error")); + } + +- // Spec says no CR or LF in method name +- if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) { +- throw new IllegalArgumentException( +- sm.getString("iib.invalidmethod")); +- } + // Spec says single SP but it also says be tolerant of HT + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + request.method().setBytes(buf, start, pos - start); ++ } else if (!HttpParser.isToken(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidmethod")); + } + + pos++; +@@ -179,15 +177,16 @@ public class InternalInputBuffer extends AbstractInputBuffer { + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + end = pos; +- } else if ((buf[pos] == Constants.CR) ++ } else if ((buf[pos] == Constants.CR) + || (buf[pos] == Constants.LF)) { + // HTTP/0.9 style request + eol = true; + space = true; + end = pos; +- } else if ((buf[pos] == Constants.QUESTION) +- && (questionPos == -1)) { ++ } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) { + questionPos = pos; ++ } else if (HttpParser.isNotRequestTarget(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); + } + + pos++; +@@ -223,9 +222,8 @@ public class InternalInputBuffer extends AbstractInputBuffer { + + // + // Reading the protocol +- // Protocol is always US-ASCII ++ // Protocol is always "HTTP/" DIGIT "." DIGIT + // +- + while (!eol) { + + // Read new bytes if needed +@@ -240,6 +238,8 @@ public class InternalInputBuffer extends AbstractInputBuffer { + if (end == 0) + end = pos; + eol = true; ++ } else if (!HttpParser.isHttpProtocol(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); + } + + pos++; +@@ -251,7 +251,7 @@ public class InternalInputBuffer extends AbstractInputBuffer { + } else { + request.protocol().setString(""); + } +- ++ + return true; + + } +@@ -280,7 +280,7 @@ public class InternalInputBuffer extends AbstractInputBuffer { + + /** + * Parse an HTTP header. +- * ++ * + * @return false after reading a blank line (which indicates that the + * HTTP header parsing is done + */ +@@ -338,7 +338,7 @@ public class InternalInputBuffer extends AbstractInputBuffer { + if (buf[pos] == Constants.COLON) { + colon = true; + headerValue = headers.addValue(buf, start, pos - start); +- } else if (!HTTP_TOKEN_CHAR[buf[pos]]) { ++ } else if (!HttpParser.isToken(buf[pos])) { + // If a non-token header is detected, skip the line and + // ignore the header + skipLine(start); +@@ -470,7 +470,7 @@ public class InternalInputBuffer extends AbstractInputBuffer { + if (pos - 1 > start) { + lastRealByte = pos - 1; + } +- ++ + while (!eol) { + + // Read new bytes if needed +@@ -497,7 +497,7 @@ public class InternalInputBuffer extends AbstractInputBuffer { + + /** + * Fill the internal buffer using data from the underlying input stream. +- * ++ * + * @return false if at end of stream + */ + protected boolean fill() throws IOException { +@@ -524,7 +524,7 @@ public class InternalInputBuffer extends AbstractInputBuffer { + } else { + + if (buf.length - end < 4500) { +- // In this case, the request header was really large, so we allocate a ++ // In this case, the request header was really large, so we allocate a + // brand new one; the old one will get GCed when subsequent requests + // clear all references + buf = new byte[buf.length]; +@@ -551,7 +551,7 @@ public class InternalInputBuffer extends AbstractInputBuffer { + * This class is an input buffer which will read its data from an input + * stream. + */ +- protected class InputStreamInputBuffer ++ protected class InputStreamInputBuffer + implements InputBuffer { + + +@@ -559,7 +559,7 @@ public class InternalInputBuffer extends AbstractInputBuffer { + * Read bytes into the specified chunk. + */ + @Override +- public int doRead(ByteChunk chunk, Request req ) ++ public int doRead(ByteChunk chunk, Request req ) + throws IOException { + + if (pos >= lastValid) { +diff --git a/java/org/apache/coyote/http11/InternalNioInputBuffer.java b/java/org/apache/coyote/http11/InternalNioInputBuffer.java +index 0def92d..f13982d 100644 +--- a/java/org/apache/coyote/http11/InternalNioInputBuffer.java ++++ b/java/org/apache/coyote/http11/InternalNioInputBuffer.java +@@ -25,6 +25,7 @@ import org.apache.coyote.InputBuffer; + import org.apache.coyote.Request; + import org.apache.tomcat.util.buf.ByteChunk; + import org.apache.tomcat.util.buf.MessageBytes; ++import org.apache.tomcat.util.http.parser.HttpParser; + import org.apache.tomcat.util.net.AbstractEndpoint; + import org.apache.tomcat.util.net.NioChannel; + import org.apache.tomcat.util.net.NioEndpoint; +@@ -92,7 +93,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + } + + // ----------------------------------------------------------- Constructors +- ++ + + /** + * Alternate constructor. +@@ -137,7 +138,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + * Underlying socket. + */ + private NioChannel socket; +- ++ + /** + * Selector pool, for blocking reads and blocking writes + */ +@@ -159,7 +160,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + // --------------------------------------------------------- Public Methods + + /** +- * Recycle the input buffer. This should be called when closing the ++ * Recycle the input buffer. This should be called when closing the + * connection. + */ + @Override +@@ -178,7 +179,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + + /** + * End processing of current HTTP request. +- * Note: All bytes of the current request should have been already ++ * Note: All bytes of the current request should have been already + * consumed. This method only resets all the pointers so that we are ready + * to parse the next HTTP request. + */ +@@ -195,14 +196,14 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + } + + /** +- * Read the request line. This function is meant to be used during the +- * HTTP request header parsing. Do NOT attempt to read the request body ++ * Read the request line. This function is meant to be used during the ++ * HTTP request header parsing. Do NOT attempt to read the request body + * using it. + * + * @throws IOException If an exception occurs during the underlying socket + * read operations, or if the given buffer is not big enough to accommodate + * the whole line. +- * @return true if data is properly fed; false if no data is available ++ * @return true if data is properly fed; false if no data is available + * immediately and thread should be freed + */ + @Override +@@ -217,7 +218,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + if ( parsingRequestLinePhase == 0 ) { + byte chr = 0; + do { +- ++ + // Read new bytes if needed + if (pos >= lastValid) { + if (useAvailableDataOnly) { +@@ -257,14 +258,11 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + if (!fill(true, false)) //request line parsing + return false; + } +- // Spec says no CR or LF in method name +- if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) { +- throw new IllegalArgumentException( +- sm.getString("iib.invalidmethod")); +- } + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + request.method().setBytes(buf, parsingRequestLineStart, pos - parsingRequestLineStart); ++ } else if (!HttpParser.isToken(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidmethod")); + } + pos++; + } +@@ -290,7 +288,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + } + if (parsingRequestLinePhase == 4) { + // Mark the current buffer position +- ++ + int end = 0; + // + // Reading the URI +@@ -305,21 +303,22 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + end = pos; +- } else if ((buf[pos] == Constants.CR) ++ } else if ((buf[pos] == Constants.CR) + || (buf[pos] == Constants.LF)) { + // HTTP/0.9 style request + parsingRequestLineEol = true; + space = true; + end = pos; +- } else if ((buf[pos] == Constants.QUESTION) +- && (parsingRequestLineQPos == -1)) { ++ } else if ((buf[pos] == Constants.QUESTION) && (parsingRequestLineQPos == -1)) { + parsingRequestLineQPos = pos; ++ } else if (HttpParser.isNotRequestTarget(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); + } + pos++; + } + request.unparsedURI().setBytes(buf, parsingRequestLineStart, end - parsingRequestLineStart); + if (parsingRequestLineQPos >= 0) { +- request.queryString().setBytes(buf, parsingRequestLineQPos + 1, ++ request.queryString().setBytes(buf, parsingRequestLineQPos + 1, + end - parsingRequestLineQPos - 1); + request.requestURI().setBytes(buf, parsingRequestLineStart, parsingRequestLineQPos - parsingRequestLineStart); + } else { +@@ -348,10 +347,10 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + // Mark the current buffer position + end = 0; + } +- if (parsingRequestLinePhase == 6) { ++ if (parsingRequestLinePhase == 6) { + // + // Reading the protocol +- // Protocol is always US-ASCII ++ // Protocol is always "HTTP/" DIGIT "." DIGIT + // + while (!parsingRequestLineEol) { + // Read new bytes if needed +@@ -359,17 +358,19 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + if (!fill(true, false)) //request line parsing + return false; + } +- ++ + if (buf[pos] == Constants.CR) { + end = pos; + } else if (buf[pos] == Constants.LF) { + if (end == 0) + end = pos; + parsingRequestLineEol = true; ++ } else if (!HttpParser.isHttpProtocol(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); + } + pos++; + } +- ++ + if ( (end - parsingRequestLineStart) > 0) { + request.protocol().setBytes(buf, parsingRequestLineStart, end - parsingRequestLineStart); + } else { +@@ -383,7 +384,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + } + throw new IllegalStateException("Invalid request line parse phase:"+parsingRequestLinePhase); + } +- ++ + private void expand(int newsize) { + if ( newsize > buf.length ) { + if (parsingHeader) { +@@ -398,7 +399,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + buf = tmp; + } + } +- ++ + /** + * Perform blocking read with a timeout if desired + * @param timeout boolean - if we want to use the timeout data +@@ -407,7 +408,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + * @throws IOException if a socket exception occurs + * @throws EOFException if end of stream is reached + */ +- ++ + private int readSocket(boolean timeout, boolean block) throws IOException { + int nRead = 0; + socket.getBufHandler().getReadBuffer().clear(); +@@ -429,7 +430,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + socket.getIOChannel().socket().getSoTimeout()); + } catch ( EOFException eof ) { + nRead = -1; +- } finally { ++ } finally { + if ( selector != null ) pool.put(selector); + } + } else { +@@ -462,7 +463,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + } + + HeaderParseStatus status = HeaderParseStatus.HAVE_MORE_HEADERS; +- ++ + do { + status = parseHeader(); + // Checking that +@@ -491,7 +492,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + + /** + * Parse an HTTP header. +- * ++ * + * @return false after reading a blank line (which indicates that the + * HTTP header parsing is done + */ +@@ -507,7 +508,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + + // Read new bytes if needed + if (pos >= lastValid) { +- if (!fill(true,false)) {//parse header ++ if (!fill(true,false)) {//parse header + headerParsePos = HeaderParsePosition.HEADER_START; + return HeaderParseStatus.NEED_MORE_DATA; + } +@@ -543,7 +544,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + + // Read new bytes if needed + if (pos >= lastValid) { +- if (!fill(true,false)) { //parse header ++ if (!fill(true,false)) { //parse header + return HeaderParseStatus.NEED_MORE_DATA; + } + } +@@ -558,7 +559,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + headerData.realPos = pos; + headerData.lastSignificantChar = pos; + break; +- } else if (!HTTP_TOKEN_CHAR[chr]) { ++ } else if (!HttpParser.isToken(chr)) { + // If a non-token header is detected, skip the line and + // ignore the header + headerData.lastSignificantChar = pos; +@@ -590,7 +591,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + while (true) { + // Read new bytes if needed + if (pos >= lastValid) { +- if (!fill(true,false)) {//parse header ++ if (!fill(true,false)) {//parse header + //HEADER_VALUE_START + return HeaderParseStatus.NEED_MORE_DATA; + } +@@ -613,7 +614,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + + // Read new bytes if needed + if (pos >= lastValid) { +- if (!fill(true,false)) {//parse header ++ if (!fill(true,false)) {//parse header + //HEADER_VALUE + return HeaderParseStatus.NEED_MORE_DATA; + } +@@ -646,7 +647,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill(true,false)) {//parse header +- ++ + //HEADER_MULTI_LINE + return HeaderParseStatus.NEED_MORE_DATA; + } +@@ -672,7 +673,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + headerData.recycle(); + return HeaderParseStatus.HAVE_MORE_HEADERS; + } +- ++ + public int getParsingRequestLinePhase() { + return parsingRequestLinePhase; + } +@@ -771,7 +772,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + + /** + * Fill the internal buffer using data from the underlying input stream. +- * ++ * + * @return false if at end of stream + */ + @Override +@@ -780,7 +781,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + } + + protected boolean fill(boolean timeout, boolean block) throws IOException, EOFException { +- ++ + + boolean read = false; + +@@ -809,7 +810,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + * This class is an input buffer which will read its data from an input + * stream. + */ +- protected class SocketInputBuffer ++ protected class SocketInputBuffer + implements InputBuffer { + + +@@ -817,7 +818,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer { + * Read bytes into the specified chunk. + */ + @Override +- public int doRead(ByteChunk chunk, Request req ) ++ public int doRead(ByteChunk chunk, Request req ) + throws IOException { + + if (pos >= lastValid) { +diff --git a/java/org/apache/coyote/http11/LocalStrings.properties b/java/org/apache/coyote/http11/LocalStrings.properties +index 9cd9e19..3cb31bf 100644 +--- a/java/org/apache/coyote/http11/LocalStrings.properties ++++ b/java/org/apache/coyote/http11/LocalStrings.properties +@@ -42,8 +42,10 @@ http11Processor.upgrade=An internal error has occurred as upgraded connections s + iib.apr.sslGeneralError=An APR general error was returned by the SSL read operation on APR/native socket [{0}] with wrapper [{1}]. It will be treated as EAGAIN and the socket returned to the poller. + + iib.eof.error=Unexpected EOF read on the socket +-iib.invalidheader=The HTTP header line [{0}] does not conform to RFC 2616 and has been ignored. ++iib.invalidheader=The HTTP header line [{0}] does not conform to RFC 7230 and has been ignored. + iib.invalidmethod=Invalid character (CR or LF) found in method name ++iib.invalidRequestTarget=Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986 ++iib.invalidHttpProtocol=Invalid character found in the HTTP protocol + iib.parseheaders.ise.error=Unexpected state: headers already parsed. Buffer not recycled? + iib.requestheadertoolarge.error=Request header is too large + +diff --git a/java/org/apache/tomcat/util/http/parser/HttpParser.java b/java/org/apache/tomcat/util/http/parser/HttpParser.java +index 2fc9691..23db2b1 100644 +--- a/java/org/apache/tomcat/util/http/parser/HttpParser.java ++++ b/java/org/apache/tomcat/util/http/parser/HttpParser.java +@@ -53,9 +53,14 @@ public class HttpParser { + private static final Map fieldTypes = + new HashMap(); + +- // Arrays used by isToken(), isHex() +- private static final boolean isToken[] = new boolean[128]; +- private static final boolean isHex[] = new boolean[128]; ++ private static final int ARRAY_SIZE = 128; ++ ++ private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE]; ++ private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE]; ++ private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE]; ++ private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE]; ++ private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE]; ++ private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE]; + + static { + // Digest field types. +@@ -77,25 +82,45 @@ public class HttpParser { + // RFC2617 says nc is 8LHEX. <">8LHEX<"> will also be accepted + fieldTypes.put("nc", FIELD_TYPE_LHEX); + +- // Setup the flag arrays +- for (int i = 0; i < 128; i++) { +- if (i <= 32) { // includes '\t' and ' ' +- isToken[i] = false; +- } else if (i == '(' || i == ')' || i == '<' || i == '>' || i == '@' || +- i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' || +- i == '/' || i == '[' || i == ']' || i == '?' || i == '=' || +- i == '{' || i == '}') { +- isToken[i] = false; +- } else { +- isToken[i] = true; ++ for (int i = 0; i < ARRAY_SIZE; i++) { ++ // Control> 0-31, 127 ++ if (i < 32 || i == 127) { ++ IS_CONTROL[i] = true; + } + +- if (i >= '0' && i <= '9' || i >= 'A' && i <= 'F' || +- i >= 'a' && i <= 'f') { +- isHex[i] = true; +- } else { +- isHex[i] = false; ++ // Separator ++ if ( i == '(' || i == ')' || i == '<' || i == '>' || i == '@' || ++ i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' || ++ i == '/' || i == '[' || i == ']' || i == '?' || i == '=' || ++ i == '{' || i == '}' || i == ' ' || i == '\t') { ++ IS_SEPARATOR[i] = true; ++ } ++ ++ // Token: Anything 0-127 that is not a control and not a separator ++ if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) { ++ IS_TOKEN[i] = true; ++ } ++ ++ // Hex: 0-9, a-f, A-F ++ if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) { ++ IS_HEX[i] = true; + } ++ ++ // Not valid for request target. ++ // Combination of multiple rules from RFC7230 and RFC 3986. Must be ++ // ASCII, no controls plus a few additional characters excluded ++ if (IS_CONTROL[i] || i > 127 || ++ i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' || ++ i == '^' || i == '`' || i == '{' || i == '|' || i == '}') { ++ IS_NOT_REQUEST_TARGET[i] = true; ++ } ++ ++ // Not valid for HTTP protocol ++ // "HTTP/" DIGIT "." DIGIT ++ if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) { ++ IS_HTTP_PROTOCOL[i] = true; ++ } ++ + } + } + +@@ -246,24 +271,49 @@ public class HttpParser { + return result.toString(); + } + +- private static boolean isToken(int c) { ++ ++ public static boolean isToken(int c) { + // Fast for correct values, slower for incorrect ones + try { +- return isToken[c]; ++ return IS_TOKEN[c]; + } catch (ArrayIndexOutOfBoundsException ex) { + return false; + } + } + +- private static boolean isHex(int c) { +- // Fast for correct values, slower for incorrect ones ++ ++ public static boolean isHex(int c) { ++ // Fast for correct values, slower for some incorrect ones + try { +- return isHex[c]; ++ return IS_HEX[c]; + } catch (ArrayIndexOutOfBoundsException ex) { + return false; + } + } + ++ ++ public static boolean isNotRequestTarget(int c) { ++ // Fast for valid request target characters, slower for some incorrect ++ // ones ++ try { ++ return IS_NOT_REQUEST_TARGET[c]; ++ } catch (ArrayIndexOutOfBoundsException ex) { ++ return true; ++ } ++ } ++ ++ ++ public static boolean isHttpProtocol(int c) { ++ // Fast for valid HTTP protocol characters, slower for some incorrect ++ // ones ++ try { ++ return IS_HTTP_PROTOCOL[c]; ++ } catch (ArrayIndexOutOfBoundsException ex) { ++ return false; ++ } ++ } ++ ++ + // Skip any LWS and return the next char + private static int skipLws(StringReader input, boolean withReset) + throws IOException { +-- +2.17.1 + diff -Nru tomcat7-7.0.68/debian/patches/CVE-2016-8735.patch tomcat7-7.0.68/debian/patches/CVE-2016-8735.patch --- tomcat7-7.0.68/debian/patches/CVE-2016-8735.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/CVE-2016-8735.patch 2018-10-18 20:08:33.000000000 +0000 @@ -0,0 +1,36 @@ +From: Markus Koschany +Date: Thu, 24 Nov 2016 18:22:01 +0100 +Subject: CVE-2016-8735 + +Origin: http://svn.apache.org/r1767676 +--- + .../apache/catalina/mbeans/JmxRemoteLifecycleListener.java | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java b/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java +index 918a43a..9ec673b 100644 +--- a/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java ++++ b/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java +@@ -264,6 +264,10 @@ public class JmxRemoteLifecycleListener implements LifecycleListener { + serverCsf = new RmiClientLocalhostSocketFactory(serverCsf); + } + ++ env.put("jmx.remote.rmi.server.credential.types", new String[] { ++ String[].class.getName(), ++ String.class.getName() }); ++ + // Populate the env properties used to create the server + if (serverCsf != null) { + env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, serverCsf); +@@ -328,7 +332,7 @@ public class JmxRemoteLifecycleListener implements LifecycleListener { + cs = new RMIConnectorServer(serviceUrl, theEnv, server, + ManagementFactory.getPlatformMBeanServer()); + cs.start(); +- registry.bind("jmxrmi", server); ++ registry.bind("jmxrmi", server.toStub()); + log.info(sm.getString("jmxRemoteLifecycleListener.start", + Integer.toString(theRmiRegistryPort), + Integer.toString(theRmiServerPort), serverName)); +-- +2.17.1 + diff -Nru tomcat7-7.0.68/debian/patches/CVE-2016-8745.patch tomcat7-7.0.68/debian/patches/CVE-2016-8745.patch --- tomcat7-7.0.68/debian/patches/CVE-2016-8745.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/CVE-2016-8745.patch 2018-10-18 20:19:55.000000000 +0000 @@ -0,0 +1,42 @@ +From: Markus Koschany +Date: Tue, 10 Jan 2017 22:05:28 +0100 +Subject: CVE-2016-8745 + +A bug in the error handling of the send file code for the NIO HTTP +connector resulted in the current Processor object being added to the +Processor cache multiple times. This in turn meant that the same +Processor could be used for concurrent requests. Sharing a Processor can +result in information leakage between requests including, not not +limited to, session ID and the response body. + +Bug-Upstream: https://bz.apache.org/bugzilla/show_bug.cgi?id=60409 +Origin: https://svn.apache.org/viewvc?view=revision&revision=1777471 +--- + java/org/apache/tomcat/util/net/NioEndpoint.java | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java +index 073d77d..9d44f0a 100644 +--- a/java/org/apache/tomcat/util/net/NioEndpoint.java ++++ b/java/org/apache/tomcat/util/net/NioEndpoint.java +@@ -1413,11 +1413,15 @@ public class NioEndpoint extends AbstractEndpoint { + } + }catch ( IOException x ) { + if ( log.isDebugEnabled() ) log.debug("Unable to complete sendfile request:", x); +- cancelledKey(sk,SocketStatus.ERROR,false); ++ if (!event) { ++ cancelledKey(sk,SocketStatus.ERROR,false); ++ } + return false; + }catch ( Throwable t ) { + log.error("",t); +- cancelledKey(sk, SocketStatus.ERROR, false); ++ if (!event) { ++ cancelledKey(sk, SocketStatus.ERROR, false); ++ } + return false; + } + return true; +-- +2.17.1 + diff -Nru tomcat7-7.0.68/debian/patches/series tomcat7-7.0.68/debian/patches/series --- tomcat7-7.0.68/debian/patches/series 2016-06-27 18:12:34.000000000 +0000 +++ tomcat7-7.0.68/debian/patches/series 2018-10-23 15:47:37.000000000 +0000 @@ -18,3 +18,13 @@ 0025-standard-taglibs-compatibility.patch 0026-add-asm-to-test-classpath.patch CVE-2016-3092.patch +CVE-2016-0762.patch +CVE-2016-5018.patch +CVE-2016-5018-part2.patch +CVE-2016-6794.patch +CVE-2016-6796.patch +CVE-2016-6797.patch +CVE-2016-6816.patch +CVE-2016-8735.patch +CVE-2016-8745.patch +0027-update-certs.patch diff -Nru tomcat7-7.0.68/debian/rules tomcat7-7.0.68/debian/rules --- tomcat7-7.0.68/debian/rules 2016-02-18 09:23:48.000000000 +0000 +++ tomcat7-7.0.68/debian/rules 2018-10-19 14:06:02.000000000 +0000 @@ -124,6 +124,11 @@ && sed "s/\@ROOT_WEBAPP_MD5SUM\@/$$rwmd5sum/" debian/tomcat7.postrm.in > debian/tomcat7.postrm jh_manifest + # Make the /etc/tomcat7/Catalina/localhost directory writable by the tomcat user + for PACKAGE in tomcat7 tomcat7-admin tomcat7-docs tomcat7-examples; do \ + chmod 775 --verbose debian/$$PACKAGE/etc/tomcat7/Catalina/localhost; \ + done + override_dh_auto_clean: dh_auto_clean -$(ANT) clean diff -Nru tomcat7-7.0.68/debian/tomcat7.init tomcat7-7.0.68/debian/tomcat7.init --- tomcat7-7.0.68/debian/tomcat7.init 2016-02-18 09:23:48.000000000 +0000 +++ tomcat7-7.0.68/debian/tomcat7.init 2018-10-19 13:45:54.000000000 +0000 @@ -118,7 +118,7 @@ exit 1 fi -POLICY_CACHE="$CATALINA_BASE/work/catalina.policy" +POLICY_CACHE="$CATALINA_BASE/policy/catalina.policy" if [ -z "$CATALINA_TMPDIR" ]; then CATALINA_TMPDIR="$JVM_TMP" @@ -170,8 +170,11 @@ # Run the catalina.sh script as a daemon set +e - touch "$CATALINA_PID" "$CATALINA_BASE"/logs/catalina.out - chown $TOMCAT7_USER "$CATALINA_PID" "$CATALINA_BASE"/logs/catalina.out + if [ ! -f "$CATALINA_BASE"/logs/catalina.out ]; then + # run install as tomcat7 to work around #841371 + su $TOMCAT7_USER -s /bin/bash -c "install -m 644 /dev/null $CATALINA_BASE/logs/catalina.out" + fi + install -o $TOMCAT7_USER -g adm -m 644 /dev/null "$CATALINA_PID" start-stop-daemon --start -b -u "$TOMCAT7_USER" -g "$TOMCAT7_GROUP" \ -c "$TOMCAT7_USER" -d "$CATALINA_TMPDIR" -p "$CATALINA_PID" \ -x /bin/bash -- -c "$AUTHBIND_COMMAND $TOMCAT_SH" @@ -199,6 +202,8 @@ # Regenerate POLICY_CACHE file umask 022 + rm -rf "$CATALINA_BASE/policy" + mkdir "$CATALINA_BASE/policy" echo "// AUTO-GENERATED FILE from /etc/tomcat7/policy.d/" \ > "$POLICY_CACHE" echo "" >> "$POLICY_CACHE" @@ -207,11 +212,11 @@ # Remove / recreate JVM_TMP directory rm -rf "$JVM_TMP" - mkdir -p "$JVM_TMP" || { + mkdir "$JVM_TMP" || { log_failure_msg "could not create JVM temporary directory" exit 1 } - chown $TOMCAT7_USER "$JVM_TMP" + chown -h $TOMCAT7_USER "$JVM_TMP" catalina_sh start $SECURITY sleep 5 diff -Nru tomcat7-7.0.68/debian/tomcat7.postinst tomcat7-7.0.68/debian/tomcat7.postinst --- tomcat7-7.0.68/debian/tomcat7.postinst 2016-02-18 09:23:48.000000000 +0000 +++ tomcat7-7.0.68/debian/tomcat7.postinst 2018-10-18 23:06:37.000000000 +0000 @@ -48,13 +48,28 @@ # configuration files should not be modifiable by tomcat7 user, as this can be a security issue # (an attacker may insert code in a webapp and have access to all tomcat configuration) # but those files should be readable by tomcat7, so we set the group to tomcat7 - chown -Rh root:$TOMCAT7_GROUP /etc/tomcat7/* - if [ -f /etc/tomcat7/tomcat-users.xml ] ; then - chmod 640 /etc/tomcat7/tomcat-users.xml - fi + for i in tomcat-users.xml web.xml server.xml logging.properties context.xml catalina.properties; + do + if [ -f "/etc/tomcat7/$i" ]; then + chown root:$TOMCAT7_GROUP /etc/tomcat7/$i + chmod 640 /etc/tomcat7/$i + fi + done + # configuration policy files should not be modifiable by the tomcat7 user. Only + # diverge from default permissions for known Debian files + chown root:$TOMCAT7_GROUP /etc/tomcat7/policy.d + for i in 01system.policy 02debian.policy 03catalina.policy 04webapps.policy 50local.policy; + do + if [ -f "/etc/tomcat7/policy.d/$i" ]; then + chown root:$TOMCAT7_GROUP /etc/tomcat7/policy.d/$i + chmod 640 /etc/tomcat7/policy.d/$i + fi + done + chown -Rh root:$TOMCAT7_GROUP /etc/tomcat7/Catalina + chown -Rh $TOMCAT7_USER:$TOMCAT7_GROUP /var/lib/tomcat7/webapps /var/lib/tomcat7/common /var/lib/tomcat7/server /var/lib/tomcat7/shared chmod 775 /var/lib/tomcat7/webapps - chmod 775 /etc/tomcat7/Catalina /etc/tomcat7/Catalina/localhost + chmod 775 /etc/tomcat7/Catalina # Authorize user tomcat7 to open privileged ports via authbind. TOMCAT_UID="`id -u $TOMCAT7_USER`" diff -Nru tomcat7-7.0.68/debian/tomcat7.postrm.in tomcat7-7.0.68/debian/tomcat7.postrm.in --- tomcat7-7.0.68/debian/tomcat7.postrm.in 2016-02-18 09:23:48.000000000 +0000 +++ tomcat7-7.0.68/debian/tomcat7.postrm.in 2018-10-19 13:46:31.000000000 +0000 @@ -58,9 +58,6 @@ /etc/tomcat7/Catalina/localhost /etc/tomcat7/Catalina /etc/tomcat7 # clean up /etc/authbind after conffiles have been removed rmdir --ignore-fail-on-non-empty /etc/authbind/byuid /etc/authbind - # Put all files owned by group tomcat7 back into root group before deleting - # the tomcat7 user and group - chown -Rhf root:root /etc/tomcat7/ || true # Remove user/group and log files (don't remove everything under # /var/lib/tomcat7 because there might be user-installed webapps) db_get tomcat7/username && TOMCAT7_USER="$RET" || TOMCAT7_USER="tomcat7"