diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2017-08-07 10:19:01 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2017-08-07 10:19:21 -0400 |
commit | 873741c6821d4fe8245b97e2adf1e8142c8b7531 (patch) | |
tree | 09b8726acfd2065bcbcd2c7653bc0a900608f670 | |
parent | 36f9f60958d471c62515494a0c7b0058e578c2eb (diff) | |
download | postgresql-873741c6821d4fe8245b97e2adf1e8142c8b7531.tar.gz postgresql-873741c6821d4fe8245b97e2adf1e8142c8b7531.zip |
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.c | 12 | ||||
-rw-r--r-- | src/test/regress/expected/privileges.out | 10 | ||||
-rw-r--r-- | src/test/regress/sql/privileges.sql | 4 |
3 files changed, 26 insertions, 0 deletions
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c index 89da68f9040..75e3b8da4be 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 9fbcfa7e6b6..37ecf5c1ac2 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 9368f96035d..ab67508e60e 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 |