From 340b9830c28d8dda3a0950427585956c803779d2 Mon Sep 17 00:00:00 2001 From: leiziwei Date: Mon, 8 Jul 2024 16:53:48 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A6=81=E6=AD=A2=E6=97=A0=E6=9D=83=E9=99=90?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=89=93=E5=BC=80=E5=A4=A7=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/libpq/be-fsstubs.cpp | 1 + .../storage/large_object/inv_api.cpp | 24 +++++++-- .../expected/large_object_permission.out | 51 +++++++++++++++++++ src/test/regress/parallel_schedule0B | 2 +- .../regress/sql/large_object_permission.sql | 22 ++++++++ 5 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 src/test/regress/expected/large_object_permission.out create mode 100644 src/test/regress/sql/large_object_permission.sql diff --git a/src/common/backend/libpq/be-fsstubs.cpp b/src/common/backend/libpq/be-fsstubs.cpp index 28e3bca08..b06c94913 100644 --- a/src/common/backend/libpq/be-fsstubs.cpp +++ b/src/common/backend/libpq/be-fsstubs.cpp @@ -82,6 +82,7 @@ Datum lo_open(PG_FUNCTION_ARGS) CreateFSContext(); lobjDesc = inv_open(lobjId, mode, u_sess->libpq_cxt.fscxt); if (lobjDesc == NULL) { /* lookup failed */ + elog(DEBUG4, "could not open large object %u", lobjId); PG_RETURN_INT32(-1); } diff --git a/src/gausskernel/storage/large_object/inv_api.cpp b/src/gausskernel/storage/large_object/inv_api.cpp index 34798874e..112c849ca 100644 --- a/src/gausskernel/storage/large_object/inv_api.cpp +++ b/src/gausskernel/storage/large_object/inv_api.cpp @@ -249,7 +249,21 @@ LargeObjectDesc* inv_open(Oid lobjId, int flags, MemoryContext mcxt) /* Can't use LargeObjectExists here because it always uses SnapshotNow */ if (!myLargeObjectExists(lobjId, snapshot)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("large object %u does not exist", lobjId))); - + + /* Apply permission checks, again specifying snapshot */ + if ((descflags & IFS_RDLOCK) != 0) { + if (!u_sess->attr.attr_sql.lo_compat_privileges && + pg_largeobject_aclcheck_snapshot(lobjId, GetUserId(), ACL_SELECT, snapshot) != ACLCHECK_OK) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for large object %u", lobjId))); + } + if ((descflags & IFS_WRLOCK) != 0) { + if (!u_sess->attr.attr_sql.lo_compat_privileges && + pg_largeobject_aclcheck_snapshot(lobjId, GetUserId(), ACL_UPDATE, snapshot) != ACLCHECK_OK) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for large object %u", lobjId))); + } + /* * We must register the snapshot in TopTransaction's resowner, because * it must stay alive until the LO is closed rather than until the @@ -542,7 +556,9 @@ int inv_write(LargeObjectDesc* obj_desc, const char* buf, int nbytes) Assert(buf != NULL); /* enforce writability because snapshot is probably wrong otherwise */ - Assert(obj_desc->flags & IFS_WRLOCK); + if ((obj_desc->flags & IFS_WRLOCK) == 0) + ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for large object %u", obj_desc->id))); if (nbytes <= 0) { return 0; @@ -722,7 +738,9 @@ void inv_truncate(LargeObjectDesc* obj_desc, int64 len) Assert(PointerIsValid(obj_desc)); /* enforce writability because snapshot is probably wrong otherwise */ - Assert(obj_desc->flags & IFS_WRLOCK); + if ((obj_desc->flags & IFS_WRLOCK) == 0) + ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for large object %u", obj_desc->id))); /* * use errmsg_internal here because we don't want to expose INT64_FORMAT diff --git a/src/test/regress/expected/large_object_permission.out b/src/test/regress/expected/large_object_permission.out new file mode 100644 index 000000000..9f9cb7312 --- /dev/null +++ b/src/test/regress/expected/large_object_permission.out @@ -0,0 +1,51 @@ +create database large_object_test_db; +\c large_object_test_db +SELECT lo_create(100); + lo_create +----------- + 100 +(1 row) + +CREATE USER u1 with password 'qwer@1234'; +CREATE USER u2 with password 'qwer@1234'; +GRANT SELECT ON LARGE OBJECT 100 to u1; +SET SESSION AUTHORIZATION u1 PASSWORD 'qwer@1234'; +SELECT SESSION_USER, CURRENT_USER; + session_user | current_user +--------------+-------------- + u1 | u1 +(1 row) + +select lo_open(100, CAST(x'20000' | x'40000' AS integer)); +ERROR: permission denied for large object 100 +CONTEXT: referenced column: lo_open +select lo_open(100, CAST(x'40000' AS integer)); + lo_open +--------- + 0 +(1 row) + +SET SESSION AUTHORIZATION u2 PASSWORD 'qwer@1234'; +SELECT SESSION_USER, CURRENT_USER; + session_user | current_user +--------------+-------------- + u2 | u2 +(1 row) + +select lo_open(100, CAST(x'20000' | x'40000' AS integer)); +ERROR: permission denied for large object 100 +CONTEXT: referenced column: lo_open +select lo_open(100, CAST(x'40000' AS integer)); +ERROR: permission denied for large object 100 +CONTEXT: referenced column: lo_open +\c regression +reset session AUTHORIZATION; +SELECT SESSION_USER, CURRENT_USER; + session_user | current_user +--------------+-------------- +--?.* +(1 row) + +drop database large_object_test_db; +drop user u1; +drop user u2; diff --git a/src/test/regress/parallel_schedule0B b/src/test/regress/parallel_schedule0B index 727e170ce..54763a70b 100644 --- a/src/test/regress/parallel_schedule0B +++ b/src/test/regress/parallel_schedule0B @@ -295,7 +295,7 @@ test: plpgsql_reset_session plpgsql_nested_array_and_record #test: plpgsql_depend test: plpgsql_depend/plpgsql_depend_type plpgsql_depend/plpgsql_pkg_dependency plpgsql_depend/plpgsql_recompile plpgsql_depend/plpgsql_pkg_variable_dependency plpgsql_depend/plpgsql_depend_reftype #test: plancache limit rangefuncs prepare -test: returning largeobject +test: returning largeobject large_object_permission test: hw_explain_pretty1 hw_explain_pretty2 hw_explain_pretty3 test: goto test: equivalence_class diff --git a/src/test/regress/sql/large_object_permission.sql b/src/test/regress/sql/large_object_permission.sql new file mode 100644 index 000000000..8b43bd097 --- /dev/null +++ b/src/test/regress/sql/large_object_permission.sql @@ -0,0 +1,22 @@ +create database large_object_test_db; +\c large_object_test_db +SELECT lo_create(100); +CREATE USER u1 with password 'qwer@1234'; +CREATE USER u2 with password 'qwer@1234'; +GRANT SELECT ON LARGE OBJECT 100 to u1; +SET SESSION AUTHORIZATION u1 PASSWORD 'qwer@1234'; +SELECT SESSION_USER, CURRENT_USER; +select lo_open(100, CAST(x'20000' | x'40000' AS integer)); +select lo_open(100, CAST(x'40000' AS integer)); +SET SESSION AUTHORIZATION u2 PASSWORD 'qwer@1234'; +SELECT SESSION_USER, CURRENT_USER; +select lo_open(100, CAST(x'20000' | x'40000' AS integer)); +select lo_open(100, CAST(x'40000' AS integer)); + +\c regression +reset session AUTHORIZATION; +SELECT SESSION_USER, CURRENT_USER; +drop database large_object_test_db; +drop user u1; +drop user u2; +