]> granicus.if.org Git - postgresql/commitdiff
Require update permission for the large object written by lo_put().
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 7 Aug 2017 14:19:01 +0000 (10:19 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 7 Aug 2017 14:19:19 +0000 (10:19 -0400)
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

src/backend/libpq/be-fsstubs.c
src/test/regress/expected/privileges.out
src/test/regress/sql/privileges.sql

index b31c90fa24db9995bab99422c4862d9618a98f50..bf45461b2f15453ea58923e250f60eb1be73bf3f 100644 (file)
@@ -896,6 +896,18 @@ be_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));
index da37c4faeddba46b36d569b8c1b206bdbdcebcd5..f37df6c709f58b206d07cdcf26b46c2991d11deb 100644 (file)
@@ -1238,6 +1238,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 
 --------
@@ -1333,6 +1341,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
index 5bc47bcd13724db9aa306117c7b6042788ec167b..e2c13e08a45e94918dcfa318149c40152c1380cb 100644 (file)
@@ -779,6 +779,9 @@ SET SESSION AUTHORIZATION regress_user2;
 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);
@@ -818,6 +821,7 @@ SET SESSION AUTHORIZATION regress_user4;
 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