From d2f6ef84e46765822f92cd8f403a7e4c1f8bb198 Mon Sep 17 00:00:00 2001 From: Chapman Flack Date: Sat, 23 Jan 2016 21:15:46 -0500 Subject: [PATCH 1/2] Add large object truncate and 64-bit offsets. PG 8.3 introduced inv_truncate, and 9.3 made offsets/lengths 64 bit. What's nice is that the Java and JNI method signatures have always been 64-bit ready; now just stop downcasting to 32 on 9.3+ PostgreSQLs where 64 bit offsets are really accepted. --- pljava-so/src/main/c/type/LargeObject.c | 58 ++++++++++++++++--- .../pljava/internal/LargeObject.java | 26 +++++++-- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/pljava-so/src/main/c/type/LargeObject.c b/pljava-so/src/main/c/type/LargeObject.c index 4962aef42..896861d8c 100644 --- a/pljava-so/src/main/c/type/LargeObject.c +++ b/pljava-so/src/main/c/type/LargeObject.c @@ -1,10 +1,14 @@ /* - * Copyright (c) 2004, 2005, 2006 TADA AB - Taby Sweden - * Distributed under the terms shown in the file COPYRIGHT - * found in the root folder of this project or at - * http://eng.tada.se/osprojects/COPYRIGHT.html + * Copyright (c) 2004-2016 Tada AB and other contributors, as listed below. * - * @author Thomas Hallgren + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the The BSD 3-Clause License + * which accompanies this distribution, and is available at + * http://opensource.org/licenses/BSD-3-Clause + * + * Contributors: + * Tada AB + * Chapman Flack */ #include @@ -18,6 +22,12 @@ static jclass s_LargeObject_class; static jmethodID s_LargeObject_init; +#if PG_VERSION_NUM < 90300 +#define OFFSETNARROWCAST (int) +#else +#define OFFSETNARROWCAST +#endif + /* * org.postgresql.pljava.type.LargeObject type. */ @@ -82,6 +92,11 @@ void LargeObject_initialize(void) Java_org_postgresql_pljava_internal_LargeObject__1tell }, { + "_truncate", + "(JJ)V", + Java_org_postgresql_pljava_internal_LargeObject__1truncate + }, + { "_read", "(J[B)I", Java_org_postgresql_pljava_internal_LargeObject__1read @@ -243,7 +258,7 @@ Java_org_postgresql_pljava_internal_LargeObject__1length(JNIEnv* env, jclass cls */ LargeObjectDesc lod; memcpy(&lod, self, sizeof(LargeObjectDesc)); - result = (jlong)inv_seek(&lod, 0, SEEK_END); + result = (jlong)inv_seek(&lod, OFFSETNARROWCAST 0L, SEEK_END); } PG_CATCH(); { @@ -270,7 +285,7 @@ Java_org_postgresql_pljava_internal_LargeObject__1seek(JNIEnv* env, jclass cls, BEGIN_NATIVE PG_TRY(); { - result = (jlong)inv_seek(self, (int)pos, (int)whence); + result = (jlong)inv_seek(self, OFFSETNARROWCAST pos, (int)whence); } PG_CATCH(); { @@ -309,6 +324,35 @@ Java_org_postgresql_pljava_internal_LargeObject__1tell(JNIEnv* env, jclass cls, return result; } +/* + * Class: org_postgresql_pljava_internal_LargeObject + * Method: _truncate + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_org_postgresql_pljava_internal_LargeObject__1truncate + (JNIEnv *env, jclass cls, jlong _this, jlong pos) +{ +#if PG_VERSION_NUM < 80300 + Exception_featureNotSupported("truncate() for large object", "8.3"); +#else + LargeObjectDesc* self = Invocation_getWrappedPointer(_this); + if(self != 0) + { + BEGIN_NATIVE + PG_TRY(); + { + inv_truncate(self, OFFSETNARROWCAST pos); + } + PG_CATCH(); + { + Exception_throw_ERROR("inv_truncate"); + } + PG_END_TRY(); + END_NATIVE + } +#endif +} + /* * Class: org_postgresql_pljava_internal_LargeObject * Method: _read diff --git a/pljava/src/main/java/org/postgresql/pljava/internal/LargeObject.java b/pljava/src/main/java/org/postgresql/pljava/internal/LargeObject.java index b6c751a8c..4725ae196 100644 --- a/pljava/src/main/java/org/postgresql/pljava/internal/LargeObject.java +++ b/pljava/src/main/java/org/postgresql/pljava/internal/LargeObject.java @@ -1,8 +1,14 @@ /* - * Copyright (c) 2004, 2005, 2006 TADA AB - Taby Sweden - * Distributed under the terms shown in the file COPYRIGHT - * found in the root folder of this project or at - * http://eng.tada.se/osprojects/COPYRIGHT.html + * Copyright (c) 2004-2016 Tada AB and other contributors, as listed below. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the The BSD 3-Clause License + * which accompanies this distribution, and is available at + * http://opensource.org/licenses/BSD-3-Clause + * + * Contributors: + * Tada AB + * Chapman Flack */ package org.postgresql.pljava.internal; @@ -141,6 +147,15 @@ public long tell() } } + public void truncate(long offset) + throws SQLException + { + synchronized(Backend.THREADLOCK) + { + _truncate(this.getNativePointer(), offset); + } + } + public int read(byte[] buf) throws SQLException { @@ -183,6 +198,9 @@ private static native long _seek(long pointer, long offset, int whence) private static native long _tell(long pointer) throws SQLException; + private static native void _truncate(long pointer, long offset) + throws SQLException; + private static native int _read(long pointer, byte[] buf) throws SQLException; From 675254b0f17b76f05e72cba2e3b8d3e548ae7a43 Mon Sep 17 00:00:00 2001 From: Chapman Flack Date: Sat, 23 Jan 2016 22:54:18 -0500 Subject: [PATCH 2/2] Change default USAGE grant for 'java'. Ok, it seems that another change to the PostgreSQL large object APIs happened in PG 9.0: large objects got ACLs. Before that, anybody could access them. In PL/Java, anybody still can. :( The ideal accommodation on PL/Java's side will be to retarget PL/Java's LargeObject code from the PG inv_api.c layer to the be-fsstubs.c layer (if something doesn't make that prohibitively difficult), because that's where the 9.0+ access checks happen. Otherwise, the checking code needs to be duplicated in PL/Java. The fsstubs layer has only-good-within-one-transaction semantics. Happily, that's all that's expected for the JDBC *LOB interfaces, which presumably are the public API this stuff should ultimately have. Too involved for 1.5.0. However, this is a good argument for a least- privilege, no-public-by-default installation of the 'java' language, documenting how GRANT USAGE can then be used to allow specific users/roles to make PL/Java functions. Moral: this wasn't a problem before 9.0, when everybody knew LOBs had no access controls. It became a problem when PG added access controls for them, and PL/Java didn't follow suit. What's a trusted language today could need adjustments tomorrow, so no-public-usage-by-default really seems like the best posture; the user/installer should always be encouraged to follow the least privilege principle. --- .../pljava/internal/InstallHelper.java | 1 + src/site/markdown/install/install.md.vm | 20 +++++++++ src/site/markdown/releasenotes.md.vm | 44 +++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/pljava/src/main/java/org/postgresql/pljava/internal/InstallHelper.java b/pljava/src/main/java/org/postgresql/pljava/internal/InstallHelper.java index eab07500e..8f968fdb9 100644 --- a/pljava/src/main/java/org/postgresql/pljava/internal/InstallHelper.java +++ b/pljava/src/main/java/org/postgresql/pljava/internal/InstallHelper.java @@ -212,6 +212,7 @@ private static void languages( Connection c, Statement s) "COMMENT ON LANGUAGE java IS '" + "Trusted/sandboxed language for routines and types in " + "Java; http://tada.github.io/pljava/'"); + s.execute("REVOKE USAGE ON LANGUAGE java FROM PUBLIC"); c.releaseSavepoint(p); } catch ( SQLException sqle ) diff --git a/src/site/markdown/install/install.md.vm b/src/site/markdown/install/install.md.vm index 5532ae489..90822ce70 100644 --- a/src/site/markdown/install/install.md.vm +++ b/src/site/markdown/install/install.md.vm @@ -15,6 +15,7 @@ After completing the [build][bld]: java -jar pljava-packaging/target/pljava-pgX.Y-arch-os-link.jar psql CREATE EXTENSION pljava; + GRANT USAGE ON LANGUAGE java TO ...; -- see "Usage permission" below where *pgX.Y* represents the PostgreSQL version, and *arch*, *os*, and *link* are ... wait, you're impatient, just look in the directory, you'll @@ -188,6 +189,25 @@ as long as the transaction remains open, *but they may block for the duration, so whatever testing will be done within the transaction should be done quickly if that could be an issue*. +$h2 Usage permission + +Installation of PL/Java creates two "languages", `java` and `javau`. +Functions that specify `LANGUAGE javau` can be created only by superusers, +and are subject to very few restrictions at runtime. Functions that specify +`LANGUAGE java` can be created by any user or role that has been granted +`USAGE` permission `ON LANGUAGE java`. They run under a security manager that +denies access to the host filesystem. + +PostgreSQL, by default, would grant `USAGE` to `PUBLIC` on the `java` language, +but PL/Java takes a more conservative approach on a new installation. +In keeping with the principle of least privilege, +selective access can then be granted to those users or roles that will be +expected to install Java functions. Usage may be explicitly granted to `PUBLIC` +if a site prefers that traditional policy. + +In a repeat or upgrade installation (the language `java` already exists), +no change will be made to the access permissions granted on it. + $h2 Special topics Be sure to read these additional sections if: diff --git a/src/site/markdown/releasenotes.md.vm b/src/site/markdown/releasenotes.md.vm index 7c3245565..5c737c605 100644 --- a/src/site/markdown/releasenotes.md.vm +++ b/src/site/markdown/releasenotes.md.vm @@ -16,6 +16,23 @@ compatibility with the latest PostgreSQL and Java versions with modernized build and installation procedures, automatic generation of SQL deployment code from Java annotations, and many significant fixes. +$h3 Security + +This release brings a policy change to a more secure-by-default posture, +where the ability to create functions in `LANGUAGE java` is no longer +automatically granted to `public`, but can be selectively granted to roles +that will have that responsibility. The change reduces exposure to a known +issue present in 1.5.0 and earlier versions, that will be closed in a future +release ([CVE-2016-0768][], see **large objects, access control** below). + +The new policy will be applied in a new installation; permissions will not +be changed in an upgrade, but any site can move to this policy, even before +updating to 1.5.0, with `REVOKE USAGE ON LANGUAGE java FROM public;` followed by +explicit `GRANT` commands for the users/roles expected to create Java +functions. + +[CVE-2016-0768]: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0768 + $h3 Version compatibility PL/Java 1.5.0 can be built against recent PostgreSQL versions including 9.5, @@ -82,6 +99,20 @@ so such a test transaction should be kept short*. $h3 Changes +$h4 `USAGE` to `PUBLIC` no longer default for `java` language + +Of the two languages installed by PL/Java, functions that declare +`LANGUAGE javau` can be created only by superusers, while those that +declare `LANGUAGE java` can be created by any user or role granted the +`USAGE` privilege on the language. + +In the past, the language `java` has been created with PostgreSQL's +default permission granting `USAGE` to `PUBLIC`, but PL/Java 1.5.0 +leaves the permission to be explicitly granted to those users or roles +expected to create Java functions, in keeping with least-privilege +principles. See **large objects, access control** under **known issues** +for background. + $h4 SQL generated by Java annotations Java code developed for use by PL/Java can carry in-code annotations, @@ -292,11 +323,24 @@ PL/Java now uses the current versions of these where appropriate: * `GetUserNameFromId` * `GetUserIdAndSecContext` * `pg_attribute_*` +* Large objects: truncate, and 64-bit offsets $h3 Known issues and areas for future work $h4 Developments in PostgreSQL not yet covered +Large objects, access control +: PL/Java does not yet expose PostgreSQL large objects with a documented, + stable API, and the support it does contain was developed against pre-9.0 + PostgreSQL versions, where no access control applied to large objects and + any object could be accessed by any database user. PL/Java's behavior is + proper for PostgreSQL before 9.0, but improper on 9.0+ where it would be + expected to honor access controls on large objects ([CVE-2016-0768][]). + This will be corrected in a future release. For this and earlier releases, + the recommendation is to selectively grant `USAGE` on the `java` language to + specific users or roles responsible for creating Java functions; see + "default `USAGE` permssion" under Changes. + `INSTEAD OF` triggers, triggers on `TRUNCATE` : These are supported by annotations and the SQL generator, and the runtime will deliver them to the specified method, but the `TriggerData` interface