summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-08-07 10:19:01 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2017-08-07 10:19:21 -0400
commit873741c6821d4fe8245b97e2adf1e8142c8b7531 (patch)
tree09b8726acfd2065bcbcd2c7653bc0a900608f670
parent36f9f60958d471c62515494a0c7b0058e578c2eb (diff)
downloadpostgresql-873741c6821d4fe8245b97e2adf1e8142c8b7531.tar.gz
Require update permission for the large object written by lo_put().
lo_put() surely should require UPDATE permission, the same as lowrite(), but it failed to check for that, as reported by Chapman Flack. Oversight in commit c50b7c09d; backpatch to 9.4 where that was introduced. Tom Lane and Michael Paquier Security: CVE-2017-7548
-rw-r--r--src/backend/libpq/be-fsstubs.c12
-rw-r--r--src/test/regress/expected/privileges.out10
-rw-r--r--src/test/regress/sql/privileges.sql4
3 files changed, 26 insertions, 0 deletions
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
index 89da68f904..75e3b8da4b 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -898,6 +898,18 @@ lo_put(PG_FUNCTION_ARGS)
CreateFSContext();
loDesc = inv_open(loOid, INV_WRITE, fscxt);
+
+ /* Permission check */
+ if (!lo_compat_privileges &&
+ pg_largeobject_aclcheck_snapshot(loDesc->id,
+ GetUserId(),
+ ACL_UPDATE,
+ loDesc->snapshot) != ACLCHECK_OK)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied for large object %u",
+ loDesc->id)));
+
inv_seek(loDesc, offset, SEEK_SET);
written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str));
Assert(written == VARSIZE_ANY_EXHDR(str));
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 9fbcfa7e6b..37ecf5c1ac 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -1220,6 +1220,14 @@ SELECT lo_create(2002);
2002
(1 row)
+SELECT loread(lo_open(1001, x'20000'::int), 32); -- allowed, for now
+ loread
+--------
+ \x
+(1 row)
+
+SELECT lowrite(lo_open(1001, x'40000'::int), 'abcd'); -- fail, wrong mode
+ERROR: large object descriptor 0 was not opened for writing
SELECT loread(lo_open(1001, x'40000'::int), 32);
loread
--------
@@ -1315,6 +1323,8 @@ SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied
ERROR: permission denied for large object 1002
SELECT lo_truncate(lo_open(1002, x'20000'::int), 10); -- to be denied
ERROR: permission denied for large object 1002
+SELECT lo_put(1002, 1, 'abcd'); -- to be denied
+ERROR: permission denied for large object 1002
SELECT lo_unlink(1002); -- to be denied
ERROR: must be owner of large object 1002
SELECT lo_export(1001, '/dev/null'); -- to be denied
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 9368f96035..ab67508e60 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -770,6 +770,9 @@ SET SESSION AUTHORIZATION regressuser2;
SELECT lo_create(2001);
SELECT lo_create(2002);
+SELECT loread(lo_open(1001, x'20000'::int), 32); -- allowed, for now
+SELECT lowrite(lo_open(1001, x'40000'::int), 'abcd'); -- fail, wrong mode
+
SELECT loread(lo_open(1001, x'40000'::int), 32);
SELECT loread(lo_open(1002, x'40000'::int), 32); -- to be denied
SELECT loread(lo_open(1003, x'40000'::int), 32);
@@ -809,6 +812,7 @@ SET SESSION AUTHORIZATION regressuser4;
SELECT loread(lo_open(1002, x'40000'::int), 32); -- to be denied
SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied
SELECT lo_truncate(lo_open(1002, x'20000'::int), 10); -- to be denied
+SELECT lo_put(1002, 1, 'abcd'); -- to be denied
SELECT lo_unlink(1002); -- to be denied
SELECT lo_export(1001, '/dev/null'); -- to be denied