9793 lines
296 KiB
Diff
9793 lines
296 KiB
Diff
diff -rpNU3 base/configure sepgsql-new/configure
|
|
--- base/configure 2009-03-15 17:47:25.000000000 +0900
|
|
+++ sepgsql-new/configure 2009-03-15 17:58:10.000000000 +0900
|
|
@@ -314,7 +314,7 @@ ac_includes_default="\
|
|
# include <unistd.h>
|
|
#endif"
|
|
|
|
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS configure_args build build_cpu build_vendor build_os host host_cpu host_vendor host_os PORTNAME docdir enable_nls WANTED_LANGUAGES default_port enable_shared enable_rpath enable_debug enable_profiling DTRACE DTRACEFLAGS enable_dtrace CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP GCC TAS autodepend INCLUDES enable_thread_safety with_tcl with_perl with_python with_gssapi with_krb5 krb_srvtab with_pam with_ldap with_bonjour with_openssl with_ossp_uuid XML2_CONFIG with_libxml with_libxslt with_system_tzdata with_zlib EGREP ELF_SYS LDFLAGS_SL LD with_gnu_ld ld_R_works RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP STRIP_STATIC_LIB STRIP_SHARED_LIB TAR LN_S AWK YACC YFLAGS FLEX FLEXFLAGS PERL perl_archlibexp perl_privlibexp perl_useshrplib perl_embed_ldflags PYTHON python_version python_configdir python_includespec python_libdir python_libspec python_additional_libs OSSP_UUID_LIBS HAVE_IPV6 LIBOBJS acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS LDAP_LIBS_FE LDAP_LIBS_BE HAVE_POSIX_SIGNALS MSGFMT MSGMERGE XGETTEXT localedir TCLSH TCL_CONFIG_SH TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIBS TCL_LIB_SPEC TCL_SHARED_BUILD TCL_SHLIB_LD_LIBS NSGMLS JADE have_docbook DOCBOOKSTYLE COLLATEINDEX SGMLSPL vpath_build LTLIBOBJS'
|
|
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS configure_args build build_cpu build_vendor build_os host host_cpu host_vendor host_os PORTNAME docdir enable_nls WANTED_LANGUAGES default_port enable_shared enable_rpath enable_debug enable_profiling DTRACE DTRACEFLAGS enable_dtrace CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP GCC TAS autodepend INCLUDES enable_thread_safety with_tcl with_perl with_python with_gssapi with_krb5 krb_srvtab with_pam with_ldap with_bonjour with_openssl with_ossp_uuid XML2_CONFIG with_libxml with_libxslt with_system_tzdata with_zlib enable_selinux EGREP ELF_SYS LDFLAGS_SL LD with_gnu_ld ld_R_works RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP STRIP_STATIC_LIB STRIP_SHARED_LIB TAR LN_S AWK YACC YFLAGS FLEX FLEXFLAGS PERL perl_archlibexp perl_privlibexp perl_useshrplib perl_embed_ldflags PYTHON python_version python_configdir python_includespec python_libdir python_libspec python_additional_libs OSSP_UUID_LIBS HAVE_IPV6 LIBOBJS acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS LDAP_LIBS_FE LDAP_LIBS_BE HAVE_POSIX_SIGNALS MSGFMT MSGMERGE XGETTEXT localedir TCLSH TCL_CONFIG_SH TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIBS TCL_LIB_SPEC TCL_SHARED_BUILD TCL_SHLIB_LD_LIBS NSGMLS JADE have_docbook DOCBOOKSTYLE COLLATEINDEX SGMLSPL vpath_build LTLIBOBJS'
|
|
ac_subst_files=''
|
|
|
|
# Initialize some variables set by options.
|
|
@@ -871,6 +871,7 @@ Optional Features:
|
|
--enable-cassert enable assertion checks (for debugging)
|
|
--enable-thread-safety make client libraries thread-safe
|
|
--enable-thread-safety-force force thread-safety despite thread test failure
|
|
+ --enable-selinux enable to build with SELinux support
|
|
--disable-largefile omit support for large files
|
|
|
|
Optional Packages:
|
|
@@ -4619,6 +4620,115 @@ fi;
|
|
|
|
|
|
#
|
|
+# SELinux support
|
|
+#
|
|
+
|
|
+pgac_args="$pgac_args enable_selinux"
|
|
+
|
|
+# Check whether --enable-selinux or --disable-selinux was given.
|
|
+if test "${enable_selinux+set}" = set; then
|
|
+ enableval="$enable_selinux"
|
|
+
|
|
+ case $enableval in
|
|
+ yes)
|
|
+ :
|
|
+ ;;
|
|
+ no)
|
|
+ :
|
|
+ ;;
|
|
+ *)
|
|
+ { { echo "$as_me:$LINENO: error: no argument expected for --enable-selinux option" >&5
|
|
+echo "$as_me: error: no argument expected for --enable-selinux option" >&2;}
|
|
+ { (exit 1); exit 1; }; }
|
|
+ ;;
|
|
+ esac
|
|
+
|
|
+else
|
|
+ enable_selinux=no
|
|
+
|
|
+fi;
|
|
+
|
|
+if test "$enable_selinux" = yes; then
|
|
+ echo "$as_me:$LINENO: checking for getpeercon in -lselinux" >&5
|
|
+echo $ECHO_N "checking for getpeercon in -lselinux... $ECHO_C" >&6
|
|
+if test "${ac_cv_lib_selinux_getpeercon+set}" = set; then
|
|
+ echo $ECHO_N "(cached) $ECHO_C" >&6
|
|
+else
|
|
+ ac_check_lib_save_LIBS=$LIBS
|
|
+LIBS="-lselinux $LIBS"
|
|
+cat >conftest.$ac_ext <<_ACEOF
|
|
+/* confdefs.h. */
|
|
+_ACEOF
|
|
+cat confdefs.h >>conftest.$ac_ext
|
|
+cat >>conftest.$ac_ext <<_ACEOF
|
|
+/* end confdefs.h. */
|
|
+
|
|
+/* Override any gcc2 internal prototype to avoid an error. */
|
|
+#ifdef __cplusplus
|
|
+extern "C"
|
|
+#endif
|
|
+/* We use char because int might match the return type of a gcc2
|
|
+ builtin and then its argument prototype would still apply. */
|
|
+char getpeercon ();
|
|
+int
|
|
+main ()
|
|
+{
|
|
+getpeercon ();
|
|
+ ;
|
|
+ return 0;
|
|
+}
|
|
+_ACEOF
|
|
+rm -f conftest.$ac_objext conftest$ac_exeext
|
|
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
|
|
+ (eval $ac_link) 2>conftest.er1
|
|
+ ac_status=$?
|
|
+ grep -v '^ *+' conftest.er1 >conftest.err
|
|
+ rm -f conftest.er1
|
|
+ cat conftest.err >&5
|
|
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
|
+ (exit $ac_status); } &&
|
|
+ { ac_try='test -z "$ac_c_werror_flag"
|
|
+ || test ! -s conftest.err'
|
|
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
|
+ (eval $ac_try) 2>&5
|
|
+ ac_status=$?
|
|
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
|
+ (exit $ac_status); }; } &&
|
|
+ { ac_try='test -s conftest$ac_exeext'
|
|
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
|
+ (eval $ac_try) 2>&5
|
|
+ ac_status=$?
|
|
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
|
+ (exit $ac_status); }; }; then
|
|
+ ac_cv_lib_selinux_getpeercon=yes
|
|
+else
|
|
+ echo "$as_me: failed program was:" >&5
|
|
+sed 's/^/| /' conftest.$ac_ext >&5
|
|
+
|
|
+ac_cv_lib_selinux_getpeercon=no
|
|
+fi
|
|
+rm -f conftest.err conftest.$ac_objext \
|
|
+ conftest$ac_exeext conftest.$ac_ext
|
|
+LIBS=$ac_check_lib_save_LIBS
|
|
+fi
|
|
+echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_getpeercon" >&5
|
|
+echo "${ECHO_T}$ac_cv_lib_selinux_getpeercon" >&6
|
|
+if test $ac_cv_lib_selinux_getpeercon = yes; then
|
|
+
|
|
+cat >>confdefs.h <<_ACEOF
|
|
+#define HAVE_SELINUX 1
|
|
+_ACEOF
|
|
+
|
|
+
|
|
+else
|
|
+ { { echo "$as_me:$LINENO: error: \"--enable-selinux requires libselinux.\"" >&5
|
|
+echo "$as_me: error: \"--enable-selinux requires libselinux.\"" >&2;}
|
|
+ { (exit 1); exit 1; }; }
|
|
+fi
|
|
+
|
|
+fi
|
|
+
|
|
+#
|
|
# Elf
|
|
#
|
|
|
|
@@ -26019,6 +26129,7 @@ s,@with_libxml@,$with_libxml,;t t
|
|
s,@with_libxslt@,$with_libxslt,;t t
|
|
s,@with_system_tzdata@,$with_system_tzdata,;t t
|
|
s,@with_zlib@,$with_zlib,;t t
|
|
+s,@enable_selinux@,$enable_selinux,;t t
|
|
s,@EGREP@,$EGREP,;t t
|
|
s,@ELF_SYS@,$ELF_SYS,;t t
|
|
s,@LDFLAGS_SL@,$LDFLAGS_SL,;t t
|
|
diff -rpNU3 base/configure.in sepgsql-new/configure.in
|
|
--- base/configure.in 2009-03-15 17:47:25.000000000 +0900
|
|
+++ sepgsql-new/configure.in 2009-03-15 17:58:10.000000000 +0900
|
|
@@ -626,6 +626,19 @@ PGAC_ARG_BOOL(with, zlib, yes,
|
|
AC_SUBST(with_zlib)
|
|
|
|
#
|
|
+# SELinux support
|
|
+#
|
|
+PGAC_ARG_BOOL(enable, selinux, no,
|
|
+ [ --enable-selinux enable to build with SELinux support])
|
|
+if test "$enable_selinux" = yes; then
|
|
+ AC_CHECK_LIB(selinux, getpeercon,
|
|
+ AC_DEFINE_UNQUOTED(HAVE_SELINUX, 1,
|
|
+ [SE-PostgreSQL feature is enabled])
|
|
+ AC_SUBST(enable_selinux),
|
|
+ AC_MSG_ERROR("--enable-selinux requires libselinux."))
|
|
+fi
|
|
+
|
|
+#
|
|
# Elf
|
|
#
|
|
|
|
diff -rpNU3 base/src/Makefile.global.in sepgsql-new/src/Makefile.global.in
|
|
--- base/src/Makefile.global.in 2007-11-17 20:15:40.000000000 +0900
|
|
+++ sepgsql-new/src/Makefile.global.in 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -165,6 +165,7 @@ enable_rpath = @enable_rpath@
|
|
enable_nls = @enable_nls@
|
|
enable_debug = @enable_debug@
|
|
enable_dtrace = @enable_dtrace@
|
|
+enable_selinux = @enable_selinux@
|
|
enable_thread_safety = @enable_thread_safety@
|
|
|
|
python_includespec = @python_includespec@
|
|
diff -rpNU3 base/src/backend/Makefile sepgsql-new/src/backend/Makefile
|
|
--- base/src/backend/Makefile 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/Makefile 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -16,7 +16,7 @@ include $(top_builddir)/src/Makefile.glo
|
|
|
|
DIRS = access bootstrap catalog parser commands executor lib libpq \
|
|
main nodes optimizer port postmaster regex rewrite \
|
|
- storage tcop tsearch utils $(top_builddir)/src/timezone
|
|
+ security storage tcop tsearch utils $(top_builddir)/src/timezone
|
|
|
|
SUBSYSOBJS = $(DIRS:%=%/SUBSYS.o)
|
|
|
|
@@ -32,6 +32,11 @@ LIBS := $(filter-out -lpgport, $(LIBS))
|
|
# The backend doesn't need everything that's in LIBS, however
|
|
LIBS := $(filter-out -lz -lreadline -ledit -ltermcap -lncurses -lcurses, $(LIBS))
|
|
|
|
+# SELinux needs libselinux
|
|
+ifeq ($(enable_selinux), yes)
|
|
+LIBS += -lselinux
|
|
+endif
|
|
+
|
|
##########################################################################
|
|
|
|
all: submake-libpgport postgres $(POSTGRES_IMP)
|
|
diff -rpNU3 base/src/backend/access/common/heaptuple.c sepgsql-new/src/backend/access/common/heaptuple.c
|
|
--- base/src/backend/access/common/heaptuple.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/access/common/heaptuple.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -66,6 +66,7 @@
|
|
|
|
#include "access/heapam.h"
|
|
#include "access/tuptoaster.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "executor/tuptable.h"
|
|
|
|
|
|
@@ -473,6 +474,7 @@ heap_attisnull(HeapTuple tup, int attnum
|
|
case MinCommandIdAttributeNumber:
|
|
case MaxTransactionIdAttributeNumber:
|
|
case MaxCommandIdAttributeNumber:
|
|
+ case SecurityLabelAttributeNumber:
|
|
/* these are never null */
|
|
break;
|
|
|
|
@@ -785,6 +787,9 @@ heap_getsysattr(HeapTuple tup, int attnu
|
|
case TableOidAttributeNumber:
|
|
result = ObjectIdGetDatum(tup->t_tableOid);
|
|
break;
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ result = securityHeapGetSecLabelSysattr(tup);
|
|
+ break;
|
|
default:
|
|
elog(ERROR, "invalid attnum: %d", attnum);
|
|
result = 0; /* keep compiler quiet */
|
|
@@ -908,6 +913,8 @@ heap_form_tuple(TupleDesc tupleDescripto
|
|
|
|
if (tupleDescriptor->tdhasoid)
|
|
len += sizeof(Oid);
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ len += sizeof(Oid);
|
|
|
|
hoff = len = MAXALIGN(len); /* align user data safely */
|
|
|
|
@@ -939,6 +946,8 @@ heap_form_tuple(TupleDesc tupleDescripto
|
|
|
|
if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
|
|
td->t_infomask = HEAP_HASOID;
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ td->t_infomask |= HEAP_HAS_SECLABEL;
|
|
|
|
heap_fill_tuple(tupleDescriptor,
|
|
values,
|
|
@@ -1019,6 +1028,8 @@ heap_formtuple(TupleDesc tupleDescriptor
|
|
|
|
if (tupleDescriptor->tdhasoid)
|
|
len += sizeof(Oid);
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ len += sizeof(Oid);
|
|
|
|
hoff = len = MAXALIGN(len); /* align user data safely */
|
|
|
|
@@ -1050,6 +1061,8 @@ heap_formtuple(TupleDesc tupleDescriptor
|
|
|
|
if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
|
|
td->t_infomask = HEAP_HASOID;
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ td->t_infomask |= HEAP_HAS_SECLABEL;
|
|
|
|
DataFill(tupleDescriptor,
|
|
values,
|
|
@@ -1129,6 +1142,8 @@ heap_modify_tuple(HeapTuple tuple,
|
|
newTuple->t_tableOid = tuple->t_tableOid;
|
|
if (tupleDesc->tdhasoid)
|
|
HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
|
|
+ if (HeapTupleHasSecLabel(newTuple))
|
|
+ HeapTupleSetSecLabel(newTuple, HeapTupleGetSecLabel(tuple));
|
|
|
|
return newTuple;
|
|
}
|
|
@@ -1201,6 +1216,8 @@ heap_modifytuple(HeapTuple tuple,
|
|
newTuple->t_tableOid = tuple->t_tableOid;
|
|
if (tupleDesc->tdhasoid)
|
|
HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
|
|
+ if (HeapTupleHasSecLabel(newTuple))
|
|
+ HeapTupleSetSecLabel(newTuple, HeapTupleGetSecLabel(tuple));
|
|
|
|
return newTuple;
|
|
}
|
|
@@ -1846,6 +1863,8 @@ heap_form_minimal_tuple(TupleDesc tupleD
|
|
|
|
if (tupleDescriptor->tdhasoid)
|
|
len += sizeof(Oid);
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ len += sizeof(Oid);
|
|
|
|
hoff = len = MAXALIGN(len); /* align user data safely */
|
|
|
|
@@ -1867,6 +1886,8 @@ heap_form_minimal_tuple(TupleDesc tupleD
|
|
|
|
if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
|
|
tuple->t_infomask = HEAP_HASOID;
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ tuple->t_infomask |= HEAP_HAS_SECLABEL;
|
|
|
|
heap_fill_tuple(tupleDescriptor,
|
|
values,
|
|
@@ -1965,6 +1986,7 @@ minimal_tuple_from_heap_tuple(HeapTuple
|
|
HeapTuple
|
|
heap_addheader(int natts, /* max domain index */
|
|
bool withoid, /* reserve space for oid */
|
|
+ bool withseclabel, /* reserve space for security */
|
|
Size structlen, /* its length */
|
|
void *structure) /* pointer to the struct */
|
|
{
|
|
@@ -1979,6 +2001,8 @@ heap_addheader(int natts, /* max domain
|
|
hoff = offsetof(HeapTupleHeaderData, t_bits);
|
|
if (withoid)
|
|
hoff += sizeof(Oid);
|
|
+ if (withseclabel)
|
|
+ hoff += sizeof(Oid);
|
|
hoff = MAXALIGN(hoff);
|
|
len = hoff + structlen;
|
|
|
|
@@ -1996,6 +2020,8 @@ heap_addheader(int natts, /* max domain
|
|
|
|
if (withoid) /* else leave infomask = 0 */
|
|
td->t_infomask = HEAP_HASOID;
|
|
+ if (withseclabel)
|
|
+ td->t_infomask |= HEAP_HAS_SECLABEL;
|
|
|
|
memcpy((char *) td + hoff, structure, structlen);
|
|
|
|
diff -rpNU3 base/src/backend/access/common/tupdesc.c sepgsql-new/src/backend/access/common/tupdesc.c
|
|
--- base/src/backend/access/common/tupdesc.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/access/common/tupdesc.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -84,6 +84,7 @@ CreateTemplateTupleDesc(int natts, bool
|
|
desc->tdtypeid = RECORDOID;
|
|
desc->tdtypmod = -1;
|
|
desc->tdhasoid = hasoid;
|
|
+ desc->tdhasseclabel = false;
|
|
desc->tdrefcount = -1; /* assume not reference-counted */
|
|
|
|
return desc;
|
|
@@ -117,6 +118,7 @@ CreateTupleDesc(int natts, bool hasoid,
|
|
desc->tdtypeid = RECORDOID;
|
|
desc->tdtypmod = -1;
|
|
desc->tdhasoid = hasoid;
|
|
+ desc->tdhasseclabel = false;
|
|
desc->tdrefcount = -1; /* assume not reference-counted */
|
|
|
|
return desc;
|
|
@@ -146,6 +148,7 @@ CreateTupleDescCopy(TupleDesc tupdesc)
|
|
|
|
desc->tdtypeid = tupdesc->tdtypeid;
|
|
desc->tdtypmod = tupdesc->tdtypmod;
|
|
+ desc->tdhasseclabel = tupdesc->tdhasseclabel;
|
|
|
|
return desc;
|
|
}
|
|
@@ -204,6 +207,7 @@ CreateTupleDescCopyConstr(TupleDesc tupd
|
|
|
|
desc->tdtypeid = tupdesc->tdtypeid;
|
|
desc->tdtypmod = tupdesc->tdtypmod;
|
|
+ desc->tdhasseclabel = tupdesc->tdhasseclabel;
|
|
|
|
return desc;
|
|
}
|
|
@@ -310,6 +314,8 @@ equalTupleDescs(TupleDesc tupdesc1, Tupl
|
|
return false;
|
|
if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
|
|
return false;
|
|
+ if (tupdesc1->tdhasseclabel != tupdesc2->tdhasseclabel)
|
|
+ return false;
|
|
|
|
for (i = 0; i < tupdesc1->natts; i++)
|
|
{
|
|
diff -rpNU3 base/src/backend/access/heap/heapam.c sepgsql-new/src/backend/access/heap/heapam.c
|
|
--- base/src/backend/access/heap/heapam.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql-new/src/backend/access/heap/heapam.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -50,6 +50,7 @@
|
|
#include "catalog/namespace.h"
|
|
#include "miscadmin.h"
|
|
#include "pgstat.h"
|
|
+#include "security/rowlevel.h"
|
|
#include "storage/procarray.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/datum.h"
|
|
@@ -1949,6 +1950,8 @@ heap_insert(Relation relation, HeapTuple
|
|
Oid
|
|
simple_heap_insert(Relation relation, HeapTuple tup)
|
|
{
|
|
+ rowlvHeapTupleInsert(relation, tup, true);
|
|
+
|
|
return heap_insert(relation, tup, GetCurrentCommandId(true), true, true);
|
|
}
|
|
|
|
@@ -2230,6 +2233,8 @@ simple_heap_delete(Relation relation, It
|
|
ItemPointerData update_ctid;
|
|
TransactionId update_xmax;
|
|
|
|
+ rowlvHeapTupleDelete(relation, tid, true);
|
|
+
|
|
result = heap_delete(relation, tid,
|
|
&update_ctid, &update_xmax,
|
|
GetCurrentCommandId(true), InvalidSnapshot,
|
|
@@ -2874,6 +2879,8 @@ simple_heap_update(Relation relation, It
|
|
ItemPointerData update_ctid;
|
|
TransactionId update_xmax;
|
|
|
|
+ rowlvHeapTupleUpdate(relation, otid, tup, true);
|
|
+
|
|
result = heap_update(relation, otid, tup,
|
|
&update_ctid, &update_xmax,
|
|
GetCurrentCommandId(true), InvalidSnapshot,
|
|
diff -rpNU3 base/src/backend/access/heap/tuptoaster.c sepgsql-new/src/backend/access/heap/tuptoaster.c
|
|
--- base/src/backend/access/heap/tuptoaster.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql-new/src/backend/access/heap/tuptoaster.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -35,6 +35,7 @@
|
|
#include "access/tuptoaster.h"
|
|
#include "access/xact.h"
|
|
#include "catalog/catalog.h"
|
|
+#include "security/rowlevel.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/pg_lzcompress.h"
|
|
#include "utils/typcache.h"
|
|
@@ -589,6 +590,8 @@ toast_insert_or_update(Relation rel, Hea
|
|
hoff += BITMAPLEN(numAttrs);
|
|
if (newtup->t_data->t_infomask & HEAP_HASOID)
|
|
hoff += sizeof(Oid);
|
|
+ if (HeapTupleHasSecLabel(newtup))
|
|
+ hoff += sizeof(Oid);
|
|
hoff = MAXALIGN(hoff);
|
|
Assert(hoff == newtup->t_data->t_hoff);
|
|
/* now convert to a limit on the tuple data size */
|
|
@@ -838,6 +841,8 @@ toast_insert_or_update(Relation rel, Hea
|
|
new_len += BITMAPLEN(numAttrs);
|
|
if (olddata->t_infomask & HEAP_HASOID)
|
|
new_len += sizeof(Oid);
|
|
+ if (HeapTupleHeaderHasSecLabel(olddata))
|
|
+ new_len += sizeof(Oid);
|
|
new_len = MAXALIGN(new_len);
|
|
Assert(new_len == olddata->t_hoff);
|
|
new_data_len = heap_compute_data_size(tupleDesc,
|
|
@@ -989,6 +994,8 @@ toast_flatten_tuple_attribute(Datum valu
|
|
new_len += BITMAPLEN(numAttrs);
|
|
if (olddata->t_infomask & HEAP_HASOID)
|
|
new_len += sizeof(Oid);
|
|
+ if (HeapTupleHeaderHasSecLabel(olddata))
|
|
+ new_len += sizeof(Oid);
|
|
new_len = MAXALIGN(new_len);
|
|
Assert(new_len == olddata->t_hoff);
|
|
new_data_len = heap_compute_data_size(tupleDesc,
|
|
@@ -1173,6 +1180,8 @@ toast_save_datum(Relation rel, Datum val
|
|
memcpy(VARDATA(&chunk_data), data_p, chunk_size);
|
|
toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull);
|
|
|
|
+ rowlvHeapTupleInsert(toastrel, toasttup, true);
|
|
+
|
|
heap_insert(toastrel, toasttup, mycid, use_wal, use_fsm);
|
|
|
|
/*
|
|
diff -rpNU3 base/src/backend/bootstrap/bootparse.y sepgsql-new/src/backend/bootstrap/bootparse.y
|
|
--- base/src/backend/bootstrap/bootparse.y 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/bootstrap/bootparse.y 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -33,6 +33,7 @@
|
|
#include "catalog/pg_class.h"
|
|
#include "catalog/pg_namespace.h"
|
|
#include "catalog/pg_tablespace.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/toasting.h"
|
|
#include "commands/defrem.h"
|
|
#include "miscadmin.h"
|
|
@@ -42,6 +43,7 @@
|
|
#include "nodes/pg_list.h"
|
|
#include "nodes/primnodes.h"
|
|
#include "rewrite/prs2lock.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/block.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/ipc.h"
|
|
@@ -194,6 +196,12 @@ Boot_CreateStmt:
|
|
RELKIND_RELATION,
|
|
$3,
|
|
true);
|
|
+ /*
|
|
+ * fixup boot_reldesc->rd_att->tdhassecXXXX
|
|
+ */
|
|
+ boot_reldesc->rd_rel->relkind = RELKIND_RELATION;
|
|
+ boot_reldesc->rd_att->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(boot_reldesc);
|
|
elog(DEBUG4, "bootstrap relation created");
|
|
}
|
|
else
|
|
@@ -212,7 +220,8 @@ Boot_CreateStmt:
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
(Datum) 0,
|
|
- true);
|
|
+ true,
|
|
+ NIL);
|
|
elog(DEBUG4, "relation created with oid %u", id);
|
|
}
|
|
do_end();
|
|
diff -rpNU3 base/src/backend/bootstrap/bootstrap.c sepgsql-new/src/backend/bootstrap/bootstrap.c
|
|
--- base/src/backend/bootstrap/bootstrap.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/bootstrap/bootstrap.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -25,6 +25,7 @@
|
|
#include "access/xact.h"
|
|
#include "bootstrap/bootstrap.h"
|
|
#include "catalog/index.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "libpq/pqsignal.h"
|
|
#include "miscadmin.h"
|
|
@@ -499,6 +500,11 @@ BootstrapModeMain(void)
|
|
*/
|
|
boot_yyparse();
|
|
|
|
+ /*
|
|
+ * Flush all the cached security label
|
|
+ */
|
|
+ securityPostBootstrapingMode();
|
|
+
|
|
/* Perform a checkpoint to ensure everything's down to disk */
|
|
SetProcessingMode(NormalProcessing);
|
|
CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);
|
|
@@ -796,6 +802,8 @@ InsertOneTuple(Oid objectid)
|
|
tupDesc = CreateTupleDesc(numattr,
|
|
RelationGetForm(boot_reldesc)->relhasoids,
|
|
attrtypes);
|
|
+ tupDesc->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(boot_reldesc);
|
|
tuple = heap_formtuple(tupDesc, values, Blanks);
|
|
if (objectid != (Oid) 0)
|
|
HeapTupleSetOid(tuple, objectid);
|
|
diff -rpNU3 base/src/backend/catalog/Makefile sepgsql-new/src/backend/catalog/Makefile
|
|
--- base/src/backend/catalog/Makefile 2007-09-11 10:53:53.000000000 +0900
|
|
+++ sepgsql-new/src/backend/catalog/Makefile 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -13,7 +13,7 @@ include $(top_builddir)/src/Makefile.glo
|
|
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
|
|
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
|
|
pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
|
|
- pg_type.o toasting.o
|
|
+ pg_security.o pg_type.o toasting.o
|
|
|
|
BKIFILES = postgres.bki postgres.description postgres.shdescription
|
|
|
|
@@ -35,7 +35,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_sr
|
|
pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
|
|
pg_database.h pg_tablespace.h pg_pltemplate.h \
|
|
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
|
|
- pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
|
|
+ pg_security.h pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
|
|
pg_ts_parser.h pg_ts_template.h \
|
|
toasting.h indexing.h \
|
|
)
|
|
diff -rpNU3 base/src/backend/catalog/aclchk.c sepgsql-new/src/backend/catalog/aclchk.c
|
|
--- base/src/backend/catalog/aclchk.c 2008-06-12 22:34:19.000000000 +0900
|
|
+++ sepgsql-new/src/backend/catalog/aclchk.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -39,6 +39,7 @@
|
|
#include "commands/dbcommands.h"
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_func.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -1979,7 +1980,14 @@ AclResult
|
|
pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
|
|
{
|
|
if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
|
|
+ {
|
|
+ /* SELinux: db_database:{access} permission */
|
|
+ if ((mode & ACL_CONNECT) != 0
|
|
+ && !sepgsqlCheckDatabaseAccess(db_oid))
|
|
+ return ACLCHECK_NO_PRIV;
|
|
+
|
|
return ACLCHECK_OK;
|
|
+ }
|
|
else
|
|
return ACLCHECK_NO_PRIV;
|
|
}
|
|
@@ -1991,7 +1999,14 @@ AclResult
|
|
pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
|
|
{
|
|
if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
|
|
+ {
|
|
+ /* SELinux: db_procedure:{execute} permission */
|
|
+ if ((mode & ACL_EXECUTE) != 0
|
|
+ && !sepgsqlCheckProcedureExecute(proc_oid))
|
|
+ return ACLCHECK_NO_PRIV;
|
|
+
|
|
return ACLCHECK_OK;
|
|
+ }
|
|
else
|
|
return ACLCHECK_NO_PRIV;
|
|
}
|
|
diff -rpNU3 base/src/backend/catalog/catalog.c sepgsql-new/src/backend/catalog/catalog.c
|
|
--- base/src/backend/catalog/catalog.c 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql-new/src/backend/catalog/catalog.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -30,6 +30,7 @@
|
|
#include "catalog/pg_database.h"
|
|
#include "catalog/pg_namespace.h"
|
|
#include "catalog/pg_pltemplate.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_shdepend.h"
|
|
#include "catalog/pg_shdescription.h"
|
|
#include "catalog/pg_tablespace.h"
|
|
@@ -257,6 +258,7 @@ IsSharedRelation(Oid relationId)
|
|
relationId == AuthMemRelationId ||
|
|
relationId == DatabaseRelationId ||
|
|
relationId == PLTemplateRelationId ||
|
|
+ relationId == SecurityRelationId ||
|
|
relationId == SharedDescriptionRelationId ||
|
|
relationId == SharedDependRelationId ||
|
|
relationId == TableSpaceRelationId)
|
|
@@ -269,6 +271,8 @@ IsSharedRelation(Oid relationId)
|
|
relationId == DatabaseNameIndexId ||
|
|
relationId == DatabaseOidIndexId ||
|
|
relationId == PLTemplateNameIndexId ||
|
|
+ relationId == SecurityOidIndexId ||
|
|
+ relationId == SecuritySeclabelIndexId ||
|
|
relationId == SharedDescriptionObjIndexId ||
|
|
relationId == SharedDependDependerIndexId ||
|
|
relationId == SharedDependReferenceIndexId ||
|
|
diff -rpNU3 base/src/backend/catalog/heap.c sepgsql-new/src/backend/catalog/heap.c
|
|
--- base/src/backend/catalog/heap.c 2009-03-15 17:47:25.000000000 +0900
|
|
+++ sepgsql-new/src/backend/catalog/heap.c 2009-03-15 17:58:10.000000000 +0900
|
|
@@ -42,6 +42,7 @@
|
|
#include "catalog/pg_constraint.h"
|
|
#include "catalog/pg_inherits.h"
|
|
#include "catalog/pg_namespace.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_statistic.h"
|
|
#include "catalog/pg_tablespace.h"
|
|
#include "catalog/pg_type.h"
|
|
@@ -53,6 +54,7 @@
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_expr.h"
|
|
#include "parser/parse_relation.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
@@ -67,7 +69,8 @@ static void AddNewRelationTuple(Relation
|
|
Oid new_rel_oid, Oid new_type_oid,
|
|
Oid relowner,
|
|
char relkind,
|
|
- Datum reloptions);
|
|
+ Datum reloptions,
|
|
+ List *selblList);
|
|
static Oid AddNewRelationType(const char *typeName,
|
|
Oid typeNamespace,
|
|
Oid new_rel_oid,
|
|
@@ -145,7 +148,16 @@ static FormData_pg_attribute a7 = {
|
|
true, 'p', 'i', true, false, false, true, 0
|
|
};
|
|
|
|
-static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};
|
|
+/*
|
|
+ * System columns for enhanced security features
|
|
+ */
|
|
+static FormData_pg_attribute a8 = {
|
|
+ 0, {SecurityLabelAttributeName}, TEXTOID, 0, -1,
|
|
+ SecurityLabelAttributeNumber, 0, -1, -1,
|
|
+ false, 'x', 'i', true, false, false, true, 0
|
|
+};
|
|
+
|
|
+static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8};
|
|
|
|
/*
|
|
* This function returns a Form_pg_attribute pointer for a system attribute.
|
|
@@ -185,6 +197,18 @@ SystemAttributeByName(const char *attnam
|
|
return NULL;
|
|
}
|
|
|
|
+/*
|
|
+ * This function returns true, if the given attribute number is writable
|
|
+ * system column. If not, returns false.
|
|
+ */
|
|
+bool
|
|
+SystemAttributeIsWritable(AttrNumber attnum)
|
|
+{
|
|
+ if (attnum == SecurityLabelAttributeNumber)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* XXX END OF UGLY HARD CODED BADNESS XXX
|
|
@@ -468,7 +492,8 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|
TupleDesc tupdesc,
|
|
char relkind,
|
|
bool oidislocal,
|
|
- int oidinhcount)
|
|
+ int oidinhcount,
|
|
+ List *selblList)
|
|
{
|
|
const Form_pg_attribute *dpp;
|
|
int i;
|
|
@@ -493,16 +518,40 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|
dpp = tupdesc->attrs;
|
|
for (i = 0; i < natts; i++)
|
|
{
|
|
+ ListCell *l;
|
|
+ Oid attselabel = InvalidOid;
|
|
+
|
|
/* Fill in the correct relation OID */
|
|
(*dpp)->attrelid = new_rel_oid;
|
|
/* Make sure these are OK, too */
|
|
(*dpp)->attstattarget = -1;
|
|
(*dpp)->attcacheoff = -1;
|
|
|
|
+ /* SELinux: extract a given security context */
|
|
+ foreach (l, selblList)
|
|
+ {
|
|
+ DefElem *defel = lfirst(l);
|
|
+
|
|
+ if (defel->defname &&
|
|
+ strcmp(defel->defname, NameStr((*dpp)->attname)) == 0)
|
|
+ {
|
|
+ attselabel = sepgsqlInputGivenSecLabel(defel);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
tup = heap_addheader(Natts_pg_attribute,
|
|
false,
|
|
+ RelationGetDescr(rel)->tdhasseclabel,
|
|
ATTRIBUTE_TUPLE_SIZE,
|
|
(void *) *dpp);
|
|
+ if (OidIsValid(attselabel))
|
|
+ {
|
|
+ if (!HeapTupleHasSecLabel(tup))
|
|
+ elog(ERROR, "Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(rel));
|
|
+ HeapTupleSetSecLabel(tup, attselabel);
|
|
+ }
|
|
|
|
simple_heap_insert(rel, tup);
|
|
|
|
@@ -538,6 +587,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|
|
|
tup = heap_addheader(Natts_pg_attribute,
|
|
false,
|
|
+ RelationGetDescr(rel)->tdhasseclabel,
|
|
ATTRIBUTE_TUPLE_SIZE,
|
|
(void *) *dpp);
|
|
attStruct = (Form_pg_attribute) GETSTRUCT(tup);
|
|
@@ -593,7 +643,8 @@ void
|
|
InsertPgClassTuple(Relation pg_class_desc,
|
|
Relation new_rel_desc,
|
|
Oid new_rel_oid,
|
|
- Datum reloptions)
|
|
+ Datum reloptions,
|
|
+ Oid relselabel)
|
|
{
|
|
Form_pg_class rd_rel = new_rel_desc->rd_rel;
|
|
Datum values[Natts_pg_class];
|
|
@@ -644,11 +695,23 @@ InsertPgClassTuple(Relation pg_class_des
|
|
*/
|
|
HeapTupleSetOid(tup, new_rel_oid);
|
|
|
|
+ /* set explicit security label */
|
|
+ if (OidIsValid(relselabel))
|
|
+ {
|
|
+ if (!HeapTupleHasSecLabel(tup))
|
|
+ elog(ERROR, "Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(pg_class_desc));
|
|
+ HeapTupleSetSecLabel(tup, relselabel);
|
|
+ }
|
|
+
|
|
/* finally insert the new tuple, update the indexes, and clean up */
|
|
simple_heap_insert(pg_class_desc, tup);
|
|
|
|
CatalogUpdateIndexes(pg_class_desc, tup);
|
|
|
|
+ /* temporary use for this tuple */
|
|
+ InsertSysCache(RelationGetRelid(pg_class_desc), tup);
|
|
+
|
|
heap_freetuple(tup);
|
|
}
|
|
|
|
@@ -666,9 +729,12 @@ AddNewRelationTuple(Relation pg_class_de
|
|
Oid new_type_oid,
|
|
Oid relowner,
|
|
char relkind,
|
|
- Datum reloptions)
|
|
+ Datum reloptions,
|
|
+ List *selblList)
|
|
{
|
|
Form_pg_class new_rel_reltup;
|
|
+ Oid relselabel = InvalidOid;
|
|
+ ListCell *l;
|
|
|
|
/*
|
|
* first we update some of the information in our uncataloged relation's
|
|
@@ -725,8 +791,21 @@ AddNewRelationTuple(Relation pg_class_de
|
|
|
|
new_rel_desc->rd_att->tdtypeid = new_type_oid;
|
|
|
|
+ /* SELinux: extract a given security context */
|
|
+ foreach (l, selblList)
|
|
+ {
|
|
+ DefElem *defel = lfirst(l);
|
|
+
|
|
+ if (!defel->defname)
|
|
+ {
|
|
+ relselabel = sepgsqlInputGivenSecLabel(defel);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
/* Now build and insert the tuple */
|
|
- InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions);
|
|
+ InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
|
|
+ reloptions, relselabel);
|
|
}
|
|
|
|
|
|
@@ -794,7 +873,8 @@ heap_create_with_catalog(const char *rel
|
|
int oidinhcount,
|
|
OnCommitAction oncommit,
|
|
Datum reloptions,
|
|
- bool allow_system_table_mods)
|
|
+ bool allow_system_table_mods,
|
|
+ List *selblList)
|
|
{
|
|
Relation pg_class_desc;
|
|
Relation new_rel_desc;
|
|
@@ -968,13 +1048,20 @@ heap_create_with_catalog(const char *rel
|
|
new_type_oid,
|
|
ownerid,
|
|
relkind,
|
|
- reloptions);
|
|
+ reloptions,
|
|
+ selblList);
|
|
|
|
/*
|
|
* now add tuples to pg_attribute for the attributes in our new relation.
|
|
*/
|
|
AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind,
|
|
- oidislocal, oidinhcount);
|
|
+ oidislocal, oidinhcount, selblList);
|
|
+
|
|
+ /*
|
|
+ * Fixup rel->rd_att->tdhassecacl and rel->rd_att->tdhasseclabel
|
|
+ */
|
|
+ new_rel_desc->rd_att->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(new_rel_desc);
|
|
|
|
/*
|
|
* Make a dependency link to force the relation to be deleted if its
|
|
diff -rpNU3 base/src/backend/catalog/index.c sepgsql-new/src/backend/catalog/index.c
|
|
--- base/src/backend/catalog/index.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql-new/src/backend/catalog/index.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -37,6 +37,7 @@
|
|
#include "catalog/pg_constraint.h"
|
|
#include "catalog/pg_operator.h"
|
|
#include "catalog/pg_opclass.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_tablespace.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "commands/tablecmds.h"
|
|
@@ -315,6 +316,7 @@ AppendAttributeTuples(Relation indexRela
|
|
|
|
new_tuple = heap_addheader(Natts_pg_attribute,
|
|
false,
|
|
+ RelationGetDescr(pg_attribute)->tdhasseclabel,
|
|
ATTRIBUTE_TUPLE_SIZE,
|
|
(void *) indexTupDesc->attrs[i]);
|
|
|
|
@@ -602,6 +604,12 @@ index_create(Oid heapRelationId,
|
|
Assert(indexRelationId == RelationGetRelid(indexRelation));
|
|
|
|
/*
|
|
+ * Fixup rel->rd_att->tdhassecXXX
|
|
+ */
|
|
+ indexRelation->rd_att->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(indexRelation);
|
|
+
|
|
+ /*
|
|
* Obtain exclusive lock on it. Although no other backends can see it
|
|
* until we commit, this prevents deadlock-risk complaints from lock
|
|
* manager in cases such as CLUSTER.
|
|
@@ -624,7 +632,7 @@ index_create(Oid heapRelationId,
|
|
*/
|
|
InsertPgClassTuple(pg_class, indexRelation,
|
|
RelationGetRelid(indexRelation),
|
|
- reloptions);
|
|
+ reloptions, InvalidOid);
|
|
|
|
/* done with pg_class */
|
|
heap_close(pg_class, RowExclusiveLock);
|
|
diff -rpNU3 base/src/backend/catalog/pg_aggregate.c sepgsql-new/src/backend/catalog/pg_aggregate.c
|
|
--- base/src/backend/catalog/pg_aggregate.c 2008-01-14 22:59:48.000000000 +0900
|
|
+++ sepgsql-new/src/backend/catalog/pg_aggregate.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -214,7 +214,8 @@ AggregateCreate(const char *aggName,
|
|
PointerGetDatum(NULL), /* parameterNames */
|
|
PointerGetDatum(NULL), /* proconfig */
|
|
1, /* procost */
|
|
- 0); /* prorows */
|
|
+ 0, /* prorows */
|
|
+ InvalidOid); /* proseclabel */
|
|
|
|
/*
|
|
* Okay to create the pg_aggregate entry.
|
|
diff -rpNU3 base/src/backend/catalog/pg_largeobject.c sepgsql-new/src/backend/catalog/pg_largeobject.c
|
|
--- base/src/backend/catalog/pg_largeobject.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/catalog/pg_largeobject.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -18,6 +18,7 @@
|
|
#include "access/heapam.h"
|
|
#include "catalog/indexing.h"
|
|
#include "catalog/pg_largeobject.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
|
|
@@ -91,6 +92,8 @@ LargeObjectDrop(Oid loid)
|
|
|
|
while ((tuple = systable_getnext(sd)) != NULL)
|
|
{
|
|
+ if (!found)
|
|
+ sepgsqlCheckBlobDrop(tuple);
|
|
simple_heap_delete(pg_largeobject, &tuple->t_self);
|
|
found = true;
|
|
}
|
|
diff -rpNU3 base/src/backend/catalog/pg_proc.c sepgsql-new/src/backend/catalog/pg_proc.c
|
|
--- base/src/backend/catalog/pg_proc.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/catalog/pg_proc.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -27,6 +27,7 @@
|
|
#include "mb/pg_wchar.h"
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_type.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "tcop/pquery.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/acl.h"
|
|
@@ -74,7 +75,8 @@ ProcedureCreate(const char *procedureNam
|
|
Datum parameterNames,
|
|
Datum proconfig,
|
|
float4 procost,
|
|
- float4 prorows)
|
|
+ float4 prorows,
|
|
+ Oid proselabel)
|
|
{
|
|
Oid retval;
|
|
int parameterCount;
|
|
@@ -339,6 +341,13 @@ ProcedureCreate(const char *procedureNam
|
|
|
|
/* Okay, do it... */
|
|
tup = heap_modifytuple(oldtup, tupDesc, values, nulls, replaces);
|
|
+ if (OidIsValid(proselabel))
|
|
+ {
|
|
+ if (!HeapTupleHasSecLabel(tup))
|
|
+ elog(ERROR, "Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(rel));
|
|
+ HeapTupleSetSecLabel(tup, proselabel);
|
|
+ }
|
|
simple_heap_update(rel, &tup->t_self, tup);
|
|
|
|
ReleaseSysCache(oldtup);
|
|
@@ -348,6 +357,13 @@ ProcedureCreate(const char *procedureNam
|
|
{
|
|
/* Creating a new procedure */
|
|
tup = heap_formtuple(tupDesc, values, nulls);
|
|
+ if (OidIsValid(proselabel))
|
|
+ {
|
|
+ if (!HeapTupleHasSecLabel(tup))
|
|
+ elog(ERROR, "Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(rel));
|
|
+ HeapTupleSetSecLabel(tup, proselabel);
|
|
+ }
|
|
simple_heap_insert(rel, tup);
|
|
is_update = false;
|
|
}
|
|
diff -rpNU3 base/src/backend/catalog/pg_security.c sepgsql-new/src/backend/catalog/pg_security.c
|
|
--- base/src/backend/catalog/pg_security.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/catalog/pg_security.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,290 @@
|
|
+/*
|
|
+ * src/backend/catalog/pg_security.c
|
|
+ * routines to support security label management
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/heapam.h"
|
|
+#include "access/xact.h"
|
|
+#include "catalog/catalog.h"
|
|
+#include "catalog/indexing.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "miscadmin.h"
|
|
+#include "security/sepgsql.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/memutils.h"
|
|
+#include "utils/rel.h"
|
|
+#include "utils/syscache.h"
|
|
+
|
|
+bool
|
|
+securityTupleDescHasSecLabel(Relation rel)
|
|
+{
|
|
+ return sepgsqlTupleDescHasSecLabel(rel);
|
|
+}
|
|
+
|
|
+static char *
|
|
+securityMetaSecurityLabel(void)
|
|
+{
|
|
+ return sepgsqlMetaSecurityLabel();
|
|
+}
|
|
+
|
|
+typedef struct earlySecLabel
|
|
+{
|
|
+ struct earlySecLabel *next;
|
|
+ Oid secid;
|
|
+ char seclabel[1];
|
|
+} earlySecLabel;
|
|
+
|
|
+static earlySecLabel *earlySecLabelList = NULL;
|
|
+
|
|
+static Oid
|
|
+earlyLookupSecurityId(const char *seclabel)
|
|
+{
|
|
+ earlySecLabel *es;
|
|
+ Oid minsecid = SecurityRelationId;
|
|
+
|
|
+ for (es = earlySecLabelList; es; es = es->next)
|
|
+ {
|
|
+ if (strcmp(seclabel, es->seclabel) == 0)
|
|
+ return es->secid;
|
|
+ if (es->secid < minsecid)
|
|
+ minsecid = es->secid;
|
|
+ }
|
|
+
|
|
+ /* not found */
|
|
+ es = MemoryContextAllocZero(TopMemoryContext,
|
|
+ sizeof(*es) + strlen(seclabel));
|
|
+ es->next = earlySecLabelList;
|
|
+ es->secid = minsecid - 1;
|
|
+ strcpy(es->seclabel, seclabel);
|
|
+ earlySecLabelList = es;
|
|
+
|
|
+ return es->secid;
|
|
+}
|
|
+
|
|
+static char *
|
|
+earlyLookupSecurityLabel(Oid secid)
|
|
+{
|
|
+ earlySecLabel *es;
|
|
+
|
|
+ for (es = earlySecLabelList; es; es = es->next)
|
|
+ {
|
|
+ if (es->secid == secid)
|
|
+ return pstrdup(es->seclabel);
|
|
+ }
|
|
+
|
|
+ return NULL; /* not found */
|
|
+}
|
|
+
|
|
+void
|
|
+securityPostBootstrapingMode(void)
|
|
+{
|
|
+ Relation rel;
|
|
+ CatalogIndexState ind;
|
|
+ HeapTuple tuple;
|
|
+ earlySecLabel *es;
|
|
+ Oid labelSid;
|
|
+ Datum values[Natts_pg_security];
|
|
+ bool nulls[Natts_pg_security];
|
|
+ char *meta_label;
|
|
+
|
|
+ if (!earlySecLabelList)
|
|
+ return; /* do nothing */
|
|
+
|
|
+ StartTransactionCommand();
|
|
+
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+ ind = CatalogOpenIndexes(rel);
|
|
+
|
|
+ if (RelationGetDescr(rel)->tdhasseclabel &&
|
|
+ (meta_label = securityMetaSecurityLabel()) != NULL)
|
|
+ labelSid = earlyLookupSecurityId(meta_label);
|
|
+ else
|
|
+ labelSid = InvalidOid;
|
|
+
|
|
+ for (es = earlySecLabelList; es; es = es->next)
|
|
+ {
|
|
+ memset(nulls, false, sizeof(nulls));
|
|
+
|
|
+ values[Anum_pg_security_seclabel - 1]
|
|
+ = CStringGetTextDatum(es->seclabel);
|
|
+
|
|
+ tuple = heap_form_tuple(RelationGetDescr(rel),
|
|
+ values, nulls);
|
|
+ HeapTupleSetOid(tuple, es->secid);
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, labelSid);
|
|
+
|
|
+ simple_heap_insert(rel, tuple);
|
|
+ CatalogIndexInsert(ind, tuple);
|
|
+
|
|
+ heap_freetuple(tuple);
|
|
+ }
|
|
+
|
|
+ CatalogCloseIndexes(ind);
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+
|
|
+ CommitTransactionCommand();
|
|
+}
|
|
+
|
|
+Oid
|
|
+securityLookupSecurityId(const char *seclabel)
|
|
+{
|
|
+ Relation rel;
|
|
+ CatalogIndexState ind;
|
|
+ HeapTuple tuple;
|
|
+ Oid labelOid;
|
|
+ Oid labelSid;
|
|
+ Datum values[Natts_pg_security];
|
|
+ bool nulls[Natts_pg_security];
|
|
+ char *meta_label;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ return earlyLookupSecurityId(seclabel);
|
|
+
|
|
+ /*
|
|
+ * lookup syscache at first
|
|
+ */
|
|
+ tuple = SearchSysCache(SECURITYLABEL,
|
|
+ CStringGetTextDatum(seclabel),
|
|
+ 0, 0, 0);
|
|
+ if (HeapTupleIsValid(tuple))
|
|
+ {
|
|
+ labelOid = HeapTupleGetOid(tuple);
|
|
+ ReleaseSysCache(tuple);
|
|
+ return labelOid;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Not found, insert a new one into pg_security
|
|
+ */
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+
|
|
+ ind = CatalogOpenIndexes(rel);
|
|
+
|
|
+ if (RelationGetDescr(rel)->tdhasseclabel &&
|
|
+ (meta_label = securityMetaSecurityLabel()) != NULL)
|
|
+ {
|
|
+ if (strcmp(seclabel, meta_label) == 0)
|
|
+ {
|
|
+ labelOid = labelSid = GetNewOid(rel);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ labelOid = GetNewOid(rel);
|
|
+ labelSid = securityLookupSecurityId(meta_label);
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ labelOid = GetNewOid(rel);
|
|
+ labelSid = InvalidOid;
|
|
+ }
|
|
+
|
|
+ memset(nulls, false, sizeof(nulls));
|
|
+ values[Anum_pg_security_seclabel - 1]
|
|
+ = CStringGetTextDatum(seclabel);
|
|
+
|
|
+ tuple = heap_form_tuple(RelationGetDescr(rel),
|
|
+ values, nulls);
|
|
+
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, labelSid);
|
|
+ HeapTupleSetOid(tuple, labelOid);
|
|
+
|
|
+ simple_heap_insert(rel, tuple);
|
|
+ CatalogIndexInsert(ind, tuple);
|
|
+
|
|
+ /*
|
|
+ * NOTE:
|
|
+ * We also have to insert a cache entry of new tuple of
|
|
+ * pg_security for temporary usage.
|
|
+ * If user tries to apply same security attribute twice
|
|
+ * or more within same command id, PGACE cannot decide
|
|
+ * whether it should be inserted, or not, because it
|
|
+ * cannot scan the prior one with SnapshotNow.
|
|
+ *
|
|
+ * A cache entry inserted will be invalidated on the
|
|
+ * next CommandIdIncrement().
|
|
+ * The purpose of InsertSysCache() here is to prevent
|
|
+ * duplicate insertion
|
|
+ */
|
|
+ InsertSysCache(RelationGetRelid(rel), tuple);
|
|
+
|
|
+ CatalogCloseIndexes(ind);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+
|
|
+ return labelOid;
|
|
+}
|
|
+
|
|
+char *
|
|
+securityLookupSecurityLabel(Oid secid)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ Datum labelTxt;
|
|
+ char *label;
|
|
+ bool isnull;
|
|
+
|
|
+ if (!OidIsValid(secid))
|
|
+ return NULL;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ return earlyLookupSecurityLabel(secid);
|
|
+
|
|
+ tuple = SearchSysCache(SECURITYOID,
|
|
+ ObjectIdGetDatum(secid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ return NULL;
|
|
+
|
|
+ labelTxt = SysCacheGetAttr(SECURITYOID, tuple,
|
|
+ Anum_pg_security_seclabel,
|
|
+ &isnull);
|
|
+ Assert(!isnull);
|
|
+ label = TextDatumGetCString(labelTxt);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return label;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * "security_label" system column related stuffs
|
|
+ */
|
|
+Oid
|
|
+securityTransSecLabelIn(char *seclabel)
|
|
+{
|
|
+ char *rawlabel = sepgsqlSecurityLabelTransIn(seclabel);
|
|
+
|
|
+ if (!sepgsqlCheckValidSecurityLabel(rawlabel))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("invalid security label: %s", rawlabel)));
|
|
+
|
|
+ return securityLookupSecurityId(rawlabel);
|
|
+}
|
|
+
|
|
+char *
|
|
+securityTransSecLabelOut(Oid secid)
|
|
+{
|
|
+ char *rawlabel = securityLookupSecurityLabel(secid);
|
|
+
|
|
+ if (!rawlabel || !sepgsqlCheckValidSecurityLabel(rawlabel))
|
|
+ rawlabel = sepgsqlGetUnlabeledLabel();
|
|
+
|
|
+ if (!rawlabel)
|
|
+ rawlabel = pstrdup("unlabeled");
|
|
+
|
|
+ return sepgsqlSecurityLabelTransOut(rawlabel);
|
|
+}
|
|
+
|
|
+Datum
|
|
+securityHeapGetSecLabelSysattr(HeapTuple tuple)
|
|
+{
|
|
+ Oid secid = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ return CStringGetTextDatum(securityTransSecLabelOut(secid));
|
|
+}
|
|
diff -rpNU3 base/src/backend/catalog/toasting.c sepgsql-new/src/backend/catalog/toasting.c
|
|
--- base/src/backend/catalog/toasting.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/catalog/toasting.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -199,7 +199,8 @@ create_toast_table(Relation rel, Oid toa
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
(Datum) 0,
|
|
- true);
|
|
+ true,
|
|
+ NIL);
|
|
|
|
/* make the toast relation visible, else index creation will fail */
|
|
CommandCounterIncrement();
|
|
diff -rpNU3 base/src/backend/commands/cluster.c sepgsql-new/src/backend/commands/cluster.c
|
|
--- base/src/backend/commands/cluster.c 2008-02-03 01:11:28.000000000 +0900
|
|
+++ sepgsql-new/src/backend/commands/cluster.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -34,6 +34,7 @@
|
|
#include "commands/trigger.h"
|
|
#include "commands/vacuum.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/procarray.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/fmgroids.h"
|
|
@@ -666,7 +667,8 @@ make_new_heap(Oid OIDOldHeap, const char
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
reloptions,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ NIL);
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
@@ -856,6 +858,9 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOl
|
|
/* Preserve OID, if any */
|
|
if (NewHeap->rd_rel->relhasoids)
|
|
HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple));
|
|
+ /* Preserve SecLabel, if any */
|
|
+ if (HeapTupleHasSecLabel(copiedTuple))
|
|
+ HeapTupleSetSecLabel(copiedTuple, HeapTupleGetSecLabel(tuple));
|
|
|
|
/* The heap rewrite module does the rest */
|
|
rewrite_heap_tuple(rwstate, tuple, copiedTuple);
|
|
diff -rpNU3 base/src/backend/commands/copy.c sepgsql-new/src/backend/commands/copy.c
|
|
--- base/src/backend/commands/copy.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/commands/copy.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -22,7 +22,9 @@
|
|
|
|
#include "access/heapam.h"
|
|
#include "access/xact.h"
|
|
+#include "catalog/heap.h"
|
|
#include "catalog/namespace.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "commands/copy.h"
|
|
#include "commands/trigger.h"
|
|
@@ -34,6 +36,8 @@
|
|
#include "optimizer/planner.h"
|
|
#include "parser/parse_relation.h"
|
|
#include "rewrite/rewriteHandler.h"
|
|
+#include "security/rowlevel.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/fd.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/acl.h"
|
|
@@ -159,6 +163,10 @@ typedef struct CopyStateData
|
|
char *raw_buf;
|
|
int raw_buf_index; /* next byte to process */
|
|
int raw_buf_len; /* total # of bytes stored */
|
|
+
|
|
+ /* dump/restore support for security_label */
|
|
+ FmgrInfo seclabel_out_function;
|
|
+ bool seclabel_force_quot;
|
|
} CopyStateData;
|
|
|
|
typedef CopyStateData *CopyState;
|
|
@@ -242,7 +250,7 @@ static const char BinarySignature[11] =
|
|
/* non-export function prototypes */
|
|
static void DoCopyTo(CopyState cstate);
|
|
static void CopyTo(CopyState cstate);
|
|
-static void CopyOneRowTo(CopyState cstate, Oid tupleOid,
|
|
+static void CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid secLabelId,
|
|
Datum *values, bool *nulls);
|
|
static void CopyFrom(CopyState cstate);
|
|
static bool CopyReadLine(CopyState cstate);
|
|
@@ -1073,6 +1081,9 @@ DoCopy(const CopyStmt *stmt, const char
|
|
/* Generate or convert list of attributes to process */
|
|
cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
|
|
|
|
+ /* SELinux checks table/column level permissions */
|
|
+ sepgsqlCheckCopyTable(cstate->rel, cstate->attnumlist, is_from);
|
|
+
|
|
num_phys_attrs = tupDesc->natts;
|
|
|
|
/* Convert FORCE QUOTE name list to per-column flags, check validity */
|
|
@@ -1089,11 +1100,32 @@ DoCopy(const CopyStmt *stmt, const char
|
|
int attnum = lfirst_int(cur);
|
|
|
|
if (!list_member_int(cstate->attnumlist, attnum))
|
|
+ {
|
|
+ Form_pg_attribute attForm;
|
|
+
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ attForm = SystemAttributeDefinition(attnum, true);
|
|
+ else
|
|
+ attForm = tupDesc->attrs[attnum - 1];
|
|
+
|
|
+ Assert(attForm != NULL);
|
|
+
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
errmsg("FORCE QUOTE column \"%s\" not referenced by COPY",
|
|
- NameStr(tupDesc->attrs[attnum - 1]->attname))));
|
|
- cstate->force_quote_flags[attnum - 1] = true;
|
|
+ NameStr(attForm->attname))));
|
|
+ }
|
|
+
|
|
+ switch (attnum)
|
|
+ {
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ cstate->seclabel_force_quot = true;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ cstate->force_quote_flags[attnum - 1] = true;
|
|
+ break;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -1111,10 +1143,23 @@ DoCopy(const CopyStmt *stmt, const char
|
|
int attnum = lfirst_int(cur);
|
|
|
|
if (!list_member_int(cstate->attnumlist, attnum))
|
|
+ {
|
|
+ Form_pg_attribute attForm;
|
|
+
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ attForm = SystemAttributeDefinition(attnum, true);
|
|
+ else
|
|
+ attForm = tupDesc->attrs[attnum - 1];
|
|
+
|
|
+ Assert(attForm != NULL);
|
|
+
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY",
|
|
- NameStr(tupDesc->attrs[attnum - 1]->attname))));
|
|
+ NameStr(attForm->attname))));
|
|
+ }
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ continue; /* ignore, if specified */
|
|
cstate->force_notnull_flags[attnum - 1] = true;
|
|
}
|
|
}
|
|
@@ -1242,6 +1287,9 @@ DoCopyTo(CopyState cstate)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
errmsg("\"%s\" is a directory", cstate->filename)));
|
|
+
|
|
+ /* SELinux: check file:{write} permission */
|
|
+ sepgsqlCheckFileWrite(fileno(cstate->copy_file), cstate->filename);
|
|
}
|
|
|
|
PG_TRY();
|
|
@@ -1305,16 +1353,31 @@ CopyTo(CopyState cstate)
|
|
int attnum = lfirst_int(cur);
|
|
Oid out_func_oid;
|
|
bool isvarlena;
|
|
+ FmgrInfo *out_fmgr;
|
|
+ Form_pg_attribute attForm;
|
|
+
|
|
+ switch (attnum)
|
|
+ {
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ attForm = SystemAttributeDefinition(attnum, true);
|
|
+ out_fmgr = &cstate->seclabel_out_function;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ attForm = attr[attnum - 1];
|
|
+ out_fmgr = &cstate->out_functions[attnum - 1];
|
|
+ break;
|
|
+ }
|
|
|
|
if (cstate->binary)
|
|
- getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid,
|
|
+ getTypeBinaryOutputInfo(attForm->atttypid,
|
|
&out_func_oid,
|
|
&isvarlena);
|
|
else
|
|
- getTypeOutputInfo(attr[attnum - 1]->atttypid,
|
|
+ getTypeOutputInfo(attForm->atttypid,
|
|
&out_func_oid,
|
|
&isvarlena);
|
|
- fmgr_info(out_func_oid, &cstate->out_functions[attnum - 1]);
|
|
+ fmgr_info(out_func_oid, out_fmgr);
|
|
}
|
|
|
|
/*
|
|
@@ -1369,7 +1432,14 @@ CopyTo(CopyState cstate)
|
|
CopySendChar(cstate, cstate->delim[0]);
|
|
hdr_delim = true;
|
|
|
|
- colname = NameStr(attr[attnum - 1]->attname);
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ {
|
|
+ Form_pg_attribute attForm
|
|
+ = SystemAttributeDefinition(attnum, true);
|
|
+ colname = NameStr(attForm->attname);
|
|
+ }
|
|
+ else
|
|
+ colname = NameStr(attr[attnum - 1]->attname);
|
|
|
|
CopyAttributeOutCSV(cstate, colname, false,
|
|
list_length(cstate->attnumlist) == 1);
|
|
@@ -1395,11 +1465,18 @@ CopyTo(CopyState cstate)
|
|
{
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
+ /* Row-level controls on the fetched tuple */
|
|
+ if (!rowlvCopyToTuple(cstate->rel, tuple))
|
|
+ continue;
|
|
+
|
|
/* Deconstruct the tuple ... faster than repeated heap_getattr */
|
|
heap_deform_tuple(tuple, tupDesc, values, nulls);
|
|
|
|
/* Format and send the data */
|
|
- CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls);
|
|
+ CopyOneRowTo(cstate,
|
|
+ HeapTupleGetOid(tuple),
|
|
+ HeapTupleGetSecLabel(tuple),
|
|
+ values, nulls);
|
|
}
|
|
|
|
heap_endscan(scandesc);
|
|
@@ -1425,7 +1502,7 @@ CopyTo(CopyState cstate)
|
|
* Emit one row during CopyTo().
|
|
*/
|
|
static void
|
|
-CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls)
|
|
+CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid secLabelId, Datum *values, bool *nulls)
|
|
{
|
|
bool need_delim = false;
|
|
FmgrInfo *out_functions = cstate->out_functions;
|
|
@@ -1464,8 +1541,10 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
foreach(cur, cstate->attnumlist)
|
|
{
|
|
int attnum = lfirst_int(cur);
|
|
- Datum value = values[attnum - 1];
|
|
- bool isnull = nulls[attnum - 1];
|
|
+ Datum value;
|
|
+ bool isnull;
|
|
+ bool force_quot;
|
|
+ FmgrInfo *out_fmgr;
|
|
|
|
if (!cstate->binary)
|
|
{
|
|
@@ -1474,6 +1553,23 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
need_delim = true;
|
|
}
|
|
|
|
+ switch (attnum)
|
|
+ {
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ value = CStringGetTextDatum(securityTransSecLabelOut(secLabelId));
|
|
+ isnull = false;
|
|
+ force_quot = cstate->seclabel_force_quot;
|
|
+ out_fmgr = &cstate->seclabel_out_function;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ value = values[attnum - 1];
|
|
+ isnull = nulls[attnum - 1];
|
|
+ force_quot = cstate->force_quote_flags[attnum - 1];
|
|
+ out_fmgr = &out_functions[attnum - 1];
|
|
+ break;
|
|
+ }
|
|
+
|
|
if (isnull)
|
|
{
|
|
if (!cstate->binary)
|
|
@@ -1485,11 +1581,9 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
{
|
|
if (!cstate->binary)
|
|
{
|
|
- string = OutputFunctionCall(&out_functions[attnum - 1],
|
|
- value);
|
|
+ string = OutputFunctionCall(out_fmgr, value);
|
|
if (cstate->csv_mode)
|
|
- CopyAttributeOutCSV(cstate, string,
|
|
- cstate->force_quote_flags[attnum - 1],
|
|
+ CopyAttributeOutCSV(cstate, string, force_quot,
|
|
list_length(cstate->attnumlist) == 1);
|
|
else
|
|
CopyAttributeOutText(cstate, string);
|
|
@@ -1498,8 +1592,7 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
{
|
|
bytea *outputbytes;
|
|
|
|
- outputbytes = SendFunctionCall(&out_functions[attnum - 1],
|
|
- value);
|
|
+ outputbytes = SendFunctionCall(out_fmgr, value);
|
|
CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);
|
|
CopySendData(cstate, VARDATA(outputbytes),
|
|
VARSIZE(outputbytes) - VARHDRSZ);
|
|
@@ -1633,8 +1726,10 @@ CopyFrom(CopyState cstate)
|
|
num_defaults;
|
|
FmgrInfo *in_functions;
|
|
FmgrInfo oid_in_function;
|
|
+ FmgrInfo seclabel_in_function;
|
|
Oid *typioparams;
|
|
Oid oid_typioparam;
|
|
+ Oid seclabel_typioparam;
|
|
int attnum;
|
|
int i;
|
|
Oid in_func_oid;
|
|
@@ -1737,6 +1832,9 @@ CopyFrom(CopyState cstate)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
errmsg("\"%s\" is a directory", cstate->filename)));
|
|
+
|
|
+ /* SELinux checks file:{read} permission */
|
|
+ sepgsqlCheckFileRead(fileno(cstate->copy_file), cstate->filename);
|
|
}
|
|
|
|
tupDesc = RelationGetDescr(cstate->rel);
|
|
@@ -1872,6 +1970,18 @@ CopyFrom(CopyState cstate)
|
|
fmgr_info(in_func_oid, &oid_in_function);
|
|
}
|
|
|
|
+ if (list_member_int(cstate->attnumlist,
|
|
+ SecurityLabelAttributeNumber))
|
|
+ {
|
|
+ if (!cstate->binary)
|
|
+ getTypeInputInfo(TEXTOID,
|
|
+ &in_func_oid, &seclabel_typioparam);
|
|
+ else
|
|
+ getTypeBinaryInputInfo(TEXTOID,
|
|
+ &in_func_oid, &seclabel_typioparam);
|
|
+ fmgr_info(in_func_oid, &seclabel_in_function);
|
|
+ }
|
|
+
|
|
values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
|
|
nulls = (char *) palloc(num_phys_attrs * sizeof(char));
|
|
|
|
@@ -1904,6 +2014,7 @@ CopyFrom(CopyState cstate)
|
|
{
|
|
bool skip_tuple;
|
|
Oid loaded_oid = InvalidOid;
|
|
+ Oid loaded_seclabel = InvalidOid;
|
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
@@ -1975,31 +2086,55 @@ CopyFrom(CopyState cstate)
|
|
/* Loop to read the user attributes on the line. */
|
|
foreach(cur, cstate->attnumlist)
|
|
{
|
|
+ Form_pg_attribute attForm;
|
|
+ Datum dat;
|
|
int attnum = lfirst_int(cur);
|
|
int m = attnum - 1;
|
|
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ attForm = SystemAttributeDefinition(attnum, true);
|
|
+ else
|
|
+ attForm = attr[m];
|
|
+
|
|
if (fieldno >= fldct)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
|
errmsg("missing data for column \"%s\"",
|
|
- NameStr(attr[m]->attname))));
|
|
+ NameStr(attForm->attname))));
|
|
string = field_strings[fieldno++];
|
|
|
|
- if (cstate->csv_mode && string == NULL &&
|
|
- cstate->force_notnull_flags[m])
|
|
+ cstate->cur_attname = NameStr(attForm->attname);
|
|
+ cstate->cur_attval = string;
|
|
+
|
|
+ switch (attnum)
|
|
{
|
|
- /* Go ahead and read the NULL string */
|
|
- string = cstate->null_print;
|
|
- }
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ if (!string)
|
|
+ break;
|
|
|
|
- cstate->cur_attname = NameStr(attr[m]->attname);
|
|
- cstate->cur_attval = string;
|
|
- values[m] = InputFunctionCall(&in_functions[m],
|
|
- string,
|
|
- typioparams[m],
|
|
- attr[m]->atttypmod);
|
|
- if (string != NULL)
|
|
- nulls[m] = ' ';
|
|
+ dat = InputFunctionCall(&seclabel_in_function,
|
|
+ string,
|
|
+ seclabel_typioparam,
|
|
+ attForm->atttypmod);
|
|
+ loaded_seclabel
|
|
+ = securityTransSecLabelIn(TextDatumGetCString(dat));
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ if (cstate->csv_mode && string == NULL &&
|
|
+ cstate->force_notnull_flags[m])
|
|
+ {
|
|
+ /* Go ahead and read the NULL string */
|
|
+ string = cstate->null_print;
|
|
+ }
|
|
+
|
|
+ values[m] = InputFunctionCall(&in_functions[m],
|
|
+ string,
|
|
+ typioparams[m],
|
|
+ attForm->atttypmod);
|
|
+ if (string != NULL)
|
|
+ nulls[m] = ' ';
|
|
+ }
|
|
cstate->cur_attname = NULL;
|
|
cstate->cur_attval = NULL;
|
|
}
|
|
@@ -2045,18 +2180,41 @@ CopyFrom(CopyState cstate)
|
|
i = 0;
|
|
foreach(cur, cstate->attnumlist)
|
|
{
|
|
+ Form_pg_attribute attForm;
|
|
+ Datum dat;
|
|
int attnum = lfirst_int(cur);
|
|
int m = attnum - 1;
|
|
|
|
- cstate->cur_attname = NameStr(attr[m]->attname);
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ attForm = SystemAttributeDefinition(attnum, false);
|
|
+ else
|
|
+ attForm = attr[m];
|
|
+
|
|
+ cstate->cur_attname = NameStr(attForm->attname);
|
|
i++;
|
|
- values[m] = CopyReadBinaryAttribute(cstate,
|
|
- i,
|
|
- &in_functions[m],
|
|
- typioparams[m],
|
|
- attr[m]->atttypmod,
|
|
- &isnull);
|
|
- nulls[m] = isnull ? 'n' : ' ';
|
|
+
|
|
+ switch (attnum)
|
|
+ {
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ dat = CopyReadBinaryAttribute(cstate, i,
|
|
+ &seclabel_in_function,
|
|
+ seclabel_typioparam,
|
|
+ attForm->atttypmod,
|
|
+ &isnull);
|
|
+ if (!isnull)
|
|
+ loaded_seclabel
|
|
+ = securityTransSecLabelIn(TextDatumGetCString(dat));
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ values[m] = CopyReadBinaryAttribute(cstate, i,
|
|
+ &in_functions[m],
|
|
+ typioparams[m],
|
|
+ attr[m]->atttypmod,
|
|
+ &isnull);
|
|
+ nulls[m] = isnull ? 'n' : ' ';
|
|
+ break;
|
|
+ }
|
|
cstate->cur_attname = NULL;
|
|
}
|
|
}
|
|
@@ -2080,6 +2238,9 @@ CopyFrom(CopyState cstate)
|
|
if (cstate->oids && file_has_oids)
|
|
HeapTupleSetOid(tuple, loaded_oid);
|
|
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, loaded_seclabel);
|
|
+
|
|
/* Triggers and stuff need to be invoked in query context. */
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
@@ -2102,6 +2263,9 @@ CopyFrom(CopyState cstate)
|
|
}
|
|
}
|
|
|
|
+ if (!skip_tuple && !rowlvHeapTupleInsert(cstate->rel, tuple, false))
|
|
+ skip_tuple = true;
|
|
+
|
|
if (!skip_tuple)
|
|
{
|
|
/* Place tuple in tuple slot */
|
|
@@ -3366,6 +3530,13 @@ CopyGetAttnums(TupleDesc tupDesc, Relati
|
|
}
|
|
if (attnum == InvalidAttrNumber)
|
|
{
|
|
+ Form_pg_attribute attForm
|
|
+ = SystemAttributeByName(name, tupDesc->tdhasoid);
|
|
+ if (attForm && SystemAttributeIsWritable(attForm->attnum))
|
|
+ attnum = attForm->attnum;
|
|
+ }
|
|
+ if (attnum == InvalidAttrNumber)
|
|
+ {
|
|
if (rel != NULL)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
@@ -3413,7 +3584,8 @@ copy_dest_receive(TupleTableSlot *slot,
|
|
slot_getallattrs(slot);
|
|
|
|
/* And send the data */
|
|
- CopyOneRowTo(cstate, InvalidOid, slot->tts_values, slot->tts_isnull);
|
|
+ CopyOneRowTo(cstate, InvalidOid, InvalidOid,
|
|
+ slot->tts_values, slot->tts_isnull);
|
|
}
|
|
|
|
/*
|
|
diff -rpNU3 base/src/backend/commands/dbcommands.c sepgsql-new/src/backend/commands/dbcommands.c
|
|
--- base/src/backend/commands/dbcommands.c 2008-11-05 09:57:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/commands/dbcommands.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -40,6 +40,7 @@
|
|
#include "miscadmin.h"
|
|
#include "pgstat.h"
|
|
#include "postmaster/bgwriter.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/freespace.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/procarray.h"
|
|
@@ -100,6 +101,7 @@ createdb(const CreatedbStmt *stmt)
|
|
DefElem *dtemplate = NULL;
|
|
DefElem *dencoding = NULL;
|
|
DefElem *dconnlimit = NULL;
|
|
+ DefElem *dselabel = NULL;
|
|
char *dbname = stmt->dbname;
|
|
char *dbowner = NULL;
|
|
const char *dbtemplate = NULL;
|
|
@@ -160,6 +162,14 @@ createdb(const CreatedbStmt *stmt)
|
|
errmsg("LOCATION is not supported anymore"),
|
|
errhint("Consider using tablespaces instead.")));
|
|
}
|
|
+ else if (strcmp(defel->defname, "security_context") == 0)
|
|
+ {
|
|
+ if (dselabel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ dselabel = defel;
|
|
+ }
|
|
else
|
|
elog(ERROR, "option \"%s\" not recognized",
|
|
defel->defname);
|
|
@@ -433,7 +443,15 @@ createdb(const CreatedbStmt *stmt)
|
|
new_record, new_record_nulls);
|
|
|
|
HeapTupleSetOid(tuple, dboid);
|
|
+ if (dselabel)
|
|
+ {
|
|
+ Oid secid = sepgsqlInputGivenSecLabel(dselabel);
|
|
|
|
+ if (!HeapTupleHasSecLabel(tuple))
|
|
+ elog(ERROR, "Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(pg_database_rel));
|
|
+ HeapTupleSetSecLabel(tuple, secid);
|
|
+ }
|
|
simple_heap_insert(pg_database_rel, tuple);
|
|
|
|
/* Update indexes */
|
|
@@ -858,6 +876,7 @@ AlterDatabase(AlterDatabaseStmt *stmt)
|
|
ListCell *option;
|
|
int connlimit = -1;
|
|
DefElem *dconnlimit = NULL;
|
|
+ DefElem *dselabel = NULL;
|
|
Datum new_record[Natts_pg_database];
|
|
char new_record_nulls[Natts_pg_database];
|
|
char new_record_repl[Natts_pg_database];
|
|
@@ -875,6 +894,14 @@ AlterDatabase(AlterDatabaseStmt *stmt)
|
|
errmsg("conflicting or redundant options")));
|
|
dconnlimit = defel;
|
|
}
|
|
+ else if (strcmp(defel->defname, "security_context") == 0)
|
|
+ {
|
|
+ if (dselabel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ dselabel = defel;
|
|
+ }
|
|
else
|
|
elog(ERROR, "option \"%s\" not recognized",
|
|
defel->defname);
|
|
@@ -920,6 +947,15 @@ AlterDatabase(AlterDatabaseStmt *stmt)
|
|
|
|
newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), new_record,
|
|
new_record_nulls, new_record_repl);
|
|
+ if (dselabel)
|
|
+ {
|
|
+ Oid secid = sepgsqlInputGivenSecLabel(dselabel);
|
|
+
|
|
+ if (!HeapTupleHasSecLabel(newtuple))
|
|
+ elog(ERROR, "Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(rel));
|
|
+ HeapTupleSetSecLabel(newtuple, secid);
|
|
+ }
|
|
simple_heap_update(rel, &tuple->t_self, newtuple);
|
|
|
|
/* Update indexes */
|
|
diff -rpNU3 base/src/backend/commands/functioncmds.c sepgsql-new/src/backend/commands/functioncmds.c
|
|
--- base/src/backend/commands/functioncmds.c 2009-03-15 17:47:25.000000000 +0900
|
|
+++ sepgsql-new/src/backend/commands/functioncmds.c 2009-03-15 17:58:10.000000000 +0900
|
|
@@ -47,6 +47,7 @@
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_func.h"
|
|
#include "parser/parse_type.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
@@ -295,7 +296,8 @@ compute_common_attribute(DefElem *defel,
|
|
DefElem **security_item,
|
|
List **set_items,
|
|
DefElem **cost_item,
|
|
- DefElem **rows_item)
|
|
+ DefElem **rows_item,
|
|
+ DefElem **selabel_item)
|
|
{
|
|
if (strcmp(defel->defname, "volatility") == 0)
|
|
{
|
|
@@ -336,6 +338,13 @@ compute_common_attribute(DefElem *defel,
|
|
|
|
*rows_item = defel;
|
|
}
|
|
+ else if (strcmp(defel->defname, "security_context") == 0)
|
|
+ {
|
|
+ if (*selabel_item)
|
|
+ goto duplicate_error;
|
|
+
|
|
+ *selabel_item = defel;
|
|
+ }
|
|
else
|
|
return false;
|
|
|
|
@@ -412,7 +421,8 @@ compute_attributes_sql_style(List *optio
|
|
bool *security_definer,
|
|
ArrayType **proconfig,
|
|
float4 *procost,
|
|
- float4 *prorows)
|
|
+ float4 *prorows,
|
|
+ Oid *proselabel)
|
|
{
|
|
ListCell *option;
|
|
DefElem *as_item = NULL;
|
|
@@ -423,6 +433,7 @@ compute_attributes_sql_style(List *optio
|
|
List *set_items = NIL;
|
|
DefElem *cost_item = NULL;
|
|
DefElem *rows_item = NULL;
|
|
+ DefElem *selabel_item = NULL;
|
|
|
|
foreach(option, options)
|
|
{
|
|
@@ -450,7 +461,8 @@ compute_attributes_sql_style(List *optio
|
|
&security_item,
|
|
&set_items,
|
|
&cost_item,
|
|
- &rows_item))
|
|
+ &rows_item,
|
|
+ &selabel_item))
|
|
{
|
|
/* recognized common option */
|
|
continue;
|
|
@@ -506,6 +518,8 @@ compute_attributes_sql_style(List *optio
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
errmsg("ROWS must be positive")));
|
|
}
|
|
+ if (selabel_item)
|
|
+ *proselabel = sepgsqlInputGivenSecLabel(selabel_item);
|
|
}
|
|
|
|
|
|
@@ -621,6 +635,7 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|
ArrayType *proconfig;
|
|
float4 procost;
|
|
float4 prorows;
|
|
+ Oid proselabel;
|
|
HeapTuple languageTuple;
|
|
Form_pg_language languageStruct;
|
|
List *as_clause;
|
|
@@ -642,12 +657,13 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|
proconfig = NULL;
|
|
procost = -1; /* indicates not set */
|
|
prorows = -1; /* indicates not set */
|
|
+ proselabel = InvalidOid; /* follows default labeling behavior */
|
|
|
|
/* override attributes from explicit list */
|
|
compute_attributes_sql_style(stmt->options,
|
|
&as_clause, &language,
|
|
&volatility, &isStrict, &security,
|
|
- &proconfig, &procost, &prorows);
|
|
+ &proconfig, &procost, &prorows, &proselabel);
|
|
|
|
/* Convert language name to canonical case */
|
|
languageName = case_translate_language_name(language);
|
|
@@ -801,7 +817,8 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|
PointerGetDatum(parameterNames),
|
|
PointerGetDatum(proconfig),
|
|
procost,
|
|
- prorows);
|
|
+ prorows,
|
|
+ proselabel);
|
|
}
|
|
|
|
|
|
@@ -1151,6 +1168,7 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|
List *set_items = NIL;
|
|
DefElem *cost_item = NULL;
|
|
DefElem *rows_item = NULL;
|
|
+ DefElem *selabel_item = NULL;
|
|
|
|
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
|
|
|
|
@@ -1188,7 +1206,8 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|
&security_def_item,
|
|
&set_items,
|
|
&cost_item,
|
|
- &rows_item) == false)
|
|
+ &rows_item,
|
|
+ &selabel_item) == false)
|
|
elog(ERROR, "option \"%s\" not recognized", defel->defname);
|
|
}
|
|
|
|
@@ -1218,7 +1237,7 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
errmsg("ROWS is not applicable when function does not return a set")));
|
|
}
|
|
- if (set_items)
|
|
+ if (set_items || selabel_item)
|
|
{
|
|
Datum datum;
|
|
bool isnull;
|
|
@@ -1227,30 +1246,42 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|
char repl_null[Natts_pg_proc];
|
|
char repl_repl[Natts_pg_proc];
|
|
|
|
- /* extract existing proconfig setting */
|
|
- datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
|
|
- a = isnull ? NULL : DatumGetArrayTypeP(datum);
|
|
-
|
|
- /* update according to each SET or RESET item, left to right */
|
|
- a = update_proconfig_value(a, set_items);
|
|
-
|
|
- /* update the tuple */
|
|
memset(repl_repl, ' ', sizeof(repl_repl));
|
|
- repl_repl[Anum_pg_proc_proconfig - 1] = 'r';
|
|
|
|
- if (a == NULL)
|
|
+ if (set_items)
|
|
{
|
|
- repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
|
|
- repl_null[Anum_pg_proc_proconfig - 1] = 'n';
|
|
+ /* extract existing proconfig setting */
|
|
+ datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
|
|
+ a = isnull ? NULL : DatumGetArrayTypeP(datum);
|
|
+
|
|
+ /* update according to each SET or RESET item, left to right */
|
|
+ a = update_proconfig_value(a, set_items);
|
|
+
|
|
+ /* update the tuple */
|
|
+ repl_repl[Anum_pg_proc_proconfig - 1] = 'r';
|
|
+
|
|
+ if (a == NULL)
|
|
+ {
|
|
+ repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
|
|
+ repl_null[Anum_pg_proc_proconfig - 1] = 'n';
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
|
|
+ repl_null[Anum_pg_proc_proconfig - 1] = ' ';
|
|
+ }
|
|
}
|
|
- else
|
|
+ tup = heap_modifytuple(tup, RelationGetDescr(rel),
|
|
+ repl_val, repl_null, repl_repl);
|
|
+ if (selabel_item)
|
|
{
|
|
- repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
|
|
- repl_null[Anum_pg_proc_proconfig - 1] = ' ';
|
|
- }
|
|
+ Oid secid = sepgsqlInputGivenSecLabel(selabel_item);
|
|
|
|
- tup = heap_modifytuple(tup, RelationGetDescr(rel),
|
|
- repl_val, repl_null, repl_repl);
|
|
+ if (!HeapTupleHasSecLabel(tup))
|
|
+ elog(ERROR, "Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(rel));
|
|
+ HeapTupleSetSecLabel(tup, secid);
|
|
+ }
|
|
}
|
|
|
|
/* Do the update */
|
|
diff -rpNU3 base/src/backend/commands/lockcmds.c sepgsql-new/src/backend/commands/lockcmds.c
|
|
--- base/src/backend/commands/lockcmds.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/commands/lockcmds.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -18,6 +18,7 @@
|
|
#include "catalog/namespace.h"
|
|
#include "commands/lockcmds.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/lsyscache.h"
|
|
|
|
@@ -55,7 +56,8 @@ LockTableCommand(LockStmt *lockstmt)
|
|
aclresult = pg_class_aclcheck(reloid, GetUserId(),
|
|
ACL_UPDATE | ACL_DELETE);
|
|
|
|
- if (aclresult != ACLCHECK_OK)
|
|
+ if (aclresult != ACLCHECK_OK ||
|
|
+ !sepgsqlCheckTableLock(reloid))
|
|
aclcheck_error(aclresult, ACL_KIND_CLASS,
|
|
get_rel_name(reloid));
|
|
|
|
diff -rpNU3 base/src/backend/commands/proclang.c sepgsql-new/src/backend/commands/proclang.c
|
|
--- base/src/backend/commands/proclang.c 2008-06-12 22:34:19.000000000 +0900
|
|
+++ sepgsql-new/src/backend/commands/proclang.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -146,7 +146,8 @@ CreateProceduralLanguage(CreatePLangStmt
|
|
PointerGetDatum(NULL),
|
|
PointerGetDatum(NULL),
|
|
1,
|
|
- 0);
|
|
+ 0,
|
|
+ InvalidOid);
|
|
}
|
|
|
|
/*
|
|
@@ -179,7 +180,8 @@ CreateProceduralLanguage(CreatePLangStmt
|
|
PointerGetDatum(NULL),
|
|
PointerGetDatum(NULL),
|
|
1,
|
|
- 0);
|
|
+ 0,
|
|
+ InvalidOid);
|
|
}
|
|
}
|
|
else
|
|
diff -rpNU3 base/src/backend/commands/tablecmds.c sepgsql-new/src/backend/commands/tablecmds.c
|
|
--- base/src/backend/commands/tablecmds.c 2008-11-05 09:57:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/commands/tablecmds.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -57,6 +57,7 @@
|
|
#include "parser/parser.h"
|
|
#include "rewrite/rewriteDefine.h"
|
|
#include "rewrite/rewriteHandler.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
@@ -259,6 +260,7 @@ static void ATExecEnableDisableRule(Rela
|
|
char fires_when);
|
|
static void ATExecAddInherit(Relation rel, RangeVar *parent);
|
|
static void ATExecDropInherit(Relation rel, RangeVar *parent);
|
|
+static void ATExecSetSecurityLabel(Relation rel, const char *name, DefElem *defel);
|
|
static void copy_relation_data(Relation rel, SMgrRelation dst);
|
|
|
|
|
|
@@ -281,6 +283,7 @@ DefineRelation(CreateStmt *stmt, char re
|
|
TupleDesc descriptor;
|
|
List *inheritOids;
|
|
List *old_constraints;
|
|
+ List *selblList;
|
|
bool localHasOids;
|
|
int parentOidCount;
|
|
List *rawDefaults;
|
|
@@ -365,6 +368,10 @@ DefineRelation(CreateStmt *stmt, char re
|
|
schema = MergeAttributes(schema, stmt->inhRelations,
|
|
stmt->relation->istemp,
|
|
&inheritOids, &old_constraints, &parentOidCount);
|
|
+ /*
|
|
+ * SELinux: fetch SECURITY_CONTEXT = '...' from CREATE TABLE statement
|
|
+ */
|
|
+ selblList = sepgsqlInputGivenSecLabelRelation(stmt);
|
|
|
|
/*
|
|
* Create a relation descriptor from the relation schema and create the
|
|
@@ -434,7 +441,8 @@ DefineRelation(CreateStmt *stmt, char re
|
|
parentOidCount,
|
|
stmt->oncommit,
|
|
reloptions,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ selblList);
|
|
|
|
StoreCatalogInheritance(relationId, inheritOids);
|
|
|
|
@@ -660,6 +668,10 @@ truncate_check_rel(Relation rel)
|
|
errmsg("permission denied: \"%s\" is a system catalog",
|
|
RelationGetRelationName(rel))));
|
|
|
|
+ if (!sepgsqlCheckTableTruncate(rel))
|
|
+ aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
|
|
+ RelationGetRelationName(rel));
|
|
+
|
|
/*
|
|
* We can never allow truncation of shared or nailed-in-cache relations,
|
|
* because we can't support changing their relfilenode values.
|
|
@@ -2031,6 +2043,7 @@ ATPrepCmd(List **wqueue, Relation rel, A
|
|
case AT_DisableRule:
|
|
case AT_AddInherit: /* INHERIT / NO INHERIT */
|
|
case AT_DropInherit:
|
|
+ case AT_SetSecurityLabel:
|
|
ATSimplePermissions(rel, false);
|
|
/* These commands never recurse */
|
|
/* No command-specific prep needed */
|
|
@@ -2253,6 +2266,9 @@ ATExecCmd(AlteredTableInfo *tab, Relatio
|
|
case AT_DropInherit:
|
|
ATExecDropInherit(rel, (RangeVar *) cmd->def);
|
|
break;
|
|
+ case AT_SetSecurityLabel:
|
|
+ ATExecSetSecurityLabel(rel, cmd->name, (DefElem *) cmd->def);
|
|
+ break;
|
|
default: /* oops */
|
|
elog(ERROR, "unrecognized alter table type: %d",
|
|
(int) cmd->subtype);
|
|
@@ -2591,11 +2607,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oi
|
|
if (newrel)
|
|
{
|
|
Oid tupOid = InvalidOid;
|
|
+ Oid tupSecLabel = InvalidOid;
|
|
|
|
/* Extract data from old tuple */
|
|
heap_deform_tuple(tuple, oldTupDesc, values, isnull);
|
|
if (oldTupDesc->tdhasoid)
|
|
tupOid = HeapTupleGetOid(tuple);
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ tupSecLabel = HeapTupleGetSecLabel(tuple);
|
|
|
|
/* Set dropped attributes to null in new tuple */
|
|
foreach(lc, dropped_attrs)
|
|
@@ -2627,6 +2646,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oi
|
|
/* Preserve OID, if any */
|
|
if (newTupDesc->tdhasoid)
|
|
HeapTupleSetOid(tuple, tupOid);
|
|
+ /* Preserve SecLabel, if any */
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, tupSecLabel);
|
|
}
|
|
|
|
/* Now check any constraints on the possibly-changed tuple */
|
|
@@ -3113,6 +3135,7 @@ ATExecAddColumn(AlteredTableInfo *tab, R
|
|
|
|
attributeTuple = heap_addheader(Natts_pg_attribute,
|
|
false,
|
|
+ RelationGetDescr(attrdesc)->tdhasseclabel,
|
|
ATTRIBUTE_TUPLE_SIZE,
|
|
(void *) &attributeD);
|
|
|
|
@@ -6515,6 +6538,95 @@ ATExecDropInherit(Relation rel, RangeVar
|
|
heap_close(parent_rel, NoLock);
|
|
}
|
|
|
|
+void
|
|
+ATExecSetSecurityLabel(Relation rel, const char *attr_name, DefElem *defel)
|
|
+{
|
|
+ Relation class_rel;
|
|
+ Relation attr_rel;
|
|
+ HeapTuple tuple, newtup;
|
|
+ Oid secid;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: disabled now")));
|
|
+
|
|
+ Assert(IsA(defel, DefElem));
|
|
+
|
|
+ if (!attr_name)
|
|
+ {
|
|
+ Datum values[Natts_pg_class];
|
|
+ bool nulls[Natts_pg_class];
|
|
+ bool replaces[Natts_pg_class];
|
|
+
|
|
+ memset(replaces, false, sizeof(replaces));
|
|
+
|
|
+ class_rel = heap_open(RelationRelationId, RowExclusiveLock);
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(RelationGetRelid(rel)),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation: \"%s\"",
|
|
+ RelationGetRelationName(rel));
|
|
+ /*
|
|
+ * NOTE: heap_modify_tuple() is necessary to make sure
|
|
+ * newtup has HEAP_HAS_SECLABEL and a field to store
|
|
+ * security lidentifier.
|
|
+ */
|
|
+ newtup = heap_modify_tuple(tuple, RelationGetDescr(class_rel),
|
|
+ values, nulls, replaces);
|
|
+ if (!HeapTupleHasSecLabel(newtup))
|
|
+ elog(ERROR, "Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(class_rel));
|
|
+
|
|
+ secid = sepgsqlInputGivenSecLabel(defel);
|
|
+ HeapTupleSetSecLabel(newtup, secid);
|
|
+
|
|
+ simple_heap_update(class_rel, &tuple->t_self, newtup);
|
|
+
|
|
+ CatalogUpdateIndexes(class_rel, newtup);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ heap_close(class_rel, RowExclusiveLock);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ Datum values[Natts_pg_attribute];
|
|
+ bool nulls[Natts_pg_attribute];
|
|
+ bool replaces[Natts_pg_attribute];
|
|
+
|
|
+ memset(replaces, false, sizeof(replaces));
|
|
+
|
|
+ attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
|
|
+
|
|
+ tuple = SearchSysCacheAttName(RelationGetRelid(rel),
|
|
+ attr_name);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for column \"%s.%s\"",
|
|
+ RelationGetRelationName(rel), attr_name);
|
|
+ /*
|
|
+ * NOTE: heap_modify_tuple() is necessary to make sure
|
|
+ * newtup has HEAP_HAS_SECLABEL and a field to store
|
|
+ * security lidentifier.
|
|
+ */
|
|
+ newtup = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
|
|
+ values, nulls, replaces);
|
|
+ if (!HeapTupleHasSecLabel(newtup))
|
|
+ elog(ERROR, "Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(attr_rel));
|
|
+
|
|
+ secid = sepgsqlInputGivenSecLabel(defel);
|
|
+ HeapTupleSetSecLabel(newtup, secid);
|
|
+
|
|
+ simple_heap_update(attr_rel, &tuple->t_self, newtup);
|
|
+
|
|
+ CatalogUpdateIndexes(attr_rel, newtup);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ heap_close(attr_rel, RowExclusiveLock);
|
|
+ }
|
|
+}
|
|
|
|
/*
|
|
* Execute ALTER TABLE SET SCHEMA
|
|
diff -rpNU3 base/src/backend/executor/execJunk.c sepgsql-new/src/backend/executor/execJunk.c
|
|
--- base/src/backend/executor/execJunk.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/executor/execJunk.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -60,7 +60,7 @@
|
|
* An optional resultSlot can be passed as well.
|
|
*/
|
|
JunkFilter *
|
|
-ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
|
|
+ExecInitJunkFilter(List *targetList, bool hasoid, bool hasseclabel, TupleTableSlot *slot)
|
|
{
|
|
JunkFilter *junkfilter;
|
|
TupleDesc cleanTupType;
|
|
@@ -72,7 +72,7 @@ ExecInitJunkFilter(List *targetList, boo
|
|
/*
|
|
* Compute the tuple descriptor for the cleaned tuple.
|
|
*/
|
|
- cleanTupType = ExecCleanTypeFromTL(targetList, hasoid);
|
|
+ cleanTupType = ExecCleanTypeFromTL(targetList, hasoid, hasseclabel);
|
|
|
|
/*
|
|
* Use the given slot, or make a new slot if we weren't given one.
|
|
diff -rpNU3 base/src/backend/executor/execMain.c sepgsql-new/src/backend/executor/execMain.c
|
|
--- base/src/backend/executor/execMain.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql-new/src/backend/executor/execMain.c 2009-03-15 17:38:39.000000000 +0900
|
|
@@ -38,6 +38,7 @@
|
|
#include "access/xact.h"
|
|
#include "catalog/heap.h"
|
|
#include "catalog/namespace.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/toasting.h"
|
|
#include "commands/tablespace.h"
|
|
#include "commands/trigger.h"
|
|
@@ -49,6 +50,8 @@
|
|
#include "parser/parse_clause.h"
|
|
#include "parser/parse_expr.h"
|
|
#include "parser/parsetree.h"
|
|
+#include "security/rowlevel.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
@@ -383,7 +386,10 @@ ExecCheckRTPerms(List *rangeTable)
|
|
|
|
foreach(l, rangeTable)
|
|
{
|
|
- ExecCheckRTEPerms((RangeTblEntry *) lfirst(l));
|
|
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
|
+
|
|
+ ExecCheckRTEPerms(rte);
|
|
+ sepgsqlCheckRTEPerms(rte);
|
|
}
|
|
}
|
|
|
|
@@ -410,6 +416,13 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
|
|
* No work if requiredPerms is empty.
|
|
*/
|
|
requiredPerms = rte->requiredPerms;
|
|
+
|
|
+ /* fixup ACL_SELECT_FOR_UPDATE */
|
|
+ if (requiredPerms & ACL_SELECT_FOR_UPDATE)
|
|
+ {
|
|
+ requiredPerms &= ~ACL_SELECT_FOR_UPDATE;
|
|
+ requiredPerms |= ACL_UPDATE;
|
|
+ }
|
|
if (requiredPerms == 0)
|
|
return;
|
|
|
|
@@ -738,15 +751,16 @@ InitPlan(QueryDesc *queryDesc, int eflag
|
|
for (i = 0; i < as_nplans; i++)
|
|
{
|
|
PlanState *subplan = appendplans[i];
|
|
+ Relation resultRel = resultRelInfo->ri_RelationDesc;
|
|
JunkFilter *j;
|
|
|
|
if (operation == CMD_UPDATE)
|
|
- ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
|
|
- subplan->plan->targetlist);
|
|
+ ExecCheckPlanOutput(resultRel, subplan->plan->targetlist);
|
|
|
|
j = ExecInitJunkFilter(subplan->plan->targetlist,
|
|
- resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
|
|
- ExecAllocTableSlot(estate->es_tupleTable));
|
|
+ RelationGetDescr(resultRel)->tdhasoid,
|
|
+ RelationGetDescr(resultRel)->tdhasseclabel,
|
|
+ ExecAllocTableSlot(estate->es_tupleTable));
|
|
|
|
/*
|
|
* Since it must be UPDATE/DELETE, there had better be a
|
|
@@ -790,6 +804,7 @@ InitPlan(QueryDesc *queryDesc, int eflag
|
|
|
|
j = ExecInitJunkFilter(planstate->plan->targetlist,
|
|
tupType->tdhasoid,
|
|
+ tupType->tdhasseclabel,
|
|
ExecAllocTableSlot(estate->es_tupleTable));
|
|
estate->es_junkFilter = j;
|
|
if (estate->es_result_relation_info)
|
|
@@ -848,7 +863,7 @@ InitPlan(QueryDesc *queryDesc, int eflag
|
|
* We assume all the sublists will generate the same output tupdesc.
|
|
*/
|
|
tupType = ExecTypeFromTL((List *) linitial(plannedstmt->returningLists),
|
|
- false);
|
|
+ false, false);
|
|
|
|
/* Set up a slot for the output of the RETURNING projection(s) */
|
|
slot = ExecAllocTableSlot(estate->es_tupleTable);
|
|
@@ -1171,6 +1186,33 @@ ExecContextForcesOids(PlanState *plansta
|
|
return false;
|
|
}
|
|
|
|
+/*
|
|
+ * ExecContextForcesSecLabel
|
|
+ *
|
|
+ * We need to ensure that result tuples have space for security label,
|
|
+ * if the security feature need to store it within the given relation.
|
|
+ */
|
|
+bool ExecContextForcesSecLabel(PlanState *planstate, bool *hassecurity)
|
|
+{
|
|
+ if (planstate->state->es_select_into)
|
|
+ {
|
|
+ *hassecurity = securityTupleDescHasSecLabel(NULL);
|
|
+ return true;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ResultRelInfo *ri = planstate->state->es_result_relation_info;
|
|
+
|
|
+ if (ri && ri->ri_RelationDesc)
|
|
+ {
|
|
+ *hassecurity = securityTupleDescHasSecLabel(ri->ri_RelationDesc);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
/* ----------------------------------------------------------------
|
|
* ExecEndPlan
|
|
*
|
|
@@ -1251,6 +1293,47 @@ ExecEndPlan(PlanState *planstate, EState
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * fetchWritableSystemAttribute() fetches writable system column data
|
|
+ * using Junkfilter, and saves them at TupleTableSlot temporary.
|
|
+ *
|
|
+ * storeWritableSystemAttribute() copies these fetched data into
|
|
+ * header structure of HeapTuple.
|
|
+ */
|
|
+static void
|
|
+fetchWritableSystemAttribute(JunkFilter *junkfilter, TupleTableSlot *slot, Oid *tts_seclabel)
|
|
+{
|
|
+ AttrNumber attno;
|
|
+ Datum datum;
|
|
+ bool isnull;
|
|
+
|
|
+ /* for Security Label */
|
|
+ attno = ExecFindJunkAttribute(junkfilter, SecurityLabelAttributeName);
|
|
+ if (attno != InvalidAttrNumber)
|
|
+ {
|
|
+ datum = ExecGetJunkAttribute(slot, attno, &isnull);
|
|
+ if (isnull)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("setting NULL on \"%s\" system column is not supported",
|
|
+ SecurityLabelAttributeName)));
|
|
+ *tts_seclabel = securityTransSecLabelIn(TextDatumGetCString(datum));
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+storeWritableSystemAttribute(Relation rel, TupleTableSlot *slot, HeapTuple tuple)
|
|
+{
|
|
+ /* "security_label" */
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, slot->tts_seclabel);
|
|
+ else if (OidIsValid(slot->tts_seclabel))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(rel))));
|
|
+}
|
|
+
|
|
/* ----------------------------------------------------------------
|
|
* ExecutePlan
|
|
*
|
|
@@ -1318,6 +1401,8 @@ ExecutePlan(EState *estate,
|
|
|
|
for (;;)
|
|
{
|
|
+ Oid tts_seclabel = InvalidOid;
|
|
+
|
|
/* Reset the per-output-tuple exprcontext */
|
|
ResetPerTupleExprContext(estate);
|
|
|
|
@@ -1442,6 +1527,11 @@ lnext: ;
|
|
}
|
|
|
|
/*
|
|
+ * extract writable system attribute
|
|
+ */
|
|
+ fetchWritableSystemAttribute(junkfilter, slot, &tts_seclabel);
|
|
+
|
|
+ /*
|
|
* extract the 'ctid' junk attribute.
|
|
*/
|
|
if (operation == CMD_UPDATE || operation == CMD_DELETE)
|
|
@@ -1468,6 +1558,7 @@ lnext: ;
|
|
if (operation != CMD_DELETE)
|
|
slot = ExecFilterJunk(junkfilter, slot);
|
|
}
|
|
+ slot->tts_seclabel = tts_seclabel;
|
|
|
|
/*
|
|
* now that we have a tuple, do the appropriate thing with it.. either
|
|
@@ -1588,6 +1679,8 @@ ExecInsert(TupleTableSlot *slot,
|
|
resultRelInfo = estate->es_result_relation_info;
|
|
resultRelationDesc = resultRelInfo->ri_RelationDesc;
|
|
|
|
+ storeWritableSystemAttribute(resultRelationDesc, slot, tuple);
|
|
+
|
|
/* BEFORE ROW INSERT Triggers */
|
|
if (resultRelInfo->ri_TrigDesc &&
|
|
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
|
|
@@ -1624,6 +1717,12 @@ ExecInsert(TupleTableSlot *slot,
|
|
ExecConstraints(resultRelInfo, slot, estate);
|
|
|
|
/*
|
|
+ * Check row-level permission on the tuple
|
|
+ */
|
|
+ if (!rowlvHeapTupleInsert(resultRelationDesc, tuple, false))
|
|
+ return;
|
|
+
|
|
+ /*
|
|
* insert the tuple
|
|
*
|
|
* Note: heap_insert returns the tid (location) of the new tuple in the
|
|
@@ -1691,6 +1790,12 @@ ExecDelete(ItemPointer tupleid,
|
|
}
|
|
|
|
/*
|
|
+ * Check row-level permission on the tuple
|
|
+ */
|
|
+ if (!rowlvHeapTupleDelete(resultRelationDesc, tupleid, false))
|
|
+ return;
|
|
+
|
|
+ /*
|
|
* delete the tuple
|
|
*
|
|
* Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that
|
|
@@ -1826,6 +1931,8 @@ ExecUpdate(TupleTableSlot *slot,
|
|
resultRelInfo = estate->es_result_relation_info;
|
|
resultRelationDesc = resultRelInfo->ri_RelationDesc;
|
|
|
|
+ storeWritableSystemAttribute(resultRelationDesc, slot, tuple);
|
|
+
|
|
/* BEFORE ROW UPDATE Triggers */
|
|
if (resultRelInfo->ri_TrigDesc &&
|
|
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
|
|
@@ -1870,6 +1977,12 @@ lreplace:;
|
|
ExecConstraints(resultRelInfo, slot, estate);
|
|
|
|
/*
|
|
+ * Check row-level permission on the tuple
|
|
+ */
|
|
+ if (!rowlvHeapTupleUpdate(resultRelationDesc, tupleid, tuple, false))
|
|
+ return;
|
|
+
|
|
+ /*
|
|
* replace the heap tuple
|
|
*
|
|
* Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that
|
|
@@ -2733,7 +2846,8 @@ OpenIntoRel(QueryDesc *queryDesc)
|
|
0,
|
|
into->onCommit,
|
|
reloptions,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ NIL);
|
|
|
|
FreeTupleDesc(tupdesc);
|
|
|
|
@@ -2839,6 +2953,10 @@ intorel_receive(TupleTableSlot *slot, De
|
|
|
|
tuple = ExecCopySlotTuple(slot);
|
|
|
|
+ storeWritableSystemAttribute(estate->es_into_relation_descriptor, slot, tuple);
|
|
+ if (!rowlvHeapTupleInsert(estate->es_into_relation_descriptor, tuple, false))
|
|
+ return;
|
|
+
|
|
heap_insert(estate->es_into_relation_descriptor,
|
|
tuple,
|
|
estate->es_output_cid,
|
|
diff -rpNU3 base/src/backend/executor/execScan.c sepgsql-new/src/backend/executor/execScan.c
|
|
--- base/src/backend/executor/execScan.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/executor/execScan.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -20,6 +20,7 @@
|
|
|
|
#include "executor/executor.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/rowlevel.h"
|
|
#include "utils/memutils.h"
|
|
|
|
|
|
@@ -53,6 +54,7 @@ ExecScan(ScanState *node,
|
|
ProjectionInfo *projInfo;
|
|
ExprDoneCond isDone;
|
|
TupleTableSlot *resultSlot;
|
|
+ Scan *scan = (Scan *)node->ps.plan;
|
|
|
|
/*
|
|
* Fetch data from node
|
|
@@ -64,7 +66,7 @@ ExecScan(ScanState *node,
|
|
* If we have neither a qual to check nor a projection to do, just skip
|
|
* all the overhead and return the raw scan tuple.
|
|
*/
|
|
- if (!qual && !projInfo)
|
|
+ if (!qual && !projInfo && !scan->requiredPerms)
|
|
return (*accessMtd) (node);
|
|
|
|
/*
|
|
@@ -128,9 +130,17 @@ ExecScan(ScanState *node,
|
|
* when the qual is nil ... saves only a few cycles, but they add up
|
|
* ...
|
|
*/
|
|
- if (!qual || ExecQual(qual, econtext, false))
|
|
+ if (rowlvExecScan(scan, node->ss_currentRelation, slot, false)
|
|
+ && (!qual || ExecQual(qual, econtext, false)))
|
|
{
|
|
/*
|
|
+ * NOTE: The purpose of rowlvExecScan() with abort = true is
|
|
+ * to ensure FK check works correctly. See also the comments
|
|
+ * at src/backend/security/rowlevel.c
|
|
+ */
|
|
+ rowlvExecScan(scan, node->ss_currentRelation, slot, true);
|
|
+
|
|
+ /*
|
|
* Found a satisfactory scan tuple.
|
|
*/
|
|
if (projInfo)
|
|
@@ -197,6 +207,7 @@ tlist_matches_tupdesc(PlanState *ps, Lis
|
|
int numattrs = tupdesc->natts;
|
|
int attrno;
|
|
bool hasoid;
|
|
+ bool hasseclabel;
|
|
ListCell *tlist_item = list_head(tlist);
|
|
|
|
/* Check the tlist attributes */
|
|
@@ -240,12 +251,17 @@ tlist_matches_tupdesc(PlanState *ps, Lis
|
|
return false; /* tlist too long */
|
|
|
|
/*
|
|
- * If the plan context requires a particular hasoid setting, then that has
|
|
+ * If the plan context requires a particular hasoid, hasseclabel
|
|
+ * setting, then that has
|
|
* to match, too.
|
|
*/
|
|
if (ExecContextForcesOids(ps, &hasoid) &&
|
|
hasoid != tupdesc->tdhasoid)
|
|
return false;
|
|
|
|
+ if (ExecContextForcesSecLabel(ps, &hasseclabel) &&
|
|
+ hasseclabel != tupdesc->tdhasseclabel)
|
|
+ return false;
|
|
+
|
|
return true;
|
|
}
|
|
diff -rpNU3 base/src/backend/executor/execTuples.c sepgsql-new/src/backend/executor/execTuples.c
|
|
--- base/src/backend/executor/execTuples.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/executor/execTuples.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -100,7 +100,7 @@
|
|
|
|
|
|
static TupleDesc ExecTypeFromTLInternal(List *targetList,
|
|
- bool hasoid, bool skipjunk);
|
|
+ bool hasoid, bool hasseclabel, bool skipjunk);
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
@@ -921,9 +921,9 @@ ExecInitNullTupleSlot(EState *estate, Tu
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
TupleDesc
|
|
-ExecTypeFromTL(List *targetList, bool hasoid)
|
|
+ExecTypeFromTL(List *targetList, bool hasoid, bool hasseclabel)
|
|
{
|
|
- return ExecTypeFromTLInternal(targetList, hasoid, false);
|
|
+ return ExecTypeFromTLInternal(targetList, hasoid, hasseclabel, false);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
@@ -933,13 +933,13 @@ ExecTypeFromTL(List *targetList, bool ha
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
TupleDesc
|
|
-ExecCleanTypeFromTL(List *targetList, bool hasoid)
|
|
+ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hasseclabel)
|
|
{
|
|
- return ExecTypeFromTLInternal(targetList, hasoid, true);
|
|
+ return ExecTypeFromTLInternal(targetList, hasoid, hasseclabel, true);
|
|
}
|
|
|
|
static TupleDesc
|
|
-ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk)
|
|
+ExecTypeFromTLInternal(List *targetList, bool hasoid, bool hasseclabel, bool skipjunk)
|
|
{
|
|
TupleDesc typeInfo;
|
|
ListCell *l;
|
|
@@ -951,6 +951,7 @@ ExecTypeFromTLInternal(List *targetList,
|
|
else
|
|
len = ExecTargetListLength(targetList);
|
|
typeInfo = CreateTemplateTupleDesc(len, hasoid);
|
|
+ typeInfo->tdhasseclabel = hasseclabel;
|
|
|
|
foreach(l, targetList)
|
|
{
|
|
diff -rpNU3 base/src/backend/executor/execUtils.c sepgsql-new/src/backend/executor/execUtils.c
|
|
--- base/src/backend/executor/execUtils.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/executor/execUtils.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -506,6 +506,7 @@ void
|
|
ExecAssignResultTypeFromTL(PlanState *planstate)
|
|
{
|
|
bool hasoid;
|
|
+ bool hasseclabel;
|
|
TupleDesc tupDesc;
|
|
|
|
if (ExecContextForcesOids(planstate, &hasoid))
|
|
@@ -518,12 +519,16 @@ ExecAssignResultTypeFromTL(PlanState *pl
|
|
hasoid = false;
|
|
}
|
|
|
|
+ if (!ExecContextForcesSecLabel(planstate, &hasseclabel))
|
|
+ hasseclabel = false;
|
|
+
|
|
/*
|
|
* ExecTypeFromTL needs the parse-time representation of the tlist, not a
|
|
* list of ExprStates. This is good because some plan nodes don't bother
|
|
* to set up planstate->targetlist ...
|
|
*/
|
|
- tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid);
|
|
+ tupDesc = ExecTypeFromTL(planstate->plan->targetlist,
|
|
+ hasoid, hasseclabel);
|
|
ExecAssignResultType(planstate, tupDesc);
|
|
}
|
|
|
|
diff -rpNU3 base/src/backend/executor/functions.c sepgsql-new/src/backend/executor/functions.c
|
|
--- base/src/backend/executor/functions.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/executor/functions.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -995,7 +995,7 @@ check_sql_fn_retval(Oid func_id, Oid ret
|
|
* what the caller expects will happen at runtime.
|
|
*/
|
|
if (junkFilter)
|
|
- *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
|
|
+ *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL);
|
|
return true;
|
|
}
|
|
Assert(tupdesc);
|
|
diff -rpNU3 base/src/backend/executor/nodeSubplan.c sepgsql-new/src/backend/executor/nodeSubplan.c
|
|
--- base/src/backend/executor/nodeSubplan.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/executor/nodeSubplan.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -855,7 +855,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanSt
|
|
* (hack alert!). The righthand expressions will be evaluated in our
|
|
* own innerecontext.
|
|
*/
|
|
- tupDesc = ExecTypeFromTL(leftptlist, false);
|
|
+ tupDesc = ExecTypeFromTL(leftptlist, false, false);
|
|
slot = ExecAllocTableSlot(tupTable);
|
|
ExecSetSlotDescriptor(slot, tupDesc);
|
|
sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
|
|
@@ -863,7 +863,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanSt
|
|
slot,
|
|
NULL);
|
|
|
|
- tupDesc = ExecTypeFromTL(rightptlist, false);
|
|
+ tupDesc = ExecTypeFromTL(rightptlist, false, false);
|
|
slot = ExecAllocTableSlot(tupTable);
|
|
ExecSetSlotDescriptor(slot, tupDesc);
|
|
sstate->projRight = ExecBuildProjectionInfo(righttlist,
|
|
diff -rpNU3 base/src/backend/executor/spi.c sepgsql-new/src/backend/executor/spi.c
|
|
--- base/src/backend/executor/spi.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql-new/src/backend/executor/spi.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -631,6 +631,8 @@ SPI_modifytuple(Relation rel, HeapTuple
|
|
mtuple->t_tableOid = tuple->t_tableOid;
|
|
if (rel->rd_att->tdhasoid)
|
|
HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
|
|
+ if (HeapTupleHasSecLabel(mtuple))
|
|
+ HeapTupleSetSecLabel(mtuple, HeapTupleGetSecLabel(tuple));
|
|
}
|
|
else
|
|
{
|
|
diff -rpNU3 base/src/backend/libpq/be-fsstubs.c sepgsql-new/src/backend/libpq/be-fsstubs.c
|
|
--- base/src/backend/libpq/be-fsstubs.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/libpq/be-fsstubs.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -42,11 +42,14 @@
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
+#include "catalog/pg_security.h"
|
|
#include "libpq/be-fsstubs.h"
|
|
#include "libpq/libpq-fs.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/large_object.h"
|
|
+#include "utils/builtins.h"
|
|
#include "utils/memutils.h"
|
|
|
|
|
|
@@ -153,6 +156,10 @@ lo_read(int fd, char *buf, int len)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
errmsg("invalid large-object descriptor: %d", fd)));
|
|
+ /*
|
|
+ * SELinux: check db_blob:{read}
|
|
+ */
|
|
+ sepgsqlCheckBlobRead(cookies[fd]);
|
|
|
|
status = inv_read(cookies[fd], buf, len);
|
|
|
|
@@ -175,6 +182,11 @@ lo_write(int fd, const char *buf, int le
|
|
errmsg("large object descriptor %d was not opened for writing",
|
|
fd)));
|
|
|
|
+ /*
|
|
+ * SELinux: check db_blob:{write} permission
|
|
+ */
|
|
+ sepgsqlCheckBlobWrite(cookies[fd]);
|
|
+
|
|
status = inv_write(cookies[fd], buf, len);
|
|
|
|
return status;
|
|
@@ -363,6 +375,11 @@ lo_import(PG_FUNCTION_ARGS)
|
|
*/
|
|
lobj = inv_open(lobjOid, INV_WRITE, fscxt);
|
|
|
|
+ /*
|
|
+ * SELinux: check db_blob:{write import} and file:{read} permission
|
|
+ */
|
|
+ sepgsqlCheckBlobImport(lobj, FileRawDescriptor(fd), fnamebuf);
|
|
+
|
|
while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0)
|
|
{
|
|
tmp = inv_write(lobj, buf, nbytes);
|
|
@@ -435,6 +452,11 @@ lo_export(PG_FUNCTION_ARGS)
|
|
fnamebuf)));
|
|
|
|
/*
|
|
+ * SELinux: check db_blob:{read export} and file:{write}
|
|
+ */
|
|
+ sepgsqlCheckBlobExport(lobj, FileRawDescriptor(fd), fnamebuf);
|
|
+
|
|
+ /*
|
|
* read in from the inversion file and write to the filesystem
|
|
*/
|
|
while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0)
|
|
@@ -468,12 +490,64 @@ lo_truncate(PG_FUNCTION_ARGS)
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
errmsg("invalid large-object descriptor: %d", fd)));
|
|
|
|
+ /*
|
|
+ * SELinux: check db_blob:{write} permission
|
|
+ */
|
|
+ sepgsqlCheckBlobWrite(cookies[fd]);
|
|
+
|
|
inv_truncate(cookies[fd], len);
|
|
|
|
PG_RETURN_INT32(0);
|
|
}
|
|
|
|
/*
|
|
+ * lo_get_seclabel
|
|
+ * get a security label of large object
|
|
+ */
|
|
+Datum
|
|
+lo_get_security(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid loid = PG_GETARG_OID(0);
|
|
+ Oid secid;
|
|
+
|
|
+ secid = inv_get_security(loid);
|
|
+
|
|
+ return CStringGetTextDatum(securityTransSecLabelOut(secid));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * lo_set_seclabel
|
|
+ * set a security label of large object
|
|
+ */
|
|
+Datum
|
|
+lo_set_security(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid loid = PG_GETARG_OID(0);
|
|
+ char *seclabel = TextDatumGetCString(PG_GETARG_DATUM(1));
|
|
+ Oid secid;
|
|
+
|
|
+ secid = securityTransSecLabelIn(seclabel);
|
|
+
|
|
+ inv_set_security(loid, secid);
|
|
+
|
|
+ /*
|
|
+ * Also on memory caches to be updated
|
|
+ */
|
|
+ if (fscxt != NULL)
|
|
+ {
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < cookies_size; i++)
|
|
+ {
|
|
+ if (cookies[i] != NULL && cookies[i]->id == loid)
|
|
+ cookies[i]->secid = secid;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ PG_RETURN_BOOL(true);
|
|
+}
|
|
+
|
|
+/*
|
|
* AtEOXact_LargeObject -
|
|
* prepares large objects for transaction commit
|
|
*/
|
|
diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql-new/src/backend/nodes/copyfuncs.c
|
|
--- base/src/backend/nodes/copyfuncs.c 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql-new/src/backend/nodes/copyfuncs.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -226,6 +226,7 @@ CopyScanFields(Scan *from, Scan *newnode
|
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
|
|
|
COPY_SCALAR_FIELD(scanrelid);
|
|
+ COPY_SCALAR_FIELD(requiredPerms);
|
|
}
|
|
|
|
/*
|
|
@@ -1523,6 +1524,8 @@ _copyRangeTblEntry(RangeTblEntry *from)
|
|
COPY_SCALAR_FIELD(inFromCl);
|
|
COPY_SCALAR_FIELD(requiredPerms);
|
|
COPY_SCALAR_FIELD(checkAsUser);
|
|
+ COPY_BITMAPSET_FIELD(selectedCols);
|
|
+ COPY_BITMAPSET_FIELD(modifiedCols);
|
|
|
|
return newnode;
|
|
}
|
|
@@ -1789,6 +1792,7 @@ _copyColumnDef(ColumnDef *from)
|
|
COPY_NODE_FIELD(raw_default);
|
|
COPY_STRING_FIELD(cooked_default);
|
|
COPY_NODE_FIELD(constraints);
|
|
+ COPY_NODE_FIELD(secLabel);
|
|
|
|
return newnode;
|
|
}
|
|
@@ -2105,6 +2109,7 @@ _copyCreateStmt(CreateStmt *from)
|
|
COPY_NODE_FIELD(options);
|
|
COPY_SCALAR_FIELD(oncommit);
|
|
COPY_STRING_FIELD(tablespacename);
|
|
+ COPY_NODE_FIELD(secLabel);
|
|
|
|
return newnode;
|
|
}
|
|
diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql-new/src/backend/nodes/equalfuncs.c
|
|
--- base/src/backend/nodes/equalfuncs.c 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql-new/src/backend/nodes/equalfuncs.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -970,6 +970,7 @@ _equalCreateStmt(CreateStmt *a, CreateSt
|
|
COMPARE_NODE_FIELD(options);
|
|
COMPARE_SCALAR_FIELD(oncommit);
|
|
COMPARE_STRING_FIELD(tablespacename);
|
|
+ COMPARE_NODE_FIELD(secLabel);
|
|
|
|
return true;
|
|
}
|
|
@@ -1818,6 +1819,7 @@ _equalColumnDef(ColumnDef *a, ColumnDef
|
|
COMPARE_NODE_FIELD(raw_default);
|
|
COMPARE_STRING_FIELD(cooked_default);
|
|
COMPARE_NODE_FIELD(constraints);
|
|
+ COMPARE_NODE_FIELD(secLabel);
|
|
|
|
return true;
|
|
}
|
|
@@ -1873,6 +1875,8 @@ _equalRangeTblEntry(RangeTblEntry *a, Ra
|
|
COMPARE_SCALAR_FIELD(inFromCl);
|
|
COMPARE_SCALAR_FIELD(requiredPerms);
|
|
COMPARE_SCALAR_FIELD(checkAsUser);
|
|
+ COMPARE_BITMAPSET_FIELD(selectedCols);
|
|
+ COMPARE_BITMAPSET_FIELD(modifiedCols);
|
|
|
|
return true;
|
|
}
|
|
diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql-new/src/backend/nodes/outfuncs.c
|
|
--- base/src/backend/nodes/outfuncs.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql-new/src/backend/nodes/outfuncs.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -282,6 +282,7 @@ _outScanInfo(StringInfo str, Scan *node)
|
|
_outPlanInfo(str, (Plan *) node);
|
|
|
|
WRITE_UINT_FIELD(scanrelid);
|
|
+ WRITE_UINT_FIELD(requiredPerms);
|
|
}
|
|
|
|
/*
|
|
@@ -1376,6 +1377,7 @@ _outRelOptInfo(StringInfo str, RelOptInf
|
|
WRITE_BOOL_FIELD(has_eclass_joins);
|
|
WRITE_BITMAPSET_FIELD(index_outer_relids);
|
|
WRITE_NODE_FIELD(index_inner_paths);
|
|
+ WRITE_UINT_FIELD(requiredPerms);
|
|
}
|
|
|
|
static void
|
|
@@ -1545,6 +1547,7 @@ _outCreateStmt(StringInfo str, CreateStm
|
|
WRITE_NODE_FIELD(options);
|
|
WRITE_ENUM_FIELD(oncommit, OnCommitAction);
|
|
WRITE_STRING_FIELD(tablespacename);
|
|
+ WRITE_NODE_FIELD(secLabel);
|
|
}
|
|
|
|
static void
|
|
@@ -1660,6 +1663,7 @@ _outColumnDef(StringInfo str, ColumnDef
|
|
WRITE_NODE_FIELD(raw_default);
|
|
WRITE_STRING_FIELD(cooked_default);
|
|
WRITE_NODE_FIELD(constraints);
|
|
+ WRITE_NODE_FIELD(secLabel);
|
|
}
|
|
|
|
static void
|
|
@@ -1834,6 +1838,8 @@ _outRangeTblEntry(StringInfo str, RangeT
|
|
WRITE_BOOL_FIELD(inFromCl);
|
|
WRITE_UINT_FIELD(requiredPerms);
|
|
WRITE_OID_FIELD(checkAsUser);
|
|
+ WRITE_BITMAPSET_FIELD(selectedCols);
|
|
+ WRITE_BITMAPSET_FIELD(modifiedCols);
|
|
}
|
|
|
|
static void
|
|
diff -rpNU3 base/src/backend/nodes/readfuncs.c sepgsql-new/src/backend/nodes/readfuncs.c
|
|
--- base/src/backend/nodes/readfuncs.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/nodes/readfuncs.c 2009-03-13 13:09:47.000000000 +0900
|
|
@@ -102,6 +102,10 @@
|
|
token = pg_strtok(&length); /* skip :fldname */ \
|
|
local_node->fldname = nodeRead(NULL, 0)
|
|
|
|
+#define READ_BITMAPSET_FIELD(fldname) \
|
|
+ token = pg_strtok(&length); /* skip :fldname */ \
|
|
+ local_node->fldname = _readBitmapset()
|
|
+
|
|
/* Routine exit */
|
|
#define READ_DONE() \
|
|
return local_node
|
|
@@ -125,6 +129,46 @@
|
|
|
|
static Datum readDatum(bool typbyval);
|
|
|
|
+/*
|
|
+ * _readBitmapset
|
|
+ */
|
|
+static Bitmapset *
|
|
+_readBitmapset(void)
|
|
+{
|
|
+ Bitmapset *result = NULL;
|
|
+ READ_TEMP_LOCALS();
|
|
+
|
|
+ token = pg_strtok(&length);
|
|
+ if (token == NULL)
|
|
+ elog(ERROR, "incomplete Bitmapset structure");
|
|
+ if (length != 1 || token[0] != '(')
|
|
+ elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
|
|
+
|
|
+ token = pg_strtok(&length);
|
|
+ if (token == NULL)
|
|
+ elog(ERROR, "incomplete Bitmapset structure");
|
|
+ if (length != 1 || token[0] != 'b')
|
|
+ elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
|
|
+
|
|
+ for (;;)
|
|
+ {
|
|
+ int val;
|
|
+ char *endptr;
|
|
+
|
|
+ token = pg_strtok(&length);
|
|
+ if (token == NULL)
|
|
+ elog(ERROR, "unterminated Bitmapset structure");
|
|
+ if (length == 1 && token[0] == ')')
|
|
+ break;
|
|
+ val = (int) strtol(token, &endptr, 10);
|
|
+ if (endptr != token + length)
|
|
+ elog(ERROR, "unrecognized integer: \"%.*s\"", length, token);
|
|
+ result = bms_add_member(result, val);
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
|
|
/*
|
|
* _readQuery
|
|
@@ -1003,6 +1047,8 @@ _readRangeTblEntry(void)
|
|
READ_BOOL_FIELD(inFromCl);
|
|
READ_UINT_FIELD(requiredPerms);
|
|
READ_OID_FIELD(checkAsUser);
|
|
+ READ_BITMAPSET_FIELD(selectedCols);
|
|
+ READ_BITMAPSET_FIELD(modifiedCols);
|
|
|
|
READ_DONE();
|
|
}
|
|
diff -rpNU3 base/src/backend/optimizer/plan/createplan.c sepgsql-new/src/backend/optimizer/plan/createplan.c
|
|
--- base/src/backend/optimizer/plan/createplan.c 2008-06-12 22:34:19.000000000 +0900
|
|
+++ sepgsql-new/src/backend/optimizer/plan/createplan.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -287,6 +287,11 @@ create_scan_plan(PlannerInfo *root, Path
|
|
}
|
|
|
|
/*
|
|
+ * Copies row-level permissions
|
|
+ */
|
|
+ ((Scan *)plan)->requiredPerms = rel->requiredPerms;
|
|
+
|
|
+ /*
|
|
* If there are any pseudoconstant clauses attached to this node, insert a
|
|
* gating Result node that evaluates the pseudoconstants as one-time
|
|
* quals.
|
|
diff -rpNU3 base/src/backend/optimizer/prep/prepunion.c sepgsql-new/src/backend/optimizer/prep/prepunion.c
|
|
--- base/src/backend/optimizer/prep/prepunion.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql-new/src/backend/optimizer/prep/prepunion.c 2009-03-13 13:09:47.000000000 +0900
|
|
@@ -75,6 +75,8 @@ static void make_inh_translation_lists(R
|
|
Index newvarno,
|
|
List **col_mappings,
|
|
List **translated_vars);
|
|
+static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
|
|
+ List *translated_vars);
|
|
static Node *adjust_appendrel_attrs_mutator(Node *node,
|
|
AppendRelInfo *context);
|
|
static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
|
|
@@ -882,6 +884,19 @@ expand_inherited_rtentry(PlannerInfo *ro
|
|
appinfo->parent_reloid = parentOID;
|
|
appinfos = lappend(appinfos, appinfo);
|
|
|
|
+ /*
|
|
+ * Translate the column permissions bitmaps to the child's attnums
|
|
+ * (we have to build the translated_vars list before we can do this).
|
|
+ * But if this is the parent table, leave copyObject's result alone.
|
|
+ */
|
|
+ if (childOID != parentOID)
|
|
+ {
|
|
+ childrte->selectedCols = translate_col_privs(rte->selectedCols,
|
|
+ appinfo->translated_vars);
|
|
+ childrte->modifiedCols = translate_col_privs(rte->modifiedCols,
|
|
+ appinfo->translated_vars);
|
|
+ }
|
|
+
|
|
/* Close child relations, but keep locks */
|
|
if (childOID != parentOID)
|
|
heap_close(newrelation, NoLock);
|
|
@@ -1015,6 +1030,62 @@ make_inh_translation_lists(Relation oldr
|
|
}
|
|
|
|
/*
|
|
+ * translate_col_privs
|
|
+ * Translate a bitmapset representing per-column privileges from the
|
|
+ * parent rel's attribute numbering to the child's.
|
|
+ *
|
|
+ * The only surprise here is that we don't translate a parent whole-row
|
|
+ * reference into a child whole-row reference. That would mean requiring
|
|
+ * permissions on all child columns, which is overly strict, since the
|
|
+ * query is really only going to reference the inherited columns. Instead
|
|
+ * we set the per-column bits for all inherited columns.
|
|
+ */
|
|
+static Bitmapset *
|
|
+translate_col_privs(const Bitmapset *parent_privs,
|
|
+ List *translated_vars)
|
|
+{
|
|
+ Bitmapset *child_privs = NULL;
|
|
+ bool whole_row;
|
|
+ int attno;
|
|
+ ListCell *lc;
|
|
+
|
|
+ /* System attributes have the same numbers in all tables */
|
|
+ for (attno = FirstLowInvalidHeapAttributeNumber+1; attno < 0; attno++)
|
|
+ {
|
|
+ if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
|
|
+ parent_privs))
|
|
+ child_privs = bms_add_member(child_privs,
|
|
+ attno - FirstLowInvalidHeapAttributeNumber);
|
|
+ }
|
|
+
|
|
+ /* Check if parent has whole-row reference */
|
|
+ whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
|
|
+ parent_privs);
|
|
+ /* Check if parent has whole-row reference */
|
|
+ whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
|
|
+ parent_privs);
|
|
+
|
|
+ /* And now translate the regular user attributes, using the vars list */
|
|
+ attno = InvalidAttrNumber;
|
|
+ foreach(lc, translated_vars)
|
|
+ {
|
|
+ Var *var = (Var *) lfirst(lc);
|
|
+
|
|
+ attno++;
|
|
+ if (var == NULL) /* ignore dropped columns */
|
|
+ continue;
|
|
+ Assert(IsA(var, Var));
|
|
+ if (whole_row ||
|
|
+ bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
|
|
+ parent_privs))
|
|
+ child_privs = bms_add_member(child_privs,
|
|
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
|
|
+ }
|
|
+
|
|
+ return child_privs;
|
|
+}
|
|
+
|
|
+/*
|
|
* adjust_appendrel_attrs
|
|
* Copy the specified query or expression and translate Vars referring
|
|
* to the parent rel of the specified AppendRelInfo to refer to the
|
|
diff -rpNU3 base/src/backend/optimizer/util/clauses.c sepgsql-new/src/backend/optimizer/util/clauses.c
|
|
--- base/src/backend/optimizer/util/clauses.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql-new/src/backend/optimizer/util/clauses.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -38,6 +38,7 @@
|
|
#include "parser/parse_clause.h"
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_expr.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
@@ -3046,6 +3047,7 @@ inline_function(Oid funcid, Oid result_t
|
|
funcform->prosecdef ||
|
|
funcform->proretset ||
|
|
!heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
|
|
+ !sepgsqlAllowFunctionInlined(func_tuple) ||
|
|
funcform->pronargs != list_length(args))
|
|
return NULL;
|
|
|
|
diff -rpNU3 base/src/backend/optimizer/util/relnode.c sepgsql-new/src/backend/optimizer/util/relnode.c
|
|
--- base/src/backend/optimizer/util/relnode.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/optimizer/util/relnode.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -90,6 +90,7 @@ build_simple_rel(PlannerInfo *root, int
|
|
rel->has_eclass_joins = false;
|
|
rel->index_outer_relids = NULL;
|
|
rel->index_inner_paths = NIL;
|
|
+ rel->requiredPerms = rte->requiredPerms;
|
|
|
|
/* Check type of rtable entry */
|
|
switch (rte->rtekind)
|
|
diff -rpNU3 base/src/backend/parser/analyze.c sepgsql-new/src/backend/parser/analyze.c
|
|
--- base/src/backend/parser/analyze.c 2009-03-15 17:47:25.000000000 +0900
|
|
+++ sepgsql-new/src/backend/parser/analyze.c 2009-03-15 17:58:10.000000000 +0900
|
|
@@ -24,6 +24,8 @@
|
|
|
|
#include "postgres.h"
|
|
|
|
+#include "access/htup.h"
|
|
+#include "catalog/heap.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "optimizer/clauses.h"
|
|
@@ -427,6 +429,7 @@ transformInsertStmt(ParseState *pstate,
|
|
* bugs of just that nature...)
|
|
*/
|
|
sub_pstate->p_rtable = sub_rtable;
|
|
+ sub_pstate->p_joinexprs = NIL; /* sub_rtable has no joins */
|
|
sub_pstate->p_relnamespace = sub_relnamespace;
|
|
sub_pstate->p_varnamespace = sub_varnamespace;
|
|
|
|
@@ -608,6 +611,7 @@ transformInsertStmt(ParseState *pstate,
|
|
/*
|
|
* Generate query's target list using the computed list of expressions.
|
|
*/
|
|
+ rte = pstate->p_target_rangetblentry;
|
|
qry->targetList = NIL;
|
|
icols = list_head(icolumns);
|
|
attnos = list_head(attrnos);
|
|
@@ -615,17 +619,22 @@ transformInsertStmt(ParseState *pstate,
|
|
{
|
|
Expr *expr = (Expr *) lfirst(lc);
|
|
ResTarget *col;
|
|
+ AttrNumber attr_num;
|
|
TargetEntry *tle;
|
|
|
|
col = (ResTarget *) lfirst(icols);
|
|
Assert(IsA(col, ResTarget));
|
|
+ attr_num = (AttrNumber) lfirst_int(attnos);
|
|
|
|
tle = makeTargetEntry(expr,
|
|
- (AttrNumber) lfirst_int(attnos),
|
|
+ attr_num,
|
|
col->name,
|
|
- false);
|
|
+ attr_num < 0 ? true : false);
|
|
qry->targetList = lappend(qry->targetList, tle);
|
|
|
|
+ rte->modifiedCols = bms_add_member(rte->modifiedCols,
|
|
+ attr_num - FirstLowInvalidHeapAttributeNumber);
|
|
+
|
|
icols = lnext(icols);
|
|
attnos = lnext(attnos);
|
|
}
|
|
@@ -721,6 +730,46 @@ transformInsertRow(ParseState *pstate, L
|
|
return result;
|
|
}
|
|
|
|
+static void
|
|
+transformSelectIntoSystemColumn(ParseState *pstate, Query *qry)
|
|
+{
|
|
+ ListCell *l;
|
|
+ uint32 system_attrs = 0;
|
|
+ bool relhasoids
|
|
+ = interpretOidsOption(qry->intoClause->options);
|
|
+
|
|
+ foreach (l, qry->targetList) {
|
|
+ Form_pg_attribute attr;
|
|
+ TargetEntry *tle = lfirst(l);
|
|
+
|
|
+ if (tle->resjunk)
|
|
+ continue;
|
|
+
|
|
+ attr = SystemAttributeByName(tle->resname, relhasoids);
|
|
+ if (attr && SystemAttributeIsWritable(attr->attnum))
|
|
+ {
|
|
+ uint32 mask = (1<<(-attr->attnum));
|
|
+
|
|
+ /* duplication checks */
|
|
+ if (system_attrs & mask)
|
|
+ continue;
|
|
+ system_attrs |= mask;
|
|
+
|
|
+ if (exprType((Node *) tle->expr) != attr->atttypid)
|
|
+ {
|
|
+ tle->expr =
|
|
+ (Expr *) coerce_to_target_type(pstate,
|
|
+ (Node *) tle->expr,
|
|
+ exprType((Node *) tle->expr),
|
|
+ attr->atttypid,
|
|
+ attr->atttypmod,
|
|
+ COERCION_IMPLICIT,
|
|
+ COERCE_IMPLICIT_CAST);
|
|
+ }
|
|
+ tle->resjunk = true;
|
|
+ }
|
|
+ }
|
|
+}
|
|
|
|
/*
|
|
* transformSelectStmt -
|
|
@@ -787,6 +836,7 @@ transformSelectStmt(ParseState *pstate,
|
|
if (stmt->intoClause)
|
|
{
|
|
qry->intoClause = stmt->intoClause;
|
|
+ transformSelectIntoSystemColumn(pstate, qry);
|
|
if (stmt->intoClause->colNames)
|
|
applyColumnNames(qry->targetList, stmt->intoClause->colNames);
|
|
}
|
|
@@ -1478,6 +1528,7 @@ static Query *
|
|
transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
|
|
{
|
|
Query *qry = makeNode(Query);
|
|
+ RangeTblEntry *target_rte;
|
|
Node *qual;
|
|
ListCell *origTargetList;
|
|
ListCell *tl;
|
|
@@ -1527,6 +1578,7 @@ transformUpdateStmt(ParseState *pstate,
|
|
pstate->p_next_resno = pstate->p_target_relation->rd_rel->relnatts + 1;
|
|
|
|
/* Prepare non-junk columns for assignment to target table */
|
|
+ target_rte = pstate->p_target_rangetblentry;
|
|
origTargetList = list_head(stmt->targetList);
|
|
|
|
foreach(tl, qry->targetList)
|
|
@@ -1567,6 +1619,10 @@ transformUpdateStmt(ParseState *pstate,
|
|
origTarget->indirection,
|
|
origTarget->location);
|
|
|
|
+ /* Mark the target column as requiring update permissions */
|
|
+ target_rte->modifiedCols = bms_add_member(target_rte->modifiedCols,
|
|
+ attrno - FirstLowInvalidHeapAttributeNumber);
|
|
+
|
|
origTargetList = lnext(origTargetList);
|
|
}
|
|
if (origTargetList != NULL)
|
|
diff -rpNU3 base/src/backend/parser/gram.y sepgsql-new/src/backend/parser/gram.y
|
|
--- base/src/backend/parser/gram.y 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql-new/src/backend/parser/gram.y 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -56,6 +56,7 @@
|
|
#include "commands/defrem.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/gramparse.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/lmgr.h"
|
|
#include "utils/date.h"
|
|
#include "utils/datetime.h"
|
|
@@ -351,6 +352,8 @@ static Node *makeXmlExpr(XmlExprOp op, c
|
|
%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
|
|
%type <list> opt_check_option
|
|
|
|
+%type <defelt> OptSecurityItem SecurityItem
|
|
+
|
|
%type <target> xml_attribute_el
|
|
%type <list> xml_attribute_list xml_attributes
|
|
%type <node> xml_root_version opt_xml_root_standalone
|
|
@@ -1637,7 +1640,25 @@ alter_table_cmd:
|
|
n->def = (Node *) $3;
|
|
$$ = (Node *)n;
|
|
}
|
|
- | alter_rel_cmd
|
|
+ /* ALTER TABLE <relation> CONTEXT = '...' */
|
|
+ | SecurityItem
|
|
+ {
|
|
+ AlterTableCmd *n = makeNode(AlterTableCmd);
|
|
+ n->subtype = AT_SetSecurityLabel;
|
|
+ n->name = NULL;
|
|
+ n->def = (Node *) $1;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
+ /* ALTER TABLE <relation> ALTER [COLUMN] <colname> CONTEXT = '...' */
|
|
+ | ALTER opt_column ColId SecurityItem
|
|
+ {
|
|
+ AlterTableCmd *n = makeNode(AlterTableCmd);
|
|
+ n->subtype = AT_SetSecurityLabel;
|
|
+ n->name = $3;
|
|
+ n->def = (Node *) $4;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
+ | alter_rel_cmd
|
|
{
|
|
$$ = $1;
|
|
}
|
|
@@ -1883,7 +1904,7 @@ opt_using:
|
|
*****************************************************************************/
|
|
|
|
CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
|
|
- OptInherit OptWith OnCommitOption OptTableSpace
|
|
+ OptInherit OptWith OnCommitOption OptTableSpace OptSecurityItem
|
|
{
|
|
CreateStmt *n = makeNode(CreateStmt);
|
|
$4->istemp = $2;
|
|
@@ -1894,10 +1915,11 @@ CreateStmt: CREATE OptTemp TABLE qualifi
|
|
n->options = $9;
|
|
n->oncommit = $10;
|
|
n->tablespacename = $11;
|
|
+ n->secLabel = (Node *) $12;
|
|
$$ = (Node *)n;
|
|
}
|
|
| CREATE OptTemp TABLE qualified_name OF qualified_name
|
|
- '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace
|
|
+ '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace OptSecurityItem
|
|
{
|
|
/* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
|
|
* by our inheritance capabilities. Let's try it...
|
|
@@ -1911,6 +1933,7 @@ CreateStmt: CREATE OptTemp TABLE qualifi
|
|
n->options = $10;
|
|
n->oncommit = $11;
|
|
n->tablespacename = $12;
|
|
+ n->secLabel = (Node *) $13;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
@@ -1953,13 +1976,14 @@ TableElement:
|
|
| TableConstraint { $$ = $1; }
|
|
;
|
|
|
|
-columnDef: ColId Typename ColQualList
|
|
+columnDef: ColId Typename ColQualList OptSecurityItem
|
|
{
|
|
ColumnDef *n = makeNode(ColumnDef);
|
|
n->colname = $1;
|
|
n->typename = $2;
|
|
n->constraints = $3;
|
|
n->is_local = true;
|
|
+ n->secLabel = (Node *) $4;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
@@ -4278,6 +4302,10 @@ common_func_opt_item:
|
|
/* we abuse the normal content of a DefElem here */
|
|
$$ = makeDefElem("set", (Node *)$1);
|
|
}
|
|
+ | SecurityItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
;
|
|
|
|
createfunc_opt_item:
|
|
@@ -5361,6 +5389,10 @@ createdb_opt_item:
|
|
{
|
|
$$ = makeDefElem("owner", NULL);
|
|
}
|
|
+ | SecurityItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
;
|
|
|
|
/*
|
|
@@ -5409,6 +5441,10 @@ alterdb_opt_item:
|
|
{
|
|
$$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
|
|
}
|
|
+ | SecurityItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
;
|
|
|
|
|
|
@@ -8736,6 +8772,27 @@ target_el: a_expr AS ColLabel
|
|
}
|
|
;
|
|
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * SE-PostgreSQL security items
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+
|
|
+OptSecurityItem:
|
|
+ SecurityItem { $$ = $1; }
|
|
+ | /* EMPTY */ { $$ = NULL; }
|
|
+ ;
|
|
+
|
|
+SecurityItem:
|
|
+ IDENT opt_equal Sconst
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled() ||
|
|
+ strcmp("security_context", $1) != 0)
|
|
+ yyerror("syntax error");
|
|
+
|
|
+ $$ = makeDefElem($1, (Node *) makeString($3));
|
|
+ }
|
|
+ ;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
diff -rpNU3 base/src/backend/parser/parse_clause.c sepgsql-new/src/backend/parser/parse_clause.c
|
|
--- base/src/backend/parser/parse_clause.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/parser/parse_clause.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -46,6 +46,7 @@ static void extractRemainingColumns(List
|
|
List *src_colnames, List *src_colvars,
|
|
List **res_colnames, List **res_colvars);
|
|
static Node *transformJoinUsingClause(ParseState *pstate,
|
|
+ RangeTblEntry *leftRTE, RangeTblEntry *rightRTE,
|
|
List *leftVars, List *rightVars);
|
|
static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j,
|
|
RangeTblEntry *l_rte,
|
|
@@ -286,7 +287,9 @@ extractRemainingColumns(List *common_col
|
|
* Result is a transformed qualification expression.
|
|
*/
|
|
static Node *
|
|
-transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
|
|
+transformJoinUsingClause(ParseState *pstate,
|
|
+ RangeTblEntry *leftRTE, RangeTblEntry *rightRTE,
|
|
+ List *leftVars, List *rightVars)
|
|
{
|
|
Node *result = NULL;
|
|
ListCell *lvars,
|
|
@@ -303,6 +306,10 @@ transformJoinUsingClause(ParseState *pst
|
|
Node *rvar = (Node *) lfirst(rvars);
|
|
A_Expr *e;
|
|
|
|
+ /* Require read access to the join variables */
|
|
+ markVarForSelectPriv(pstate, (Var *) lvar, leftRTE);
|
|
+ markVarForSelectPriv(pstate, (Var *) rvar, rightRTE);
|
|
+
|
|
e = makeSimpleA_Expr(AEXPR_OP, "=",
|
|
copyObject(lvar), copyObject(rvar),
|
|
-1);
|
|
@@ -665,6 +672,7 @@ transformFromClauseItem(ParseState *psta
|
|
*r_colvars,
|
|
*res_colvars;
|
|
RangeTblEntry *rte;
|
|
+ int k;
|
|
|
|
/*
|
|
* Recursively process the left and right subtrees
|
|
@@ -849,6 +857,8 @@ transformFromClauseItem(ParseState *psta
|
|
}
|
|
|
|
j->quals = transformJoinUsingClause(pstate,
|
|
+ l_rte,
|
|
+ r_rte,
|
|
l_usingvars,
|
|
r_usingvars);
|
|
}
|
|
@@ -909,6 +919,12 @@ transformFromClauseItem(ParseState *psta
|
|
*top_rte = rte;
|
|
*top_rti = j->rtindex;
|
|
|
|
+ /* make a matching link to the JoinExpr for later use */
|
|
+ for (k = list_length(pstate->p_joinexprs) + 1; k < j->rtindex; k++)
|
|
+ pstate->p_joinexprs = lappend(pstate->p_joinexprs, NULL);
|
|
+ pstate->p_joinexprs = lappend(pstate->p_joinexprs, j);
|
|
+ Assert(list_length(pstate->p_joinexprs) == j->rtindex);
|
|
+
|
|
/*
|
|
* Prepare returned namespace list. If the JOIN has an alias then it
|
|
* hides the contained RTEs as far as the relnamespace goes;
|
|
diff -rpNU3 base/src/backend/parser/parse_expr.c sepgsql-new/src/backend/parser/parse_expr.c
|
|
--- base/src/backend/parser/parse_expr.c 2008-11-05 09:57:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/parser/parse_expr.c 2009-03-13 13:09:47.000000000 +0900
|
|
@@ -1764,6 +1764,9 @@ transformWholeRowRef(ParseState *pstate,
|
|
break;
|
|
}
|
|
|
|
+ /* mark relation as requiring whole-row SELECT access */
|
|
+ markVarForSelectPriv(pstate, (Var *) result, rte);
|
|
+
|
|
return result;
|
|
}
|
|
|
|
diff -rpNU3 base/src/backend/parser/parse_relation.c sepgsql-new/src/backend/parser/parse_relation.c
|
|
--- base/src/backend/parser/parse_relation.c 2008-06-12 22:34:19.000000000 +0900
|
|
+++ sepgsql-new/src/backend/parser/parse_relation.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -335,6 +335,7 @@ scanRTEForColumn(ParseState *pstate, Ran
|
|
{
|
|
Node *result = NULL;
|
|
int attnum = 0;
|
|
+ Var *var;
|
|
ListCell *c;
|
|
|
|
/*
|
|
@@ -361,9 +362,10 @@ scanRTEForColumn(ParseState *pstate, Ran
|
|
errmsg("column reference \"%s\" is ambiguous",
|
|
colname),
|
|
parser_errposition(pstate, location)));
|
|
- result = (Node *) make_var(pstate, rte, attnum);
|
|
- /* Require read access */
|
|
- rte->requiredPerms |= ACL_SELECT;
|
|
+ var = make_var(pstate, rte, attnum);
|
|
+ /* Require read access to the column */
|
|
+ markVarForSelectPriv(pstate, var, rte);
|
|
+ result = (Node *) var;
|
|
}
|
|
}
|
|
|
|
@@ -389,9 +391,10 @@ scanRTEForColumn(ParseState *pstate, Ran
|
|
Int16GetDatum(attnum),
|
|
0, 0))
|
|
{
|
|
- result = (Node *) make_var(pstate, rte, attnum);
|
|
- /* Require read access */
|
|
- rte->requiredPerms |= ACL_SELECT;
|
|
+ var = make_var(pstate, rte, attnum);
|
|
+ /* Require read access to the column */
|
|
+ markVarForSelectPriv(pstate, var, rte);
|
|
+ result = (Node *) var;
|
|
}
|
|
}
|
|
}
|
|
@@ -479,6 +482,122 @@ qualifiedNameToVar(ParseState *pstate,
|
|
}
|
|
|
|
/*
|
|
+ * markRTEForSelectPriv
|
|
+ * Mark the specified column of an RTE as requiring SELECT privilege
|
|
+ *
|
|
+ * col == InvalidAttrNumber means a "whole row" reference
|
|
+ *
|
|
+ * The caller should pass the actual RTE if it has it handy; otherwise pass
|
|
+ * NULL, and we'll look it up here. (This uglification of the API is
|
|
+ * worthwhile because nearly all external callers have the RTE at hand.)
|
|
+ */
|
|
+static void
|
|
+markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
|
+ int rtindex, AttrNumber col)
|
|
+{
|
|
+ if (rte == NULL)
|
|
+ rte = rt_fetch(rtindex, pstate->p_rtable);
|
|
+
|
|
+ if (rte->rtekind == RTE_RELATION)
|
|
+ {
|
|
+ /* Make sure the rel as a whole is marked for SELECT access */
|
|
+ rte->requiredPerms |= ACL_SELECT;
|
|
+ /* Must offset the attnum to fit in a bitmapset */
|
|
+ rte->selectedCols = bms_add_member(rte->selectedCols,
|
|
+ col - FirstLowInvalidHeapAttributeNumber);
|
|
+ }
|
|
+ else if (rte->rtekind == RTE_JOIN)
|
|
+ {
|
|
+ if (col == InvalidAttrNumber)
|
|
+ {
|
|
+ /*
|
|
+ * A whole-row reference to a join has to be treated as
|
|
+ * whole-row references to the two inputs.
|
|
+ */
|
|
+ JoinExpr *j;
|
|
+
|
|
+ if (rtindex > 0 && rtindex <= list_length(pstate->p_joinexprs))
|
|
+ j = (JoinExpr *) list_nth(pstate->p_joinexprs, rtindex - 1);
|
|
+ else
|
|
+ j = NULL;
|
|
+ if (j == NULL)
|
|
+ elog(ERROR, "could not find JoinExpr for whole-row reference");
|
|
+ Assert(IsA(j, JoinExpr));
|
|
+
|
|
+ /* Note: we can't see FromExpr here */
|
|
+ if (IsA(j->larg, RangeTblRef))
|
|
+ {
|
|
+ int varno = ((RangeTblRef *) j->larg)->rtindex;
|
|
+
|
|
+ markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
|
+ }
|
|
+ else if (IsA(j->larg, JoinExpr))
|
|
+ {
|
|
+ int varno = ((JoinExpr *) j->larg)->rtindex;
|
|
+
|
|
+ markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
|
+ }
|
|
+ else
|
|
+ elog(ERROR, "unrecognized node type: %d",
|
|
+ (int) nodeTag(j->larg));
|
|
+ if (IsA(j->rarg, RangeTblRef))
|
|
+ {
|
|
+ int varno = ((RangeTblRef *) j->rarg)->rtindex;
|
|
+
|
|
+ markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
|
+ }
|
|
+ else if (IsA(j->rarg, JoinExpr))
|
|
+ {
|
|
+ int varno = ((JoinExpr *) j->rarg)->rtindex;
|
|
+
|
|
+ markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
|
+ }
|
|
+ else
|
|
+ elog(ERROR, "unrecognized node type: %d",
|
|
+ (int) nodeTag(j->rarg));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /*
|
|
+ * Regular join attribute, look at the alias-variable list.
|
|
+ *
|
|
+ * The aliasvar could be either a Var or a COALESCE expression,
|
|
+ * but in the latter case we should already have marked the two
|
|
+ * referent variables as being selected, due to their use in the
|
|
+ * JOIN clause. So we need only be concerned with the simple
|
|
+ * Var case.
|
|
+ */
|
|
+ Var *aliasvar;
|
|
+
|
|
+ Assert(col > 0 && col <= list_length(rte->joinaliasvars));
|
|
+ aliasvar = (Var *) list_nth(rte->joinaliasvars, col - 1);
|
|
+ if (IsA(aliasvar, Var))
|
|
+ markVarForSelectPriv(pstate, aliasvar, NULL);
|
|
+ }
|
|
+ }
|
|
+ /* other RTE types don't require privilege marking */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * markVarForSelectPriv
|
|
+ * Mark the RTE referenced by a Var as requiring SELECT privilege
|
|
+ *
|
|
+ * The caller should pass the Var's referenced RTE if it has it handy
|
|
+ * (nearly all do); otherwise pass NULL.
|
|
+ */
|
|
+void
|
|
+markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte)
|
|
+{
|
|
+ Index lv;
|
|
+
|
|
+ Assert(IsA(var, Var));
|
|
+ /* Find the appropriate pstate if it's an uplevel Var */
|
|
+ for (lv = 0; lv < var->varlevelsup; lv++)
|
|
+ pstate = pstate->parentParseState;
|
|
+ markRTEForSelectPriv(pstate, rte, var->varno, var->varattno);
|
|
+}
|
|
+
|
|
+/*
|
|
* buildRelationAliases
|
|
* Construct the eref column name list for a relation RTE.
|
|
* This code is also used for the case of a function RTE returning
|
|
@@ -669,6 +788,8 @@ addRangeTableEntry(ParseState *pstate,
|
|
|
|
rte->requiredPerms = ACL_SELECT;
|
|
rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
|
|
+ rte->selectedCols = NULL;
|
|
+ rte->modifiedCols = NULL;
|
|
|
|
/*
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
@@ -722,6 +843,8 @@ addRangeTableEntryForRelation(ParseState
|
|
|
|
rte->requiredPerms = ACL_SELECT;
|
|
rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
|
|
+ rte->selectedCols = NULL;
|
|
+ rte->modifiedCols = NULL;
|
|
|
|
/*
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
@@ -800,6 +923,8 @@ addRangeTableEntryForSubquery(ParseState
|
|
|
|
rte->requiredPerms = 0;
|
|
rte->checkAsUser = InvalidOid;
|
|
+ rte->selectedCols = NULL;
|
|
+ rte->modifiedCols = NULL;
|
|
|
|
/*
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
@@ -928,6 +1053,8 @@ addRangeTableEntryForFunction(ParseState
|
|
|
|
rte->requiredPerms = 0;
|
|
rte->checkAsUser = InvalidOid;
|
|
+ rte->selectedCols = NULL;
|
|
+ rte->modifiedCols = NULL;
|
|
|
|
/*
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
@@ -997,6 +1124,8 @@ addRangeTableEntryForValues(ParseState *
|
|
rte->inFromCl = inFromCl;
|
|
rte->requiredPerms = 0;
|
|
rte->checkAsUser = InvalidOid;
|
|
+ rte->selectedCols = NULL;
|
|
+ rte->modifiedCols = NULL;
|
|
|
|
/*
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
@@ -1066,6 +1195,8 @@ addRangeTableEntryForJoin(ParseState *ps
|
|
|
|
rte->requiredPerms = 0;
|
|
rte->checkAsUser = InvalidOid;
|
|
+ rte->selectedCols = NULL;
|
|
+ rte->modifiedCols = NULL;
|
|
|
|
/*
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
@@ -1520,6 +1651,9 @@ expandRelAttrs(ParseState *pstate, Range
|
|
label,
|
|
false);
|
|
te_list = lappend(te_list, te);
|
|
+
|
|
+ /* Require read access to each column */
|
|
+ markVarForSelectPriv(pstate, (Var *) varnode, rte);
|
|
}
|
|
|
|
Assert(name == NULL && var == NULL); /* lists not the same length? */
|
|
diff -rpNU3 base/src/backend/parser/parse_target.c sepgsql-new/src/backend/parser/parse_target.c
|
|
--- base/src/backend/parser/parse_target.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/parser/parse_target.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -14,6 +14,7 @@
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
+#include "catalog/heap.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "commands/dbcommands.h"
|
|
#include "funcapi.h"
|
|
@@ -333,16 +334,33 @@ transformAssignedExpr(ParseState *pstate
|
|
Oid attrtype; /* type of target column */
|
|
int32 attrtypmod;
|
|
Relation rd = pstate->p_target_relation;
|
|
+ bool relhasoids = RelationGetForm(rd)->relhasoids;
|
|
|
|
Assert(rd != NULL);
|
|
- if (attrno <= 0)
|
|
- ereport(ERROR,
|
|
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
- errmsg("cannot assign to system column \"%s\"",
|
|
- colname),
|
|
- parser_errposition(pstate, location)));
|
|
- attrtype = attnumTypeId(rd, attrno);
|
|
- attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
|
|
+ if (attrno > 0)
|
|
+ {
|
|
+ attrtype = attnumTypeId(rd, attrno);
|
|
+ attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ Form_pg_attribute attr
|
|
+ = SystemAttributeDefinition(attrno, relhasoids);
|
|
+ if (attr && SystemAttributeIsWritable(attrno))
|
|
+ {
|
|
+ attrtype = attr->atttypid;
|
|
+ attrtypmod = attr->atttypmod;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("cannot assign to system column \"%s\"",
|
|
+ colname),
|
|
+ parser_errposition(pstate, location)));
|
|
+ return NULL; /* compiler kindness */
|
|
+ }
|
|
+ }
|
|
|
|
/*
|
|
* If the expression is a DEFAULT placeholder, insert the attribute's
|
|
@@ -483,6 +501,9 @@ updateTargetListEntry(ParseState *pstate
|
|
*/
|
|
tle->resno = (AttrNumber) attrno;
|
|
tle->resname = colname;
|
|
+
|
|
+ if (SystemAttributeIsWritable(attrno))
|
|
+ tle->resjunk = true;
|
|
}
|
|
|
|
|
|
@@ -749,6 +770,7 @@ checkInsertTargets(ParseState *pstate, L
|
|
Bitmapset *wholecols = NULL;
|
|
Bitmapset *partialcols = NULL;
|
|
ListCell *tl;
|
|
+ uint32 system_attrs = 0UL;
|
|
|
|
foreach(tl, cols)
|
|
{
|
|
@@ -757,14 +779,37 @@ checkInsertTargets(ParseState *pstate, L
|
|
int attrno;
|
|
|
|
/* Lookup column name, ereport on failure */
|
|
- attrno = attnameAttNum(pstate->p_target_relation, name, false);
|
|
+ attrno = attnameAttNum(pstate->p_target_relation, name, true);
|
|
if (attrno == InvalidAttrNumber)
|
|
+ {
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
errmsg("column \"%s\" of relation \"%s\" does not exist",
|
|
name,
|
|
RelationGetRelationName(pstate->p_target_relation)),
|
|
parser_errposition(pstate, col->location)));
|
|
+ }
|
|
+ else if (attrno < 0)
|
|
+ {
|
|
+ if (SystemAttributeIsWritable(attrno))
|
|
+ {
|
|
+ uint32 mask = (1<<(-attrno));
|
|
+
|
|
+ if ((system_attrs & mask) != 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_DUPLICATE_COLUMN),
|
|
+ errmsg("column \"%s\" specified more than once", name),
|
|
+ parser_errposition(pstate, col->location)));
|
|
+ system_attrs |= mask;
|
|
+ *attrnos = lappend_int(*attrnos, attrno);
|
|
+ continue;
|
|
+ }
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
+ errmsg("column \"%s\" of relation \"%s\" is system column",
|
|
+ name, RelationGetRelationName(pstate->p_target_relation)),
|
|
+ parser_errposition(pstate, col->location)));
|
|
+ }
|
|
|
|
/*
|
|
* Check for duplicates, but only of whole columns --- we allow
|
|
@@ -902,9 +947,25 @@ ExpandColumnRefStar(ParseState *pstate,
|
|
else
|
|
{
|
|
List *vars;
|
|
+ ListCell *l;
|
|
|
|
expandRTE(rte, rtindex, sublevels_up, false,
|
|
NULL, &vars);
|
|
+ /*
|
|
+ * Require read access to the table. This is normally redundant
|
|
+ * with the markVarForSelectPriv calls below, but not if the table
|
|
+ * has zero columns.
|
|
+ */
|
|
+ rte->requiredPerms |= ACL_SELECT;
|
|
+
|
|
+ /* Require read access to each column */
|
|
+ foreach(l, vars)
|
|
+ {
|
|
+ Var *var = (Var *) lfirst(l);
|
|
+
|
|
+ markVarForSelectPriv(pstate, var, rte);
|
|
+ }
|
|
+
|
|
return vars;
|
|
}
|
|
}
|
|
diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql-new/src/backend/postmaster/postmaster.c
|
|
--- base/src/backend/postmaster/postmaster.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql-new/src/backend/postmaster/postmaster.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -107,6 +107,7 @@
|
|
#include "postmaster/pgarch.h"
|
|
#include "postmaster/postmaster.h"
|
|
#include "postmaster/syslogger.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/pg_shmem.h"
|
|
@@ -214,7 +215,8 @@ static pid_t StartupPID = 0,
|
|
AutoVacPID = 0,
|
|
PgArchPID = 0,
|
|
PgStatPID = 0,
|
|
- SysLoggerPID = 0;
|
|
+ SysLoggerPID = 0,
|
|
+ sepgsqlWorkerPID = 0;
|
|
|
|
/* Startup/shutdown state */
|
|
#define NoShutdown 0
|
|
@@ -1321,6 +1323,10 @@ ServerLoop(void)
|
|
if (PgStatPID == 0 && pmState == PM_RUN)
|
|
PgStatPID = pgstat_start();
|
|
|
|
+ /* If we have lost the sepgsql worker (if needed), try to start a new one */
|
|
+ if (sepgsqlWorkerPID == 0 && pmState == PM_RUN)
|
|
+ sepgsqlWorkerPID = sepgsqlStartupWorkerProcess();
|
|
+
|
|
/*
|
|
* Touch the socket and lock file every 58 minutes, to ensure that
|
|
* they are not removed by overzealous /tmp-cleaning tasks. We assume
|
|
@@ -1911,6 +1917,8 @@ SIGHUP_handler(SIGNAL_ARGS)
|
|
signal_child(PgArchPID, SIGHUP);
|
|
if (SysLoggerPID != 0)
|
|
signal_child(SysLoggerPID, SIGHUP);
|
|
+ if (sepgsqlWorkerPID != 0)
|
|
+ signal_child(sepgsqlWorkerPID, SIGHUP);
|
|
/* PgStatPID does not currently need SIGHUP */
|
|
|
|
/* Reload authentication config files too */
|
|
@@ -1968,6 +1976,9 @@ pmdie(SIGNAL_ARGS)
|
|
/* and the walwriter too */
|
|
if (WalWriterPID != 0)
|
|
signal_child(WalWriterPID, SIGTERM);
|
|
+ /* and the sepgsql worker too */
|
|
+ if (sepgsqlWorkerPID != 0)
|
|
+ signal_child(sepgsqlWorkerPID, SIGTERM);
|
|
pmState = PM_WAIT_BACKENDS;
|
|
}
|
|
|
|
@@ -2006,6 +2017,9 @@ pmdie(SIGNAL_ARGS)
|
|
/* and the walwriter too */
|
|
if (WalWriterPID != 0)
|
|
signal_child(WalWriterPID, SIGTERM);
|
|
+ /* and the walwriter too */
|
|
+ if (sepgsqlWorkerPID != 0)
|
|
+ signal_child(sepgsqlWorkerPID, SIGTERM);
|
|
pmState = PM_WAIT_BACKENDS;
|
|
}
|
|
|
|
@@ -2039,6 +2053,8 @@ pmdie(SIGNAL_ARGS)
|
|
signal_child(PgArchPID, SIGQUIT);
|
|
if (PgStatPID != 0)
|
|
signal_child(PgStatPID, SIGQUIT);
|
|
+ if (sepgsqlWorkerPID != 0)
|
|
+ signal_child(sepgsqlWorkerPID, SIGQUIT);
|
|
ExitPostmaster(0);
|
|
break;
|
|
}
|
|
@@ -2287,6 +2303,16 @@ reaper(SIGNAL_ARGS)
|
|
continue;
|
|
}
|
|
|
|
+ /* Was it the sepgsql worker process? */
|
|
+ if (pid == sepgsqlWorkerPID)
|
|
+ {
|
|
+ sepgsqlWorkerPID = 0;
|
|
+ if (!EXIT_STATUS_0(exitstatus))
|
|
+ LogChildExit(LOG, _("SE-PostgreSQL worker process"),
|
|
+ pid, exitstatus);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
/*
|
|
* Else do standard backend child cleanup.
|
|
*/
|
|
@@ -2454,6 +2480,18 @@ HandleChildCrash(int pid, int exitstatus
|
|
signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
|
|
}
|
|
|
|
+ /* Take care of the sepgsql worker too */
|
|
+ if (pid == sepgsqlWorkerPID)
|
|
+ sepgsqlWorkerPID = 0;
|
|
+ else if (sepgsqlWorkerPID != 0 && !FatalError)
|
|
+ {
|
|
+ ereport(DEBUG2,
|
|
+ (errmsg_internal("sending %s to process %d",
|
|
+ (SendStop ? "SIGSTOP" : "SIGQUIT"),
|
|
+ (int) sepgsqlWorkerPID)));
|
|
+ signal_child(sepgsqlWorkerPID, (SendStop ? SIGSTOP : SIGQUIT));
|
|
+ }
|
|
+
|
|
/*
|
|
* Force a power-cycle of the pgarch process too. (This isn't absolutely
|
|
* necessary, but it seems like a good idea for robustness, and it
|
|
@@ -2573,7 +2611,8 @@ PostmasterStateMachine(void)
|
|
StartupPID == 0 &&
|
|
(BgWriterPID == 0 || !FatalError) &&
|
|
WalWriterPID == 0 &&
|
|
- AutoVacPID == 0)
|
|
+ AutoVacPID == 0 &&
|
|
+ sepgsqlWorkerPID == 0)
|
|
{
|
|
if (FatalError)
|
|
{
|
|
diff -rpNU3 base/src/backend/rewrite/rewriteHandler.c sepgsql-new/src/backend/rewrite/rewriteHandler.c
|
|
--- base/src/backend/rewrite/rewriteHandler.c 2008-11-05 09:57:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/rewrite/rewriteHandler.c 2009-03-13 13:09:47.000000000 +0900
|
|
@@ -1168,9 +1168,13 @@ ApplyRetrieveRule(Query *parsetree,
|
|
Assert(subrte->relid == relation->rd_id);
|
|
subrte->requiredPerms = rte->requiredPerms;
|
|
subrte->checkAsUser = rte->checkAsUser;
|
|
+ subrte->selectedCols = rte->selectedCols;
|
|
+ subrte->modifiedCols = rte->modifiedCols;
|
|
|
|
rte->requiredPerms = 0; /* no permission check on subquery itself */
|
|
rte->checkAsUser = InvalidOid;
|
|
+ rte->selectedCols = NULL;
|
|
+ rte->modifiedCols = NULL;
|
|
|
|
/*
|
|
* FOR UPDATE/SHARE of view?
|
|
diff -rpNU3 base/src/backend/security/Makefile sepgsql-new/src/backend/security/Makefile
|
|
--- base/src/backend/security/Makefile 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/Makefile 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,34 @@
|
|
+#
|
|
+# src/backend/security/Makefile
|
|
+# Makefile for Security Purpose Extensions
|
|
+#
|
|
+# Copyright (c) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+#
|
|
+subdir = src/backend/security
|
|
+top_builddir = ../../..
|
|
+include $(top_builddir)/src/Makefile.global
|
|
+
|
|
+
|
|
+OBJS := rowlevel.o
|
|
+
|
|
+ifeq ($(enable_selinux), yes)
|
|
+OBJS += sepgsql/avc.o sepgsql/checker.o sepgsql/core.o \
|
|
+ sepgsql/hooks.o sepgsql/label.o sepgsql/perms.o
|
|
+else
|
|
+OBJS += sepgsql/dummy.o
|
|
+endif
|
|
+
|
|
+all: SUBSYS.o
|
|
+
|
|
+SUBSYS.o: $(OBJS)
|
|
+ $(LD) $(LDREL) $(LDOUT) $@ $^
|
|
+
|
|
+depend dep:
|
|
+ $(CC) -MM $(CFLAGS) *.c >depend
|
|
+
|
|
+clean:
|
|
+ rm -f SUBSYS.o $(OBJS)
|
|
+
|
|
+ifeq (depend,$(wildcard depend))
|
|
+include depend
|
|
+endif
|
|
diff -rpNU3 base/src/backend/security/rowlevel.c sepgsql-new/src/backend/security/rowlevel.c
|
|
--- base/src/backend/security/rowlevel.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/rowlevel.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,165 @@
|
|
+/*
|
|
+ * src/backend/security/common.c
|
|
+ * common facilities for row-level access controls both of DAC and MAC
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/heapam.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "security/rowlevel.h"
|
|
+#include "security/sepgsql.h"
|
|
+#include "storage/bufmgr.h"
|
|
+#include "storage/bufpage.h"
|
|
+#include "utils/rel.h"
|
|
+
|
|
+/*
|
|
+ * rowlvBehaviorSwitchTo
|
|
+ *
|
|
+ * switches current behavior of the row level access control features.
|
|
+ * In the default, it works as a filter to skip fetching violated tuples
|
|
+ * at the ExecScan(). However, we should not apply simple filtering
|
|
+ * policy at a few exceptions, during checks of FK constraints.
|
|
+ *
|
|
+ * PostgreSQL implements FK constraints as trigger functions.
|
|
+ * When we update or delete tuples within PK table, these triggers are
|
|
+ * invoked to check FK tables whether the mofified PK is refered, or not.
|
|
+ * In this case, we have to consider a possibility one or more invisible
|
|
+ * or untouchable tuples are refering the target PK. If we simply filter
|
|
+ * out these tuples in this case, it allows to delete refered PKs, keep
|
|
+ * the current value of FK on SET CASCADE rules, and so on.
|
|
+ *
|
|
+ * So, it is necessary to raise an error when invisible or untouchable
|
|
+ * ones are refering PKs. It also makes another issues.
|
|
+ * In the filtering strategy, any permission checks are done earlier
|
|
+ * than evaluations of WHERE clause, because user can give a malicious
|
|
+ * function as a condition with side effects which allows to expose
|
|
+ * the contents of invisible tuples.
|
|
+ * However, when we adopt a strategy of "abort on violation", permission
|
|
+ * should be checked after the evaluation of WHERE clause, because it
|
|
+ * raises an error even if the given tuple is out of scopes. In this case,
|
|
+ * we have an assumption that WHERE clause is not malicious and does not
|
|
+ * has side effect.
|
|
+ * The built-in FK constraints always uses simple operators which are
|
|
+ * already cheked on installation both of database ACL and SELinux.
|
|
+ * So, it is possible to change the behavior during FK constraint.
|
|
+ * Elsewhere, we should apply filtering strategy, as far as we cannot
|
|
+ * ensure a malicious function is injected on WHERE clause.
|
|
+ */
|
|
+static bool rowlvAbortBehavior = false;
|
|
+
|
|
+bool
|
|
+rowlvBehaviorSwitchTo(bool new_abort)
|
|
+{
|
|
+ bool old_abort = rowlvAbortBehavior;
|
|
+
|
|
+ rowlvAbortBehavior = new_abort;
|
|
+
|
|
+ return old_abort;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * rowlvExecScan
|
|
+ * a hook to filter out invisible/untouchable tuples.
|
|
+ */
|
|
+bool
|
|
+rowlvExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ AclMode required = scan->requiredPerms;
|
|
+
|
|
+ /* It is not a time to make a decision */
|
|
+ if (rowlvAbortBehavior != abort)
|
|
+ return true;
|
|
+
|
|
+ /* skip row-level controls on virtual relation */
|
|
+ if (!rel)
|
|
+ return true;
|
|
+
|
|
+ tuple = ExecMaterializeSlot(slot);
|
|
+
|
|
+ if (!sepgsqlExecScan(rel, tuple, required, abort))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * rowlvHeapTupleInsert
|
|
+ * assigns default acl and label on a newly inserted tuple, and checks
|
|
+ * permissions on insert a tuple.
|
|
+ */
|
|
+bool
|
|
+rowlvHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal)
|
|
+{
|
|
+ if (!sepgsqlHeapTupleInsert(rel, newtup, internal))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * rowlvHeapTupleUpdate
|
|
+ * preserves original acl and label if necessary, and checks
|
|
+ * permissions on update a tuple.
|
|
+ */
|
|
+bool
|
|
+rowlvHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup, bool internal)
|
|
+{
|
|
+ HeapTupleData oldtup;
|
|
+ Buffer oldbuf;
|
|
+
|
|
+ ItemPointerCopy(otid, &oldtup.t_self);
|
|
+ if (!heap_fetch(rel, SnapshotAny, &oldtup, &oldbuf, false, NULL))
|
|
+ elog(ERROR, "failed to fetch a tuple for row-level access controls");
|
|
+
|
|
+ if (!sepgsqlHeapTupleUpdate(rel, &oldtup, newtup, internal))
|
|
+ {
|
|
+ ReleaseBuffer(oldbuf);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ ReleaseBuffer(oldbuf);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * rowlvHeapTupleDelete
|
|
+ * checks permissions on delete a tuple.
|
|
+ */
|
|
+bool
|
|
+rowlvHeapTupleDelete(Relation rel, ItemPointer otid, bool internal)
|
|
+{
|
|
+ HeapTupleData oldtup;
|
|
+ Buffer oldbuf;
|
|
+
|
|
+ ItemPointerCopy(otid, &oldtup.t_self);
|
|
+ if (!heap_fetch(rel, SnapshotAny, &oldtup, &oldbuf, false, NULL))
|
|
+ elog(ERROR, "failed to fetch a tuple for row-level access controls");
|
|
+
|
|
+ if (!sepgsqlHeapTupleDelete(rel, &oldtup, internal))
|
|
+ {
|
|
+ ReleaseBuffer(oldbuf);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ ReleaseBuffer(oldbuf);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * rowlvCopyToTuple
|
|
+ * checks permission on fetched tuple
|
|
+ */
|
|
+bool
|
|
+rowlvCopyToTuple(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ AclMode required = ACL_SELECT;
|
|
+
|
|
+ if (!sepgsqlExecScan(rel, tuple, required, false))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql-new/src/backend/security/sepgsql/avc.c
|
|
--- base/src/backend/security/sepgsql/avc.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/sepgsql/avc.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,840 @@
|
|
+/*
|
|
+ * src/backend/security/sepgsql/avc.c
|
|
+ * SE-PostgreSQL userspace access vector cache
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/hash.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "libpq/pqsignal.h"
|
|
+#include "postmaster/postmaster.h"
|
|
+#include "security/sepgsql.h"
|
|
+#include "storage/ipc.h"
|
|
+#include "storage/lwlock.h"
|
|
+#include "utils/memutils.h"
|
|
+#include "utils/syscache.h"
|
|
+#include <linux/netlink.h>
|
|
+#include <linux/selinux_netlink.h>
|
|
+#include <signal.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+/*
|
|
+ * AVC: userspace Access Vector Cache
|
|
+ *
|
|
+ * SE-PostgreSQL makes inqueries for SELinux to check whether the security
|
|
+ * policy allows the required action, or not. However, it need to invoke
|
|
+ * system call because SELinux is a kernel feature and it hold its security
|
|
+ * policy in the kernel memory.
|
|
+ *
|
|
+ * AVC enables to reduce the number of kernel invocation, with caching
|
|
+ * the result of inquiries. When we have to make a decision based on the
|
|
+ * security policy of SELinux, it tries to find up an appropriate cache
|
|
+ * entry on the uAVC. If exist, we don't need to invoke a system call
|
|
+ * and can reduce unnecessary overhead.
|
|
+ *
|
|
+ * If not exist, SE-PostgreSQL makes a new cache entry based on the
|
|
+ * result of inquiries, and chains it on uAVC to prepare the following
|
|
+ * decision makings.
|
|
+ *
|
|
+ * uAVC has a version number to check whether it is now valid, or not.
|
|
+ * Not need to say, uAVC cache entry has to be invalid just after
|
|
+ * policy reloaded or state change.
|
|
+ * If it is not match the latest one, updated by the policy state
|
|
+ * monitoring process, uAVC has to be reseted.
|
|
+ */
|
|
+static MemoryContext AvcMemCtx;
|
|
+
|
|
+#define AVC_HASH_NUM_SLOTS 256
|
|
+#define AVC_HASH_NUM_NODES 180
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ uint32 hash_key;
|
|
+
|
|
+ security_class_t tclass;
|
|
+ sepgsql_sid_t tsid;
|
|
+ sepgsql_sid_t nsid;
|
|
+ security_context_t ncontext;
|
|
+
|
|
+ access_vector_t allowed;
|
|
+ access_vector_t decided;
|
|
+ access_vector_t auditallow;
|
|
+ access_vector_t auditdeny;
|
|
+
|
|
+ bool hot_cache;
|
|
+} avc_datum;
|
|
+
|
|
+typedef struct avc_page
|
|
+{
|
|
+ struct avc_page *next;
|
|
+
|
|
+ int avc_version; /* copied from global state */
|
|
+
|
|
+ bool avc_enforcing; /* copied from global state */
|
|
+
|
|
+ security_context_t scontext;
|
|
+
|
|
+ List *slot[AVC_HASH_NUM_SLOTS];
|
|
+
|
|
+ uint32 avc_count;
|
|
+ uint32 lru_hint;
|
|
+} avc_page;
|
|
+
|
|
+static avc_page *client_avc_page = NULL;
|
|
+
|
|
+/*
|
|
+ * selinux_state
|
|
+ *
|
|
+ * This structure shows the global state of SELinux and its security
|
|
+ * policy, and it is assigned on shared memory region.
|
|
+ *
|
|
+ * The selinux_state->version should be checked prior to any avc
|
|
+ * accesses. If avc_page->avc_version is not matched with the
|
|
+ * global state, it means security policy is reloaded, system booleans
|
|
+ * are changed, or working mode (enforcing/permissive) is changed.
|
|
+ * The selinux_state->enforcing means current working mode. If it it
|
|
+ * true, it works in enforcing mode, elsewhere permissive mode.
|
|
+ *
|
|
+ * The only process able to update these variable are policy state
|
|
+ * monitoring process forked by postmaster. It enables to receive
|
|
+ * notifications from the kernwl via netlink socket.
|
|
+ *
|
|
+ * These global state is protected by SepgsqlAvcLock LWlock, so
|
|
+ * we need to acquire this lock when it is refered.
|
|
+ */
|
|
+struct
|
|
+{
|
|
+ int version;
|
|
+
|
|
+ bool enforcing;
|
|
+
|
|
+} *selinux_state = NULL;
|
|
+
|
|
+Size
|
|
+sepgsqlShmemSize(void)
|
|
+{
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return 0;
|
|
+
|
|
+ return sizeof(*selinux_state);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsql_avc_reset
|
|
+ * clears all AVC entries and update its version.
|
|
+ * caller need to hold SepgsqlAvcLock
|
|
+ */
|
|
+static void
|
|
+sepgsql_avc_reset(void)
|
|
+{
|
|
+ MemoryContextReset(AvcMemCtx);
|
|
+
|
|
+ client_avc_page = NULL;
|
|
+
|
|
+ sepgsqlAvcSwitchClient();
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsql_avc_reclaim
|
|
+ * reclaims recently unused AVC entries, when the number of
|
|
+ * caches overs AVC_HASH_NUM_NODES.
|
|
+ */
|
|
+static void
|
|
+sepgsql_avc_reclaim(avc_page *page)
|
|
+{
|
|
+ ListCell *l;
|
|
+ avc_datum *cache;
|
|
+
|
|
+ while (page->avc_count > AVC_HASH_NUM_NODES)
|
|
+ {
|
|
+ foreach (l, page->slot[page->lru_hint])
|
|
+ {
|
|
+ cache = lfirst(l);
|
|
+
|
|
+ if (cache->hot_cache)
|
|
+ cache->hot_cache = false;
|
|
+ else
|
|
+ {
|
|
+ list_delete_ptr(page->slot[page->lru_hint], cache);
|
|
+ pfree(cache);
|
|
+ page->avc_count--;
|
|
+ }
|
|
+ }
|
|
+ page->lru_hint = (page->lru_hint + 1) % AVC_HASH_NUM_SLOTS;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * avc_audit_common
|
|
+ * generates an audit message on the give string buffer based on
|
|
+ * the given av_decision which means the resutl of permission checks.
|
|
+ */
|
|
+static void
|
|
+avc_audit_common(char *buffer, uint32 buflen,
|
|
+ security_context_t scontext,
|
|
+ security_context_t tcontext,
|
|
+ security_class_t tclass,
|
|
+ access_vector_t audited,
|
|
+ bool denied,
|
|
+ const char *audit_name)
|
|
+{
|
|
+ access_vector_t mask;
|
|
+ uint32 ofs = 0;
|
|
+
|
|
+ ofs += snprintf(buffer + ofs, buflen - ofs, "%s {",
|
|
+ denied ? "denied" : "granted");
|
|
+ for (mask = 1; audited != 0; mask <<= 1)
|
|
+ {
|
|
+ if (audited & mask)
|
|
+ ofs += snprintf(buffer + ofs, buflen - ofs, " %s",
|
|
+ sepgsqlGetPermissionString(tclass, mask));
|
|
+ audited &= ~mask;
|
|
+ }
|
|
+ ofs += snprintf(buffer + ofs, buflen - ofs, " } ");
|
|
+
|
|
+ ofs += snprintf(buffer + ofs, buflen - ofs,
|
|
+ "scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext,
|
|
+ sepgsqlGetClassString(tclass));
|
|
+
|
|
+ if (audit_name)
|
|
+ ofs += snprintf(buffer + ofs, buflen - ofs, " name=%s", audit_name);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * avc_make_entry
|
|
+ * makes a query to in-kernel SELinux and an avc_datum object to
|
|
+ * cache the result of SELinux's decision for access rights and
|
|
+ * default security context.
|
|
+ */
|
|
+#define avc_hash_key(tcontext, tclass) ((tsid) ^ ((tclass) << 3))
|
|
+
|
|
+static avc_datum *
|
|
+avc_make_entry(avc_page *page, sepgsql_sid_t tsid, security_class_t tclass)
|
|
+{
|
|
+ security_context_t scontext, tcontext, ncontext;
|
|
+ security_class_t tclass_ex;
|
|
+ MemoryContext oldctx;
|
|
+ struct av_decision avd;
|
|
+ avc_datum *cache;
|
|
+ uint32 hash_key, index;
|
|
+
|
|
+ hash_key = avc_hash_key(tsid, tclass);
|
|
+ index = hash_key % AVC_HASH_NUM_SLOTS;
|
|
+
|
|
+ oldctx = MemoryContextSwitchTo(AvcMemCtx);
|
|
+ cache = palloc0(sizeof(avc_datum));
|
|
+ cache->hash_key = hash_key;
|
|
+ cache->tsid = tsid;
|
|
+ cache->tclass = tclass;
|
|
+
|
|
+ scontext = page->scontext;
|
|
+ tcontext = securityLookupSecurityLabel(tsid);
|
|
+ if (!tcontext || !sepgsqlCheckValidSecurityLabel(tcontext))
|
|
+ tcontext = sepgsqlGetUnlabeledLabel();
|
|
+
|
|
+ tclass_ex = sepgsqlTransToExternalClass(tclass);
|
|
+
|
|
+ if (security_compute_av_raw(scontext, tcontext, tclass_ex, 0, &avd) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not compute av_decision: "
|
|
+ "scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext, sepgsqlGetClassString(tclass))));
|
|
+ sepgsqlTransToInternalPerms(tclass, &avd);
|
|
+
|
|
+ cache->allowed = avd.allowed;
|
|
+ cache->decided = avd.decided;
|
|
+ cache->auditallow = avd.auditallow;
|
|
+ cache->auditdeny = avd.auditdeny;
|
|
+ cache->hot_cache = true;
|
|
+
|
|
+ if (security_compute_create_raw(scontext, tcontext, tclass_ex, &ncontext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not compute new context: "
|
|
+ "scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext, sepgsqlGetClassString(tclass))));
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ cache->ncontext = pstrdup(ncontext);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(ncontext);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ freecon(ncontext);
|
|
+
|
|
+ sepgsql_avc_reclaim(page);
|
|
+
|
|
+ page->slot[index] = lcons(cache, page->slot[index]);
|
|
+
|
|
+ page->avc_count++;
|
|
+
|
|
+ MemoryContextSwitchTo(oldctx);
|
|
+
|
|
+ return cache;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * avc_lookup
|
|
+ * It lookups required avc entry. Because it also checks avc_version
|
|
+ * on the global state, the caller has to hold SepgsqlAvcLock.
|
|
+ */
|
|
+static avc_datum *
|
|
+avc_lookup(avc_page *page, sepgsql_sid_t tsid, security_class_t tclass)
|
|
+{
|
|
+ avc_datum *cache = NULL;
|
|
+ uint32 hash_key, index;
|
|
+ ListCell *l;
|
|
+
|
|
+ /* check avc invalidation */
|
|
+ if (page->avc_version != selinux_state->version)
|
|
+ sepgsql_avc_reset();
|
|
+
|
|
+ /* lookup avc entry */
|
|
+ hash_key = avc_hash_key(tsid, tclass);
|
|
+ index = hash_key % AVC_HASH_NUM_SLOTS;
|
|
+
|
|
+ foreach (l, page->slot[index])
|
|
+ {
|
|
+ cache = lfirst(l);
|
|
+ if (cache->hash_key == hash_key
|
|
+ && cache->tclass == tclass
|
|
+ && cache->tsid == tsid)
|
|
+ {
|
|
+ cache->hot_cache = true;
|
|
+ return cache;
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlAvcSwitchClientLabel()
|
|
+ * switches current avc_page.
|
|
+ *
|
|
+ * NOTE: In most cases, SE-PostgreSQL checks whether client is allowed
|
|
+ * to do required actions (like SELECT, UPDATE, ...) on the targets.
|
|
+ * Both of client and targets have its security context, and all rules
|
|
+ * are described as relationship between security context of a client,
|
|
+ * a target and kind of actions.
|
|
+ * However, the security context of client is unchanged in SE-PostgreSQL
|
|
+ * (an exception is invocation of trusted procedure), so we can omit
|
|
+ * to compare security context of client with entries of uAVC.
|
|
+ * The avc_page is a set of avc_datum sorted out by the security context
|
|
+ * of client, so we can lookup correct avc_datum on currently focued
|
|
+ * avc_page without comparing the security context of client.
|
|
+ * The reason why we don't not use a unique uAVC is the security context
|
|
+ * of client does not have its security identifier on pg_security, so
|
|
+ * it requires strcmp() for each entries, but it is heavier than integer
|
|
+ * comparisons.
|
|
+ * Thus we have to switch current avc_page, whenever the security context
|
|
+ * of client changes (via trusted procedure). It makes performance well
|
|
+ * in most cases.
|
|
+ */
|
|
+static avc_page *
|
|
+sepgsqlAvcSwitch(avc_page *old_page, security_context_t scontext)
|
|
+{
|
|
+ MemoryContext oldctx;
|
|
+ avc_page *new_page;
|
|
+ int i;
|
|
+
|
|
+ if (old_page)
|
|
+ {
|
|
+ new_page = old_page;
|
|
+ do {
|
|
+ if (strcmp(new_page->scontext, scontext) == 0)
|
|
+ return new_page;
|
|
+
|
|
+ new_page = old_page->next;
|
|
+ } while (new_page != old_page);
|
|
+ }
|
|
+
|
|
+ /* Not found, so create a new avc_page */
|
|
+ oldctx = MemoryContextSwitchTo(AvcMemCtx);
|
|
+ new_page = palloc0(sizeof(avc_page));
|
|
+ new_page->scontext = pstrdup(scontext);
|
|
+ MemoryContextSwitchTo(oldctx);
|
|
+
|
|
+ for (i=0; i < AVC_HASH_NUM_SLOTS; i++)
|
|
+ new_page->slot[i] = NIL;
|
|
+
|
|
+ /* copy the global state of SELinux */
|
|
+ new_page->avc_version = selinux_state->version;
|
|
+ new_page->avc_enforcing = selinux_state->enforcing;
|
|
+
|
|
+ if (!old_page)
|
|
+ {
|
|
+ new_page->next = new_page;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ new_page->next = old_page->next;
|
|
+ old_page->next = new_page;
|
|
+ }
|
|
+
|
|
+ return new_page;
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlAvcSwitchClient(void)
|
|
+{
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
|
|
+ client_avc_page = sepgsqlAvcSwitch(client_avc_page,
|
|
+ sepgsqlGetClientLabel());
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlClientHasPerms
|
|
+ * checks client's privileges on given objects via uAVC.
|
|
+ */
|
|
+bool
|
|
+sepgsqlClientHasPerms(sepgsql_sid_t tsid,
|
|
+ security_class_t tclass,
|
|
+ access_vector_t required,
|
|
+ const char *audit_name, bool abort)
|
|
+{
|
|
+ char audit_buffer[2048];
|
|
+ access_vector_t denied, audited;
|
|
+ avc_datum *cache;
|
|
+ bool rc = true;
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
|
|
+ cache = avc_lookup(client_avc_page, tsid, tclass);
|
|
+ if (!cache)
|
|
+ cache = avc_make_entry(client_avc_page, tsid, tclass);
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ denied = required & ~cache->allowed;
|
|
+ audited = denied ? (denied & cache->auditdeny)
|
|
+ : (required & cache->auditallow);
|
|
+ if (audited)
|
|
+ {
|
|
+ security_context_t scon, tcon;
|
|
+
|
|
+ scon = sepgsqlSecurityLabelTransOut(client_avc_page->scontext);
|
|
+ tcon = securityTransSecLabelOut(tsid);
|
|
+
|
|
+ avc_audit_common(audit_buffer, sizeof(audit_buffer),
|
|
+ scon, tcon, cache->tclass,
|
|
+ audited, !!denied, audit_name);
|
|
+ pfree(scon);
|
|
+ pfree(tcon);
|
|
+ }
|
|
+
|
|
+ if (!required || denied)
|
|
+ {
|
|
+ if (client_avc_page->avc_enforcing)
|
|
+ rc = false;
|
|
+ else
|
|
+ cache->allowed |= required; /* prevent flood of audit log */
|
|
+ }
|
|
+
|
|
+ if (audited)
|
|
+ ereport((!rc && abort) ? ERROR : NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_AUDIT),
|
|
+ errmsg("SELinux: %s", audit_buffer)));
|
|
+ else if (!rc && abort)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_AUDIT),
|
|
+ errmsg("SELinux: security policy violation")));
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlClientCreate
|
|
+ * sepgsqlClientCreateLabel
|
|
+ * It returns security label of database object newly created.
|
|
+ * sepgsqlClientCreate() returns it as sepgsql_sid_t, and
|
|
+ * sepgsqlClientCreateLabel() returns it as security_context_t.
|
|
+ * Please note that these types are not different in this version,
|
|
+ * but sepgsql_sid_t is planned to replace by an identifier.
|
|
+ */
|
|
+sepgsql_sid_t
|
|
+sepgsqlClientCreate(sepgsql_sid_t tsid, security_class_t tclass)
|
|
+{
|
|
+ avc_datum *cache;
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
|
|
+ cache = avc_lookup(client_avc_page, tsid, tclass);
|
|
+ if (!cache)
|
|
+ cache = avc_make_entry(client_avc_page, tsid, tclass);
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ if (!OidIsValid(cache->nsid))
|
|
+ cache->nsid = securityLookupSecurityId(cache->ncontext);
|
|
+
|
|
+ return cache->nsid;
|
|
+}
|
|
+
|
|
+security_context_t
|
|
+sepgsqlClientCreateLabel(sepgsql_sid_t tsid, security_class_t tclass)
|
|
+{
|
|
+ avc_datum *cache;
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
|
|
+ cache = avc_lookup(client_avc_page, tsid, tclass);
|
|
+ if (!cache)
|
|
+ cache = avc_make_entry(client_avc_page, tsid, tclass);
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ return cache->ncontext;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsql_shmem_init
|
|
+ * attaches shared memory segment.
|
|
+ */
|
|
+static void
|
|
+sepgsql_shmem_init(void)
|
|
+{
|
|
+ bool found;
|
|
+
|
|
+ selinux_state = ShmemInitStruct("SELinux policy state",
|
|
+ sepgsqlShmemSize(), &found);
|
|
+ if (!found)
|
|
+ {
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
|
|
+
|
|
+ selinux_state->version = 0;
|
|
+ selinux_state->enforcing = (security_getenforce() > 0);
|
|
+
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlAvcInit
|
|
+ * initialize local uAVC facility.
|
|
+ */
|
|
+void
|
|
+sepgsqlAvcInit(void)
|
|
+{
|
|
+ /*
|
|
+ * local memory context
|
|
+ */
|
|
+ AvcMemCtx = AllocSetContextCreate(TopMemoryContext,
|
|
+ "SE-PostgreSQL userspace avc",
|
|
+ ALLOCSET_DEFAULT_MINSIZE,
|
|
+ ALLOCSET_DEFAULT_INITSIZE,
|
|
+ ALLOCSET_DEFAULT_MAXSIZE);
|
|
+ sepgsql_shmem_init();
|
|
+
|
|
+ /*
|
|
+ * reset local avc
|
|
+ */
|
|
+ sepgsql_avc_reset();
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlComputePerms
|
|
+ * sepgsqlComputeCreate
|
|
+ *
|
|
+ * The following two functions make a query to in-kernel SELinux
|
|
+ * without userspace caches, due to some reasons.
|
|
+ * The AVC can cover most of cases, but some of corner cases are
|
|
+ * not suitable for AVC structure, so we need uncached interfaces.
|
|
+ * For example, AVC is unavailable when we tries to load a shared
|
|
+ * library module, because security context of the library does not
|
|
+ * have its security identifier, so we cannot put it on AVC.
|
|
+ */
|
|
+bool
|
|
+sepgsqlComputePerms(security_context_t scontext,
|
|
+ security_context_t tcontext,
|
|
+ security_class_t tclass,
|
|
+ access_vector_t required,
|
|
+ const char *audit_name, bool abort)
|
|
+{
|
|
+ access_vector_t denied, audited;
|
|
+ security_class_t tclass_ex;
|
|
+ struct av_decision avd;
|
|
+ char audit_buffer[2048];
|
|
+ bool rc = true;
|
|
+
|
|
+ scontext = (!security_check_context_raw(scontext)
|
|
+ ? scontext : sepgsqlGetUnlabeledLabel());
|
|
+ tcontext = (!security_check_context_raw(tcontext)
|
|
+ ? tcontext : sepgsqlGetUnlabeledLabel());
|
|
+
|
|
+ tclass_ex = sepgsqlTransToExternalClass(tclass);
|
|
+ if (security_compute_av_raw(scontext, tcontext, tclass_ex, 0, &avd) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not compute an av_decision"
|
|
+ " scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext, sepgsqlGetClassString(tclass))));
|
|
+ sepgsqlTransToInternalPerms(tclass, &avd);
|
|
+
|
|
+ denied = required & ~avd.allowed;
|
|
+ audited = denied ? (denied & avd.auditdeny) : (required & avd.auditallow);
|
|
+ if (audited)
|
|
+ {
|
|
+ security_context_t scon, tcon;
|
|
+
|
|
+ scon = sepgsqlSecurityLabelTransOut(scontext);
|
|
+ tcon = sepgsqlSecurityLabelTransOut(tcontext);
|
|
+
|
|
+ avc_audit_common(audit_buffer, sizeof(audit_buffer),
|
|
+ scon, tcon, tclass,
|
|
+ audited, !!denied, audit_name);
|
|
+ }
|
|
+
|
|
+ if (!required || denied)
|
|
+ {
|
|
+ if (security_getenforce() > 0)
|
|
+ rc = false;
|
|
+ }
|
|
+
|
|
+ if (audited)
|
|
+ ereport((!rc && abort) ? ERROR : NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_AUDIT),
|
|
+ errmsg("SELinux: %s", audit_buffer)));
|
|
+ else if (!rc && abort)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_AUDIT),
|
|
+ errmsg("SELinux: security policy violation")));
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+security_context_t
|
|
+sepgsqlComputeCreate(security_context_t scontext,
|
|
+ security_context_t tcontext,
|
|
+ security_class_t tclass)
|
|
+{
|
|
+ security_context_t ncontext, result;
|
|
+ security_class_t tclass_ex;
|
|
+
|
|
+ scontext = (!security_check_context_raw(scontext)
|
|
+ ? scontext : sepgsqlGetUnlabeledLabel());
|
|
+ tcontext = (!security_check_context_raw(tcontext)
|
|
+ ? tcontext : sepgsqlGetUnlabeledLabel());
|
|
+
|
|
+ tclass_ex = sepgsqlTransToExternalClass(tclass);
|
|
+ if (security_compute_create_raw(scontext, tcontext, tclass_ex, &ncontext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not compute a default context"
|
|
+ " scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext, sepgsqlGetClassString(tclass))));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(ncontext);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(ncontext);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ freecon(ncontext);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * SELinux state monitoring process
|
|
+ *
|
|
+ * This process is forked from postmaster to monitor the state of SELinux.
|
|
+ * SELinux can make a notifier message to userspace object manager via
|
|
+ * netlink socket. When it receives the message, it updates selinux_state
|
|
+ * structure assigned on shared memory region to make any instance reset
|
|
+ * its AVC soon.
|
|
+ */
|
|
+static int
|
|
+sepgsqlStateMonitorMain()
|
|
+{
|
|
+ char buffer[2048];
|
|
+ struct sockaddr_nl addr;
|
|
+ socklen_t addrlen;
|
|
+ struct nlmsghdr *nlh;
|
|
+ int rc, nl_sockfd;
|
|
+
|
|
+ /*
|
|
+ * map shared memory segment
|
|
+ */
|
|
+ sepgsql_shmem_init();
|
|
+
|
|
+ /*
|
|
+ * setup the signal handler
|
|
+ */
|
|
+ pqinitmask();
|
|
+ pqsignal(SIGHUP, SIG_IGN);
|
|
+ pqsignal(SIGINT, SIG_IGN);
|
|
+ pqsignal(SIGTERM, exit);
|
|
+ pqsignal(SIGQUIT, exit);
|
|
+ pqsignal(SIGUSR1, SIG_IGN);
|
|
+ pqsignal(SIGUSR2, SIG_IGN);
|
|
+ pqsignal(SIGCHLD, SIG_DFL);
|
|
+ PG_SETMASK(&UnBlockSig);
|
|
+
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_INFO),
|
|
+ errmsg("SELinux: policy state monitor process (pid: %u)",
|
|
+ getpid())));
|
|
+ /*
|
|
+ * open netlink socket
|
|
+ */
|
|
+ nl_sockfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_SELINUX);
|
|
+ if (nl_sockfd < 0)
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not open netlink socket")));
|
|
+ return 1;
|
|
+ }
|
|
+ memset(&addr, 0, sizeof(addr));
|
|
+ addr.nl_family = AF_NETLINK;
|
|
+ addr.nl_groups = SELNL_GRP_AVC;
|
|
+ if (bind(nl_sockfd, (struct sockaddr *) &addr, sizeof(addr)))
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not bind netlink socket")));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * waiting loop
|
|
+ */
|
|
+ while (true)
|
|
+ {
|
|
+ addrlen = sizeof(addr);
|
|
+ rc = recvfrom(nl_sockfd, buffer, sizeof(buffer), 0,
|
|
+ (struct sockaddr *) &addr, &addrlen);
|
|
+ if (rc < 0)
|
|
+ {
|
|
+ if (errno == EINTR)
|
|
+ continue;
|
|
+
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: error on netlink recvfrom(): %s",
|
|
+ strerror(errno))));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (addrlen != sizeof(addr))
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: netlink address truncated (len=%d)",
|
|
+ addrlen)));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (addr.nl_pid)
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: netlink received spoofed packet from: %u",
|
|
+ addr.nl_pid)));
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (rc == 0)
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: netlink received EOF")));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ nlh = (struct nlmsghdr *) buffer;
|
|
+ if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > (unsigned int) rc)
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: netlink incomplete message")));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ switch (nlh->nlmsg_type)
|
|
+ {
|
|
+ case SELNL_MSG_SETENFORCE:
|
|
+ {
|
|
+ struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh);
|
|
+
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_INFO),
|
|
+ errmsg("SELinux: setenforce notifier"
|
|
+ " (enforcing=%d)", msg->val)));
|
|
+ /* switch enforcing/permissive */
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
|
|
+ selinux_state->version = selinux_state->version + 1;
|
|
+ selinux_state->enforcing = msg->val ? true : false;
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+ break;
|
|
+ }
|
|
+ case SELNL_MSG_POLICYLOAD:
|
|
+ {
|
|
+ struct selnl_msg_policyload *msg = NLMSG_DATA(nlh);
|
|
+
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_INFO),
|
|
+ errmsg("policyload notifier (seqno=%d)",
|
|
+ msg->seqno)));
|
|
+
|
|
+ /* security policy reloaded */
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
|
|
+ selinux_state->version = selinux_state->version + 1;
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+ break;
|
|
+ }
|
|
+ case NLMSG_ERROR:
|
|
+ {
|
|
+ struct nlmsgerr *err = NLMSG_DATA(nlh);
|
|
+
|
|
+ if (err->error == 0)
|
|
+ break;
|
|
+
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: netlink error: %s",
|
|
+ strerror(-err->error))));
|
|
+ return 1;
|
|
+ }
|
|
+ default:
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("netlink unknown message type (%d)",
|
|
+ nlh->nlmsg_type)));
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+pid_t
|
|
+sepgsqlStartupWorkerProcess(void)
|
|
+{
|
|
+ pid_t chld;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return (pid_t) 0;
|
|
+
|
|
+ chld = fork();
|
|
+ if (chld == 0)
|
|
+ {
|
|
+ ClosePostmasterPorts(false);
|
|
+
|
|
+ on_exit_reset();
|
|
+
|
|
+ exit(sepgsqlStateMonitorMain());
|
|
+ }
|
|
+ else if (chld > 0)
|
|
+ return chld;
|
|
+
|
|
+ return (pid_t) 0;
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/checker.c sepgsql-new/src/backend/security/sepgsql/checker.c
|
|
--- base/src/backend/security/sepgsql/checker.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/sepgsql/checker.c 2009-03-15 17:38:39.000000000 +0900
|
|
@@ -0,0 +1,523 @@
|
|
+/*
|
|
+ * src/backend/security/sepgsql/checker.c
|
|
+ * walks on given Query tree and applies checks
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_language.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_proc.h"
|
|
+#include "catalog/pg_rewrite.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "security/sepgsql.h"
|
|
+#include "storage/bufmgr.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/lsyscache.h"
|
|
+#include "utils/syscache.h"
|
|
+#include "utils/tqual.h"
|
|
+
|
|
+/*
|
|
+ * fixupWholeRowReference
|
|
+ */
|
|
+static Bitmapset *
|
|
+fixupWholeRowReference(Oid relid, int nattrs, Bitmapset *columns)
|
|
+{
|
|
+ Bitmapset *result;
|
|
+ AttrNumber attno;
|
|
+
|
|
+ attno = InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber;
|
|
+
|
|
+ if (!bms_is_member(attno, columns))
|
|
+ return columns; /* no need to fixup */
|
|
+
|
|
+ result = bms_copy(columns);
|
|
+ result = bms_del_member(result, attno);
|
|
+
|
|
+ for (attno=1; attno <= nattrs; attno++)
|
|
+ {
|
|
+ Form_pg_attribute attform;
|
|
+ HeapTuple atttup;
|
|
+
|
|
+ atttup = SearchSysCache(ATTNUM,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ Int16GetDatum(attno),
|
|
+ 0, 0);
|
|
+ if (!HeapTupleIsValid(atttup))
|
|
+ continue;
|
|
+
|
|
+ attform = (Form_pg_attribute) GETSTRUCT(atttup);
|
|
+ if (!attform->attisdropped)
|
|
+ {
|
|
+ int cindex = attno - FirstLowInvalidHeapAttributeNumber;
|
|
+ result = bms_add_member(result, cindex);
|
|
+ }
|
|
+ ReleaseSysCache(atttup);
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * checkTabelColumnPerms
|
|
+ * This functions applies table/column level permissions for
|
|
+ * all the appeared ones in user's query, and raises an error
|
|
+ * if violated.
|
|
+ * It also applies a few hardwired policy which prevent to
|
|
+ * modified some of system catalogs.
|
|
+ */
|
|
+static void
|
|
+checkTabelColumnPerms(Oid relid, Bitmapset *selected, Bitmapset *modified,
|
|
+ access_vector_t required)
|
|
+{
|
|
+ Bitmapset *columns;
|
|
+ Bitmapset *selected_ex;
|
|
+ Bitmapset *modified_ex;
|
|
+ HeapTuple tuple;
|
|
+ AttrNumber attno;
|
|
+ int nattrs;
|
|
+ const char *audit_name;
|
|
+
|
|
+ /*
|
|
+ * NOTE: HARDWIRED POLICY IN SE-POSTGRESQL
|
|
+ * - User cannot modify pg_rewrite.* by hand, because it holds
|
|
+ * a parsed Query tree which includes requiredPerms and
|
|
+ * RangeTblEntry with selectedCols/modifiedCols.
|
|
+ * The correctness of access controls depends on these data
|
|
+ * are protected from unexpected manipulation..
|
|
+ *
|
|
+ * SE-PostgreSQL always prevent user's query tries to modify
|
|
+ * these system catalogs by hand. Please use approariate
|
|
+ * interfaces.
|
|
+ */
|
|
+ if ((required & (SEPG_DB_TABLE__UPDATE
|
|
+ | SEPG_DB_TABLE__INSERT
|
|
+ | SEPG_DB_TABLE__DELETE)) != 0 &&
|
|
+ (relid == RewriteRelationId ||
|
|
+ relid == LargeObjectRelationId ||
|
|
+ relid == SecurityRelationId))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SE-PostgreSQL peremptorily prevent to modify "
|
|
+ "\"%s\" system catalog by hand", get_rel_name(relid))));
|
|
+
|
|
+ /*
|
|
+ * Check db_table:{...} permissions
|
|
+ */
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation %u", relid);
|
|
+
|
|
+ /* ignore, if the relation is not db_table class */
|
|
+ if (sepgsqlTupleObjectClass(RelationRelationId, tuple)
|
|
+ != SEPG_CLASS_DB_TABLE)
|
|
+ {
|
|
+ ReleaseSysCache(tuple);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ audit_name = sepgsqlAuditName(RelationRelationId, tuple);
|
|
+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple),
|
|
+ SEPG_CLASS_DB_TABLE,
|
|
+ required,
|
|
+ audit_name, true);
|
|
+
|
|
+ nattrs = ((Form_pg_class) GETSTRUCT(tuple))->relnatts;
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ /*
|
|
+ * Check db_column:{...} permissions
|
|
+ */
|
|
+ selected_ex = fixupWholeRowReference(relid, nattrs, selected);
|
|
+ modified_ex = fixupWholeRowReference(relid, nattrs, modified);
|
|
+ columns = bms_union(selected_ex, modified_ex);
|
|
+
|
|
+ while ((attno = bms_first_member(columns)) >= 0)
|
|
+ {
|
|
+ Form_pg_attribute attForm;
|
|
+ access_vector_t attperms = 0;
|
|
+
|
|
+ if (bms_is_member(attno, selected_ex))
|
|
+ attperms |= SEPG_DB_COLUMN__SELECT;
|
|
+ if (bms_is_member(attno, modified_ex))
|
|
+ {
|
|
+ if (required & SEPG_DB_TABLE__UPDATE)
|
|
+ attperms |= SEPG_DB_COLUMN__UPDATE;
|
|
+ if (required & SEPG_DB_TABLE__INSERT)
|
|
+ attperms |= SEPG_DB_COLUMN__INSERT;
|
|
+ }
|
|
+ if (attperms == 0)
|
|
+ continue;
|
|
+
|
|
+ /* remove the attribute number offset */
|
|
+ attno += FirstLowInvalidHeapAttributeNumber;
|
|
+ tuple = SearchSysCache(ATTNUM,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ Int16GetDatum(attno),
|
|
+ 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
|
|
+ attno, relid);
|
|
+
|
|
+ attForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ if (attForm->attisdropped)
|
|
+ elog(ERROR, "attribute %d of relation %u does not exist",
|
|
+ attno, relid);
|
|
+
|
|
+ audit_name = sepgsqlAuditName(AttributeRelationId, tuple);
|
|
+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple),
|
|
+ SEPG_CLASS_DB_COLUMN,
|
|
+ attperms,
|
|
+ audit_name, true);
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ if (selected_ex != selected)
|
|
+ bms_free(selected_ex);
|
|
+
|
|
+ if (modified_ex != modified)
|
|
+ bms_free(modified_ex);
|
|
+
|
|
+ bms_free(columns);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckQueryPerms
|
|
+ * It checks permission for all the required tables/columns on
|
|
+ * generic user queries.
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckRTEPerms(RangeTblEntry *rte)
|
|
+{
|
|
+ access_vector_t required = 0;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ if (rte->rtekind != RTE_RELATION)
|
|
+ return;
|
|
+
|
|
+ if (rte->requiredPerms & ACL_SELECT)
|
|
+ required |= SEPG_DB_TABLE__SELECT;
|
|
+ if (rte->requiredPerms & ACL_INSERT)
|
|
+ required |= SEPG_DB_TABLE__INSERT;
|
|
+ if (rte->requiredPerms & ACL_UPDATE)
|
|
+ required |= SEPG_DB_TABLE__UPDATE;
|
|
+ if (rte->requiredPerms & ACL_DELETE)
|
|
+ required |= SEPG_DB_TABLE__DELETE;
|
|
+ /*
|
|
+ * TODO: we should add SEPG_DB_TABLE__LOCK here,
|
|
+ * but ACL_SELECT_FOR_UPDATE has same value now.
|
|
+ */
|
|
+ if (required == 0)
|
|
+ return;
|
|
+
|
|
+ checkTabelColumnPerms(rte->relid,
|
|
+ rte->selectedCols,
|
|
+ rte->modifiedCols,
|
|
+ required);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckCopyTable
|
|
+ * It checks permissions on COPY TO/FROM.
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckCopyTable(Relation rel, List *attnumlist, bool is_from)
|
|
+{
|
|
+ Bitmapset *selected = NULL;
|
|
+ Bitmapset *modified = NULL;
|
|
+ ListCell *l;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ /* all checkes are done in sepgsqlCheckRTEPerms */
|
|
+ if (!rel)
|
|
+ return;
|
|
+
|
|
+ foreach (l, attnumlist)
|
|
+ {
|
|
+ AttrNumber attno = lfirst_int(l);
|
|
+
|
|
+ attno -= FirstLowInvalidHeapAttributeNumber;
|
|
+ if (is_from)
|
|
+ modified = bms_add_member(modified, attno);
|
|
+ else
|
|
+ selected = bms_add_member(selected, attno);
|
|
+ }
|
|
+
|
|
+ checkTabelColumnPerms(RelationGetRelid(rel),
|
|
+ selected, modified,
|
|
+ is_from ? SEPG_DB_TABLE__INSERT
|
|
+ : SEPG_DB_TABLE__SELECT);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckSelectInto
|
|
+ * It checks db_table/db_column:{insert} on the table newly created
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckSelectInto(Oid relationId)
|
|
+{
|
|
+ Bitmapset *modified = NULL;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ modified = bms_add_member(modified, InvalidAttrNumber
|
|
+ - FirstLowInvalidHeapAttributeNumber);
|
|
+
|
|
+ checkTabelColumnPerms(relationId, NULL, modified,
|
|
+ SEPG_DB_TABLE__INSERT);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * fixupColumnAvPerms
|
|
+ * To change pg_attribute.attisdropped means dropping a column,
|
|
+ * although this operation done by update, so it need to change
|
|
+ * required permmision in this special case.
|
|
+ */
|
|
+static access_vector_t
|
|
+fixupColumnAvPerms(HeapTuple newtup, HeapTuple oldtup)
|
|
+{
|
|
+ Form_pg_attribute oldatt = (Form_pg_attribute) GETSTRUCT(oldtup);
|
|
+ Form_pg_attribute newatt = (Form_pg_attribute) GETSTRUCT(newtup);
|
|
+
|
|
+ if (!oldatt->attisdropped && newatt->attisdropped)
|
|
+ return SEPG_DB_COLUMN__DROP;
|
|
+ if (oldatt->attisdropped && !newatt->attisdropped)
|
|
+ return SEPG_DB_COLUMN__CREATE;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * checkCLibraryInstallation
|
|
+ * It checks the correctness of C-library when user tries to
|
|
+ * create / replace C-functions.
|
|
+ */
|
|
+static void
|
|
+checkCLibraryInstallation(HeapTuple newtup, HeapTuple oldtup)
|
|
+{
|
|
+ Form_pg_proc oldpro, newpro;
|
|
+ Datum oldbin, newbin;
|
|
+ char *filename;
|
|
+ bool isnull;
|
|
+
|
|
+ newpro = (Form_pg_proc) GETSTRUCT(newtup);
|
|
+ if (newpro->prolang != ClanguageId)
|
|
+ return;
|
|
+
|
|
+ newbin = SysCacheGetAttr(PROCOID, newtup,
|
|
+ Anum_pg_proc_probin, &isnull);
|
|
+ if (isnull)
|
|
+ return;
|
|
+
|
|
+ if (HeapTupleIsValid(oldtup))
|
|
+ {
|
|
+ oldpro = (Form_pg_proc) GETSTRUCT(oldtup);
|
|
+ oldbin = SysCacheGetAttr(PROCOID, oldtup,
|
|
+ Anum_pg_proc_probin, &isnull);
|
|
+ if (!isnull &&
|
|
+ oldpro->prolang == newpro->prolang &&
|
|
+ DatumGetBool(DirectFunctionCall2(byteaeq, oldbin, newbin)))
|
|
+ return; /* no need to check, if unchanged */
|
|
+ }
|
|
+ filename = TextDatumGetCString(newbin);
|
|
+ sepgsqlCheckDatabaseInstallModule(filename);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Row-level decision making
|
|
+ */
|
|
+bool
|
|
+sepgsqlExecScan(Relation rel, HeapTuple tuple, AclMode required, bool abort)
|
|
+{
|
|
+ security_class_t tclass;
|
|
+ access_vector_t permissions = 0;
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (RelationGetForm(rel)->relkind != RELKIND_RELATION)
|
|
+ return true;
|
|
+
|
|
+ if (required & ACL_SELECT)
|
|
+ permissions |= SEPG_DB_TUPLE__SELECT;
|
|
+ if (required & ACL_UPDATE)
|
|
+ permissions |= SEPG_DB_TUPLE__UPDATE;
|
|
+ if (required & ACL_DELETE)
|
|
+ permissions |= SEPG_DB_TUPLE__DELETE;
|
|
+ if (permissions == 0)
|
|
+ return true;
|
|
+
|
|
+ audit_name = sepgsqlAuditName(RelationGetRelid(rel), tuple);
|
|
+ tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple);
|
|
+ return sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple),
|
|
+ tclass,
|
|
+ permissions,
|
|
+ audit_name, abort);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * checkTrustedAction
|
|
+ * It returns true, if we can ignore access controls for create/alter/drop
|
|
+ * on the given database objects.
|
|
+ */
|
|
+static bool
|
|
+checkTrustedAction(Relation rel, bool internal)
|
|
+{
|
|
+ if (RelationGetForm(rel)->relkind != RELKIND_RELATION)
|
|
+ return true;
|
|
+
|
|
+ if (RelationGetRelid(rel) == DatabaseRelationId ||
|
|
+ RelationGetRelid(rel) == RelationRelationId ||
|
|
+ RelationGetRelid(rel) == AttributeRelationId ||
|
|
+ RelationGetRelid(rel) == ProcedureRelationId)
|
|
+ return false;
|
|
+
|
|
+ if (internal &&
|
|
+ (RelationGetRelid(rel) == SecurityRelationId ||
|
|
+ RelationGetRelid(rel) == LargeObjectRelationId))
|
|
+ return true;
|
|
+
|
|
+ return !sepostgresql_row_level;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * HeapTuple INSERT/UPDATE/DELETE
|
|
+ */
|
|
+bool
|
|
+sepgsqlHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal)
|
|
+{
|
|
+ Oid relid = RelationGetRelid(rel);
|
|
+ security_class_t tclass;
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+
|
|
+ /* set default security context */
|
|
+ if (!OidIsValid(HeapTupleGetSecLabel(newtup)))
|
|
+ {
|
|
+ if (HeapTupleHasSecLabel(newtup))
|
|
+ sepgsqlSetDefaultSecLabel(rel, newtup);
|
|
+
|
|
+ /* need to check db_blob:{create} for the first tuple */
|
|
+ if (internal &&
|
|
+ RelationGetRelid(rel) == LargeObjectRelationId)
|
|
+ goto skip;
|
|
+ }
|
|
+
|
|
+ if (checkTrustedAction(rel, internal))
|
|
+ return true;
|
|
+
|
|
+ /* check binary library installation */
|
|
+ if (relid == ProcedureRelationId)
|
|
+ checkCLibraryInstallation(newtup, NULL);
|
|
+ /* check db_procedure:{install}, if necessary */
|
|
+ sepgsqlCheckProcedureInstall(rel, newtup, NULL);
|
|
+
|
|
+skip:
|
|
+ tclass = sepgsqlTupleObjectClass(relid, newtup);
|
|
+ audit_name = sepgsqlAuditName(relid, newtup);
|
|
+ return sepgsqlClientHasPerms(HeapTupleGetSecLabel(newtup),
|
|
+ tclass,
|
|
+ SEPG_DB_TUPLE__INSERT,
|
|
+ audit_name, internal);
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlHeapTupleUpdate(Relation rel, HeapTuple oldtup,
|
|
+ HeapTuple newtup, bool internal)
|
|
+{
|
|
+ Oid relid = RelationGetRelid(rel);
|
|
+ access_vector_t required = 0;
|
|
+ security_class_t tclass;
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+
|
|
+ /* preserve security label, if unchanged */
|
|
+ if (!OidIsValid(HeapTupleGetSecLabel(newtup)))
|
|
+ {
|
|
+ sepgsql_sid_t oldsid = HeapTupleGetSecLabel(oldtup);
|
|
+
|
|
+ if (HeapTupleHasSecLabel(newtup))
|
|
+ HeapTupleSetSecLabel(newtup, oldsid);
|
|
+ }
|
|
+
|
|
+ if (checkTrustedAction(rel, internal))
|
|
+ return true;
|
|
+
|
|
+ /* user's query is already checked in ExecScan */
|
|
+ if (internal)
|
|
+ required |= SEPG_DB_TUPLE__UPDATE;
|
|
+ /* special case in column create/drop */
|
|
+ if (relid == AttributeRelationId)
|
|
+ required |= fixupColumnAvPerms(newtup, oldtup);
|
|
+ /* check binary library installation */
|
|
+ if (relid == ProcedureRelationId)
|
|
+ checkCLibraryInstallation(newtup, oldtup);
|
|
+ /* check db_procedure:{install}, if necessary */
|
|
+ sepgsqlCheckProcedureInstall(rel, newtup, oldtup);
|
|
+
|
|
+ /* relabeled? */
|
|
+ if (sepgsqlTupleObjectClass(relid, newtup)
|
|
+ != sepgsqlTupleObjectClass(relid, oldtup) ||
|
|
+ HeapTupleGetSecLabel(newtup) != HeapTupleGetSecLabel(oldtup))
|
|
+ required |= SEPG_DB_TUPLE__RELABELFROM;
|
|
+
|
|
+ if (required)
|
|
+ {
|
|
+ audit_name = sepgsqlAuditName(relid, oldtup);
|
|
+ tclass = sepgsqlTupleObjectClass(relid, oldtup);
|
|
+ if (!sepgsqlClientHasPerms(HeapTupleGetSecLabel(oldtup),
|
|
+ tclass,
|
|
+ required,
|
|
+ audit_name, internal))
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (required & SEPG_DB_TUPLE__RELABELFROM)
|
|
+ {
|
|
+ audit_name = sepgsqlAuditName(relid, newtup);
|
|
+ tclass = sepgsqlTupleObjectClass(relid, newtup);
|
|
+ if (!sepgsqlClientHasPerms(HeapTupleGetSecLabel(newtup),
|
|
+ tclass,
|
|
+ SEPG_DB_TUPLE__RELABELTO,
|
|
+ audit_name, internal))
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlHeapTupleDelete(Relation rel, HeapTuple oldtup, bool internal)
|
|
+{
|
|
+ Oid relid = RelationGetRelid(rel);
|
|
+ security_class_t tclass;
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (!sepgsqlIsEnabled() || checkTrustedAction(rel, internal))
|
|
+ return true;
|
|
+
|
|
+ /* user's query is already checked in ExecScan */
|
|
+ if (!internal)
|
|
+ return true;
|
|
+
|
|
+ audit_name = sepgsqlAuditName(relid, oldtup);
|
|
+ tclass = sepgsqlTupleObjectClass(relid, oldtup);
|
|
+ return sepgsqlClientHasPerms(HeapTupleGetSecLabel(oldtup),
|
|
+ tclass,
|
|
+ SEPG_DB_TUPLE__DELETE,
|
|
+ audit_name, internal);
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql-new/src/backend/security/sepgsql/core.c
|
|
--- base/src/backend/security/sepgsql/core.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/sepgsql/core.c 2009-03-15 17:38:39.000000000 +0900
|
|
@@ -0,0 +1,392 @@
|
|
+/*
|
|
+ * src/backend/security/sepgsql/core.c
|
|
+ * The core facility of SE-PostgreSQL
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "catalog/indexing.h"
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_proc.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "libpq/libpq-be.h"
|
|
+#include "miscadmin.h"
|
|
+#include "security/sepgsql.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/syscache.h"
|
|
+#include "utils/tqual.h"
|
|
+
|
|
+static security_context_t clientLabel = NULL;
|
|
+static security_context_t serverLabel = NULL;
|
|
+static security_context_t unlabeledLabel = NULL;
|
|
+
|
|
+security_context_t
|
|
+sepgsqlGetServerLabel(void)
|
|
+{
|
|
+ if (!serverLabel)
|
|
+ {
|
|
+ if (getcon_raw(&serverLabel) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not get server label")));
|
|
+ }
|
|
+ return serverLabel;
|
|
+}
|
|
+
|
|
+security_context_t
|
|
+sepgsqlGetClientLabel(void)
|
|
+{
|
|
+ if (!clientLabel)
|
|
+ {
|
|
+ /*
|
|
+ * When the process is not invoked as a backend of client,
|
|
+ * it works as a server process and as a client process
|
|
+ * in same time.
|
|
+ */
|
|
+ if (!MyProcPort)
|
|
+ return sepgsqlGetServerLabel();
|
|
+
|
|
+ /*
|
|
+ * SELinux provides getpeercon(3) which enables to obtain
|
|
+ * the security context of peer process.
|
|
+ * If MyProcPort->sock is unix domain socket, no special
|
|
+ * configuration is necessary. If it is tcp/ip socket,
|
|
+ * labeled IPsec or fallback context to be configured.
|
|
+ */
|
|
+ if (getpeercon_raw(MyProcPort->sock, &clientLabel) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not obtain client label")));
|
|
+ }
|
|
+
|
|
+ return clientLabel;
|
|
+}
|
|
+
|
|
+security_context_t
|
|
+sepgsqlSwitchClient(security_context_t new_client)
|
|
+{
|
|
+ char *old_client = sepgsqlGetClientLabel();
|
|
+
|
|
+ clientLabel = new_client;
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlAvcSwitchClient();
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ clientLabel = old_client;
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ return new_client;
|
|
+}
|
|
+
|
|
+security_context_t
|
|
+sepgsqlGetUnlabeledLabel(void)
|
|
+{
|
|
+ if (!unlabeledLabel)
|
|
+ {
|
|
+ if (security_get_initial_context_raw("unlabeled",
|
|
+ &unlabeledLabel) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not get unlabeled label")));
|
|
+ }
|
|
+ return unlabeledLabel;
|
|
+}
|
|
+
|
|
+security_context_t
|
|
+sepgsqlGetDatabaseLabel(void)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ sepgsql_sid_t dbsid;
|
|
+ security_context_t dbcon;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ {
|
|
+ static security_context_t databaseLabel = NULL;
|
|
+
|
|
+ if (!databaseLabel)
|
|
+ {
|
|
+ security_class_t tclass
|
|
+ = string_to_security_class("db_database");
|
|
+
|
|
+ if (security_compute_create_raw(sepgsqlGetClientLabel(),
|
|
+ sepgsqlGetClientLabel(),
|
|
+ tclass, &databaseLabel) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: unable to compute database context")));
|
|
+ }
|
|
+ return pstrdup(databaseLabel);
|
|
+ }
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for database: %u",
|
|
+ MyDatabaseId);
|
|
+
|
|
+ dbsid = HeapTupleGetSecLabel(tuple);
|
|
+ dbcon = securityLookupSecurityLabel(dbsid);
|
|
+ if (!dbcon || !sepgsqlCheckValidSecurityLabel(dbcon))
|
|
+ dbcon = pstrdup(sepgsqlGetUnlabeledLabel());
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return dbcon;
|
|
+}
|
|
+
|
|
+sepgsql_sid_t
|
|
+sepgsqlGetDatabaseSid(void)
|
|
+{
|
|
+ security_context_t dbcontext = sepgsqlGetDatabaseLabel();
|
|
+
|
|
+ return securityLookupSecurityId(dbcontext);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlIsEnabled()
|
|
+ *
|
|
+ * returns the state of SE-PostgreSQL whether enabled, or not.
|
|
+ * When functions under src/backend/utils/ are invoked, they have to
|
|
+ * be checked on the head.
|
|
+ * This status is decided with two factors. The one is GUC parameter
|
|
+ * of "sepostgresql=on/off", and the other is is_selinux_enabled().
|
|
+ * Both of them have to be true, when SE-PostgreSQL is activated.
|
|
+ */
|
|
+bool sepostgresql_is_enabled; /* default is false */
|
|
+
|
|
+bool
|
|
+sepgsqlIsEnabled(void)
|
|
+{
|
|
+ static int enabled = -1; /* unchecked */
|
|
+
|
|
+ if (!sepostgresql_is_enabled)
|
|
+ return false;
|
|
+
|
|
+ if (enabled < 0)
|
|
+ enabled = is_selinux_enabled();
|
|
+
|
|
+ return enabled > 0 ? true : false;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlInitialize
|
|
+ */
|
|
+void
|
|
+sepgsqlInitialize(void)
|
|
+{
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ sepgsqlGetClientLabel();
|
|
+
|
|
+ sepgsqlAvcInit();
|
|
+}
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL specific functions
|
|
+ */
|
|
+Datum
|
|
+sepgsql_getcon(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ security_context_t context;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: disabled now")));
|
|
+
|
|
+ context = sepgsqlGetClientLabel();
|
|
+ context = sepgsqlSecurityLabelTransOut(context);
|
|
+ return CStringGetTextDatum(context);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_getservcon(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ security_context_t context;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: disabled now")));
|
|
+
|
|
+ context = sepgsqlGetServerLabel();
|
|
+ context = sepgsqlSecurityLabelTransOut(context);
|
|
+ return CStringGetTextDatum(context);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsql_(get|set)_(user|role|type|range)
|
|
+ * get/set a component of security context.
|
|
+ */
|
|
+static void
|
|
+parse_security_context(security_context_t context,
|
|
+ char **user, char **role, char **type, char **range)
|
|
+{
|
|
+ security_context_t raw_context;
|
|
+ char *tok;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: disabled now")));
|
|
+
|
|
+ if (selinux_trans_to_raw_context(context, &raw_context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not translate mls label: %s", context)));
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ tok = strtok(raw_context, ":");
|
|
+ if (user)
|
|
+ *user = (!tok ? NULL : pstrdup(tok));
|
|
+
|
|
+ tok = strtok(NULL, ":");
|
|
+ if (role)
|
|
+ *role = (!tok ? NULL : pstrdup(tok));
|
|
+
|
|
+ tok = strtok(NULL, ":");
|
|
+ if (type)
|
|
+ *type = (!tok ? NULL : pstrdup(tok));
|
|
+
|
|
+ tok = strtok(NULL, "\0");
|
|
+ if (range)
|
|
+ *range = (!tok ? NULL : pstrdup(tok));
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(raw_context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(raw_context);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_user(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0));
|
|
+ char *user;
|
|
+
|
|
+ parse_security_context(context, &user, NULL, NULL, NULL);
|
|
+ if (!user)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not extract user of \"%s\"", context)));
|
|
+
|
|
+ PG_RETURN_TEXT_P(CStringGetTextDatum(user));
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_role(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0));
|
|
+ char *role;
|
|
+
|
|
+ parse_security_context(context, NULL, &role, NULL, NULL);
|
|
+ if (!role)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not extract role of \"%s\"", context)));
|
|
+
|
|
+ PG_RETURN_TEXT_P(CStringGetTextDatum(role));
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_type(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0));
|
|
+ char *type;
|
|
+
|
|
+ parse_security_context(context, NULL, NULL, &type, NULL);
|
|
+ if (!type)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not extract type of \"%s\"", context)));
|
|
+
|
|
+ PG_RETURN_TEXT_P(CStringGetTextDatum(type));
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_range(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0));
|
|
+ char *range;
|
|
+
|
|
+ parse_security_context(context, NULL, NULL, NULL, &range);
|
|
+ if (!range)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not extract range of \"%s\"", context)));
|
|
+
|
|
+ PG_RETURN_TEXT_P(CStringGetTextDatum(range));
|
|
+}
|
|
+
|
|
+static Datum
|
|
+sepgsql_set_common(char *context, char *user, char *role, char *type, char *range)
|
|
+{
|
|
+ StringInfoData newcon;
|
|
+
|
|
+ parse_security_context(context,
|
|
+ !user ? &user : NULL,
|
|
+ !role ? &role : NULL,
|
|
+ !type ? &type : NULL,
|
|
+ !range ? &range : NULL);
|
|
+ if (!user || !role || !type)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: invalid security context: \"%s\"", context)));
|
|
+
|
|
+ initStringInfo(&newcon);
|
|
+ appendStringInfo(&newcon, "%s:%s:%s", user, role, type);
|
|
+ if (range)
|
|
+ appendStringInfo(&newcon, ":%s", range);
|
|
+
|
|
+ return CStringGetTextDatum(sepgsqlSecurityLabelTransOut(newcon.data));
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_user(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0));
|
|
+ char *user = TextDatumGetCString(PG_GETARG_TEXT_P(1));
|
|
+
|
|
+ return sepgsql_set_common(context, user, NULL, NULL, NULL);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_role(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0));
|
|
+ char *role = TextDatumGetCString(PG_GETARG_TEXT_P(1));
|
|
+
|
|
+ return sepgsql_set_common(context, NULL, role, NULL, NULL);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_type(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0));
|
|
+ char *type = TextDatumGetCString(PG_GETARG_TEXT_P(1));
|
|
+
|
|
+ return sepgsql_set_common(context, NULL, NULL, type, NULL);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_range(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0));
|
|
+ char *range = TextDatumGetCString(PG_GETARG_TEXT_P(1));
|
|
+
|
|
+ return sepgsql_set_common(context, NULL, NULL, NULL, range);
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/dummy.c sepgsql-new/src/backend/security/sepgsql/dummy.c
|
|
--- base/src/backend/security/sepgsql/dummy.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/sepgsql/dummy.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,79 @@
|
|
+/*
|
|
+ * src/backend/utils/sepgsql/dummy.c
|
|
+ * A set of stubs when SE-PostgreSQL is not activated
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "security/sepgsql.h"
|
|
+
|
|
+static Datum
|
|
+unavailable_function(const char *fn_name)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("function \"%s\" is not available", fn_name)));
|
|
+ PG_RETURN_VOID();
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_getcon(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_getservcon(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_user(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_role(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_type(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_range(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_user(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_role(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_type(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_range(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__);
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql-new/src/backend/security/sepgsql/hooks.c
|
|
--- base/src/backend/security/sepgsql/hooks.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/sepgsql/hooks.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,793 @@
|
|
+/*
|
|
+ * src/backend/security/sepgsql/hooks.c
|
|
+ * SE-PostgreSQL security hooks
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/heapam.h"
|
|
+#include "catalog/pg_aggregate.h"
|
|
+#include "catalog/pg_amproc.h"
|
|
+#include "catalog/pg_cast.h"
|
|
+#include "catalog/pg_conversion.h"
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_language.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_operator.h"
|
|
+#include "catalog/pg_proc.h"
|
|
+#include "catalog/pg_trigger.h"
|
|
+#include "catalog/pg_ts_parser.h"
|
|
+#include "catalog/pg_ts_template.h"
|
|
+#include "catalog/pg_ts_template.h"
|
|
+#include "catalog/pg_type.h"
|
|
+#include "miscadmin.h"
|
|
+#include "nodes/makefuncs.h"
|
|
+#include "nodes/nodes.h"
|
|
+#include "security/sepgsql.h"
|
|
+#include "storage/bufmgr.h"
|
|
+#include "utils/syscache.h"
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckDatabaseAccess
|
|
+ * checks db_database:{access} permission when the client logs-in
|
|
+ * the given database.
|
|
+ *
|
|
+ * sepgsqlCheckDatabaseSuperuser
|
|
+ * checks db_database:{superuser} permission when the client tries
|
|
+ * to perform as a superuser on the given databse.
|
|
+ */
|
|
+static bool
|
|
+checkDatabaseCommon(Oid database_oid, access_vector_t perms)
|
|
+{
|
|
+ const char *audit_name;
|
|
+ HeapTuple tuple;
|
|
+ bool rc;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(database_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for database: %u",
|
|
+ database_oid);
|
|
+
|
|
+ audit_name = sepgsqlAuditName(DatabaseRelationId, tuple);
|
|
+ rc = sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple),
|
|
+ SEPG_CLASS_DB_DATABASE,
|
|
+ perms,
|
|
+ audit_name, false);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlCheckDatabaseAccess(Oid database_oid)
|
|
+{
|
|
+ return checkDatabaseCommon(database_oid,
|
|
+ SEPG_DB_DATABASE__ACCESS);
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlCheckDatabaseSuperuser(void)
|
|
+{
|
|
+ return checkDatabaseCommon(MyDatabaseId,
|
|
+ SEPG_DB_DATABASE__SUPERUSER);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlDatabaseInstallModule
|
|
+ * checks db_database:{install_module} permission on
|
|
+ * the current database and a given loadable module.
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckDatabaseInstallModule(const char *filename)
|
|
+{
|
|
+ security_context_t fcontext;
|
|
+ HeapTuple tuple;
|
|
+ const char *audit_name;
|
|
+ char *fullpath;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ /* (client) <-- db_database:module_install --> (database) */
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for database: %u",
|
|
+ MyDatabaseId);
|
|
+
|
|
+ audit_name = sepgsqlAuditName(DatabaseRelationId, tuple);
|
|
+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple),
|
|
+ SEPG_CLASS_DB_DATABASE,
|
|
+ SEPG_DB_DATABASE__INSTALL_MODULE,
|
|
+ audit_name, true);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ /* (client) <-- db_databse:module_install --> (*.so file) */
|
|
+ fullpath = expand_dynamic_library_name(filename);
|
|
+ if (getfilecon_raw(fullpath, &fcontext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not access file \"%s\": %m", fullpath)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePerms(sepgsqlGetClientLabel(),
|
|
+ fcontext,
|
|
+ SEPG_CLASS_DB_DATABASE,
|
|
+ SEPG_DB_DATABASE__INSTALL_MODULE,
|
|
+ fullpath, true);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(fcontext);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(fcontext);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlDatabaseLoadModule
|
|
+ * checks capability of database to load a specific library
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckDatabaseLoadModule(const char *filename)
|
|
+{
|
|
+ security_context_t filecon;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ if (getfilecon_raw(filename, &filecon) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not access file \"%s\": %m", filename)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePerms(sepgsqlGetDatabaseLabel(),
|
|
+ filecon,
|
|
+ SEPG_CLASS_DB_DATABASE,
|
|
+ SEPG_DB_DATABASE__LOAD_MODULE,
|
|
+ filename, true);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(filecon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(filecon);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckTableLock
|
|
+ * checks db_table:{lock} permission when the client tries to
|
|
+ * aquire explicit lock on the given relation.
|
|
+ *
|
|
+ * sepgsqlCheckTableTruncate
|
|
+ * checks db_table:{delete} permission when the client tries to
|
|
+ * truncate the given relation.
|
|
+ */
|
|
+static bool
|
|
+checkTableCommon(Oid table_oid, access_vector_t perms)
|
|
+{
|
|
+ const char *audit_name;
|
|
+ security_class_t tclass;
|
|
+ HeapTuple tuple;
|
|
+ bool rc = true;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(table_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation %u", table_oid);
|
|
+
|
|
+ tclass = sepgsqlTupleObjectClass(RelationRelationId, tuple);
|
|
+ if (tclass == SEPG_CLASS_DB_TABLE)
|
|
+ {
|
|
+ audit_name = sepgsqlAuditName(RelationRelationId, tuple);
|
|
+ rc = sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple),
|
|
+ SEPG_CLASS_DB_TABLE,
|
|
+ perms,
|
|
+ audit_name, false);
|
|
+ }
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlCheckTableLock(Oid table_oid)
|
|
+{
|
|
+ return checkTableCommon(table_oid, SEPG_DB_TABLE__LOCK);
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlCheckTableTruncate(Relation rel)
|
|
+{
|
|
+ HeapScanDesc scan;
|
|
+ HeapTuple tuple;
|
|
+ const char *audit_name;
|
|
+ bool rc = true;
|
|
+
|
|
+ if (!checkTableCommon(RelationGetRelid(rel), SEPG_DB_TABLE__DELETE))
|
|
+ return false;
|
|
+
|
|
+ /*
|
|
+ * check db_tuple:{delete} permission
|
|
+ */
|
|
+ scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
|
|
+
|
|
+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
+ {
|
|
+ audit_name = sepgsqlAuditName(RelationGetRelid(rel), tuple);
|
|
+ rc = sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple),
|
|
+ SEPG_CLASS_DB_TABLE,
|
|
+ SEPG_DB_TUPLE__DELETE,
|
|
+ audit_name, false);
|
|
+ if (!rc)
|
|
+ break;
|
|
+ }
|
|
+ heap_endscan(scan);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckProcedureExecute
|
|
+ * checks db_procedure:{execute} permission when the client tries
|
|
+ * to invoke the given SQL function.
|
|
+ */
|
|
+bool sepgsqlCheckProcedureExecute(Oid proc_oid)
|
|
+{
|
|
+ const char *audit_name;
|
|
+ HeapTuple tuple;
|
|
+ bool rc;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+
|
|
+ /*
|
|
+ * check db_procedure:{execute} permission
|
|
+ */
|
|
+ tuple = SearchSysCache(PROCOID,
|
|
+ ObjectIdGetDatum(proc_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for procedure: %u", proc_oid);
|
|
+
|
|
+ audit_name = sepgsqlAuditName(ProcedureRelationId, tuple);
|
|
+ rc = sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple),
|
|
+ SEPG_CLASS_DB_PROCEDURE,
|
|
+ SEPG_DB_PROCEDURE__EXECUTE,
|
|
+ audit_name, false);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckProcedureEntrypoint
|
|
+ * checks whether the given function call causes domain transition,
|
|
+ * or not. If it needs a domain transition, it injects a wrapper
|
|
+ * function to invoke it under new domain.
|
|
+ */
|
|
+static Datum
|
|
+sepgsqlTrustedProcInvoker(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ security_context_t old_client;
|
|
+ FmgrInfo *finfo = fcinfo->flinfo;
|
|
+ Datum retval;
|
|
+
|
|
+ /*
|
|
+ * Set new domain and invocation
|
|
+ */
|
|
+ old_client = sepgsqlSwitchClient(finfo->sepgsql_label);
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ retval = finfo->sepgsql_addr(fcinfo);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ sepgsqlSwitchClient(old_client);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ sepgsqlSwitchClient(old_client);
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlCheckProcedureEntrypoint(FmgrInfo *finfo, HeapTuple protup)
|
|
+{
|
|
+ MemoryContext oldctx;
|
|
+ security_context_t newcon;
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ /*
|
|
+ * NOTE: It is not available to set up builtin functions as
|
|
+ * trusted procedure now, because it needs to invoke builtin
|
|
+ * functions to search system caches, then it also invokes
|
|
+ * fmgr_info_cxt_security() and makes infinite function call.
|
|
+ * This limitation should be fixed later.
|
|
+ * (It is same as security definer also)
|
|
+ */
|
|
+
|
|
+ oldctx = MemoryContextSwitchTo(finfo->fn_mcxt);
|
|
+
|
|
+ newcon = sepgsqlClientCreateLabel(HeapTupleGetSecLabel(protup),
|
|
+ SEPG_CLASS_PROCESS);
|
|
+ if (strcmp(newcon, sepgsqlGetClientLabel()) == 0)
|
|
+ {
|
|
+ MemoryContextSwitchTo(oldctx);
|
|
+ return;
|
|
+ }
|
|
+ /* db_procedure:{entrypoint}, if trusted procedure */
|
|
+ audit_name = sepgsqlAuditName(ProcedureRelationId, protup);
|
|
+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(protup),
|
|
+ SEPG_CLASS_DB_PROCEDURE,
|
|
+ SEPG_DB_PROCEDURE__ENTRYPOINT,
|
|
+ audit_name, true);
|
|
+
|
|
+ /* process:{transition}, if trusted procedure */
|
|
+ sepgsqlComputePerms(sepgsqlGetClientLabel(),
|
|
+ newcon,
|
|
+ SEPG_CLASS_PROCESS,
|
|
+ SEPG_PROCESS__TRANSITION,
|
|
+ NULL, true);
|
|
+
|
|
+ /* trusted procedure invocation */
|
|
+ finfo->sepgsql_addr = finfo->fn_addr;
|
|
+ finfo->fn_addr = sepgsqlTrustedProcInvoker;
|
|
+ finfo->sepgsql_label = newcon;
|
|
+
|
|
+ MemoryContextSwitchTo(oldctx);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckProcedureInstall
|
|
+ * checks permission: db_procedure:{install}, when client tries to modify
|
|
+ * a system catalog which contains procedure id to invoke it later.
|
|
+ * Because these functions are invoked internally, to search a table with
|
|
+ * a special index algorithm for example, the security policy has to prevent
|
|
+ * malicious user-defined functions to be installed.
|
|
+ */
|
|
+static void
|
|
+checkProcedureInstall(Oid proc_oid)
|
|
+{
|
|
+ sepgsql_sid_t prosid;
|
|
+ HeapTuple protup = NULL;
|
|
+ const char *audit_name = NULL;
|
|
+
|
|
+ if (!OidIsValid(proc_oid))
|
|
+ return;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ {
|
|
+ /*
|
|
+ * Assumption: security label is unchanged
|
|
+ * during bootstraptin mode, because no one
|
|
+ * tries to relabel anything.
|
|
+ */
|
|
+ prosid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(),
|
|
+ SEPG_CLASS_DB_PROCEDURE);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ protup = SearchSysCache(PROCOID,
|
|
+ ObjectIdGetDatum(proc_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(protup))
|
|
+ return;
|
|
+
|
|
+ audit_name = sepgsqlAuditName(ProcedureRelationId, protup);
|
|
+ prosid = HeapTupleGetSecLabel(protup);
|
|
+ }
|
|
+
|
|
+ sepgsqlClientHasPerms(prosid,
|
|
+ SEPG_CLASS_DB_PROCEDURE,
|
|
+ SEPG_DB_PROCEDURE__INSTALL,
|
|
+ audit_name, true);
|
|
+ if (HeapTupleIsValid(protup))
|
|
+ ReleaseSysCache(protup);
|
|
+}
|
|
+
|
|
+#define CHECK_PROC_INSTALL_PERM(catalog,member,newtup,oldtup) \
|
|
+ do { \
|
|
+ if (!HeapTupleIsValid(oldtup)) \
|
|
+ checkProcedureInstall(((Form_##catalog) GETSTRUCT(newtup))->member); \
|
|
+ else if (((Form_##catalog) GETSTRUCT(newtup))->member \
|
|
+ != ((Form_##catalog) GETSTRUCT(oldtup))->member) \
|
|
+ checkProcedureInstall(((Form_##catalog) GETSTRUCT(newtup))->member); \
|
|
+ } while(0)
|
|
+
|
|
+void
|
|
+sepgsqlCheckProcedureInstall(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|
+{
|
|
+ /*
|
|
+ * db_procedure:{install} check prevent a malicious functions
|
|
+ * to be installed, as a part of system catalogs.
|
|
+ * It is necessary to prevent other person implicitly to invoke
|
|
+ * malicious functions.
|
|
+ */
|
|
+ switch (RelationGetRelid(rel))
|
|
+ {
|
|
+ case AggregateRelationId:
|
|
+ /*
|
|
+ * db_procedure:{execute} is checked on invocations of:
|
|
+ * pg_aggregate.aggfnoid
|
|
+ * pg_aggregate.aggtransfn
|
|
+ * pg_aggregate.aggfinalfn
|
|
+ */
|
|
+ break;
|
|
+
|
|
+ case AccessMethodRelationId:
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, aminsert, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, ambeginscan, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, amgettuple, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, amgetmulti, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, amrescan, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, amendscan, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, ammarkpos, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, amrestrpos, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, ambuild, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, ambulkdelete, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, amvacuumcleanup, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, amcostestimate, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_am, amoptions, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case AccessMethodProcedureRelationId:
|
|
+ CHECK_PROC_INSTALL_PERM(pg_amproc, amproc, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case CastRelationId:
|
|
+ CHECK_PROC_INSTALL_PERM(pg_cast, castfunc, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case ConversionRelationId:
|
|
+ CHECK_PROC_INSTALL_PERM(pg_conversion, conproc, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case LanguageRelationId:
|
|
+ CHECK_PROC_INSTALL_PERM(pg_language, lanplcallfoid, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_language, lanvalidator, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case OperatorRelationId:
|
|
+ CHECK_PROC_INSTALL_PERM(pg_operator, oprcode, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_operator, oprrest, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_operator, oprjoin, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case TriggerRelationId:
|
|
+ CHECK_PROC_INSTALL_PERM(pg_trigger, tgfoid, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case TSParserRelationId:
|
|
+ CHECK_PROC_INSTALL_PERM(pg_ts_parser, prsstart, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_ts_parser, prstoken, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_ts_parser, prsend, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_ts_parser, prsheadline, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_ts_parser, prslextype, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case TSTemplateRelationId:
|
|
+ CHECK_PROC_INSTALL_PERM(pg_ts_template, tmplinit, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_ts_template, tmpllexize, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case TypeRelationId:
|
|
+ CHECK_PROC_INSTALL_PERM(pg_type, typinput, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_type, typoutput, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_type, typreceive, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_type, typsend, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_type, typmodin, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_type, typmodout, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_PERM(pg_type, typanalyze, newtup, oldtup);
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckBlobDrop
|
|
+ * checks db_blob:{drop} permission
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckBlobDrop(HeapTuple lotup)
|
|
+{
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ audit_name = sepgsqlAuditName(LargeObjectRelationId, lotup);
|
|
+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(lotup),
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__DROP,
|
|
+ audit_name, true);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckBlobRead
|
|
+ * checks db_blob:{read} permission
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckBlobRead(LargeObjectDesc *lobj)
|
|
+{
|
|
+ char audit_name[NAMEDATALEN];
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ snprintf(audit_name, sizeof(audit_name), "blob:%u", lobj->id);
|
|
+ sepgsqlClientHasPerms(lobj->secid,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__READ,
|
|
+ audit_name, true);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckBlobWrite
|
|
+ * check db_blob:{write} permission
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckBlobWrite(LargeObjectDesc *lobj)
|
|
+{
|
|
+ char audit_name[NAMEDATALEN];
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ snprintf(audit_name, sizeof(audit_name), "blob:%u", lobj->id);
|
|
+ sepgsqlClientHasPerms(lobj->secid,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__WRITE,
|
|
+ audit_name, true);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckBlobGetattr
|
|
+ * check db_blob:{getattr} permission
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckBlobGetattr(HeapTuple tuple)
|
|
+{
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ audit_name = sepgsqlAuditName(LargeObjectRelationId, tuple);
|
|
+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple),
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__GETATTR,
|
|
+ audit_name, true);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckBlobSetattr
|
|
+ * check db_blob:{setattr} permission
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckBlobSetattr(HeapTuple tuple)
|
|
+{
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ audit_name = sepgsqlAuditName(LargeObjectRelationId, tuple);
|
|
+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple),
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__SETATTR,
|
|
+ audit_name, true);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckBlobExport
|
|
+ * check db_blob:{read export} and file:{write} permission
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckBlobExport(LargeObjectDesc *lobj,
|
|
+ int fdesc, const char *filename)
|
|
+{
|
|
+ security_context_t fcontext;
|
|
+ security_class_t fclass;
|
|
+ char audit_name[NAMEDATALEN];
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ snprintf(audit_name, sizeof(audit_name), "blob:%u", lobj->id);
|
|
+ sepgsqlClientHasPerms(lobj->secid,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__READ | SEPG_DB_BLOB__EXPORT,
|
|
+ audit_name, true);
|
|
+
|
|
+ fclass = sepgsqlFileObjectClass(fdesc);
|
|
+ if (fgetfilecon_raw(fdesc, &fcontext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not get security context \"%s\"", filename)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePerms(sepgsqlGetClientLabel(),
|
|
+ fcontext,
|
|
+ fclass,
|
|
+ SEPG_FILE__WRITE,
|
|
+ filename, true);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(fcontext);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(fcontext);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckBlobImport
|
|
+ * check db_blob:{write import} and file:{read} permission
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckBlobImport(LargeObjectDesc *lobj,
|
|
+ int fdesc, const char *filename)
|
|
+{
|
|
+ security_context_t fcontext;
|
|
+ security_class_t fclass;
|
|
+ char audit_name[NAMEDATALEN];
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ snprintf(audit_name, sizeof(audit_name), "blob:%u", lobj->id);
|
|
+ sepgsqlClientHasPerms(lobj->secid,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__WRITE | SEPG_DB_BLOB__IMPORT,
|
|
+ audit_name, true);
|
|
+
|
|
+ fclass = sepgsqlFileObjectClass(fdesc);
|
|
+ if (fgetfilecon_raw(fdesc, &fcontext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not get security context \"%s\"", filename)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePerms(sepgsqlGetClientLabel(),
|
|
+ fcontext,
|
|
+ fclass,
|
|
+ SEPG_FILE__READ,
|
|
+ filename, true);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(fcontext);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(fcontext);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckBlobRelabel
|
|
+ * check db_blob:{setattr relabelfrom relabelto}
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckBlobRelabel(HeapTuple oldtup, HeapTuple newtup)
|
|
+{
|
|
+ access_vector_t required = SEPG_DB_BLOB__SETATTR;
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (HeapTupleGetSecLabel(oldtup) != HeapTupleGetSecLabel(newtup))
|
|
+ required |= SEPG_DB_BLOB__RELABELFROM;
|
|
+
|
|
+ audit_name = sepgsqlAuditName(LargeObjectRelationId, oldtup);
|
|
+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(oldtup),
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ required,
|
|
+ audit_name, true);
|
|
+ if ((required & SEPG_DB_BLOB__RELABELFROM) == 0)
|
|
+ return;
|
|
+
|
|
+ audit_name = sepgsqlAuditName(LargeObjectRelationId, newtup);
|
|
+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(newtup),
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__RELABELTO,
|
|
+ audit_name, true);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckFileRead
|
|
+ * sepgsqlCheckFileWrite
|
|
+ * check file:{read} or file:{write} permission on the given file,
|
|
+ * and raises an error if violated.
|
|
+ */
|
|
+static void
|
|
+checkFileCommon(int fdesc, const char *filename, access_vector_t perms)
|
|
+{
|
|
+ security_context_t context;
|
|
+ security_class_t tclass;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ tclass = sepgsqlFileObjectClass(fdesc);
|
|
+
|
|
+ if (fgetfilecon_raw(fdesc, &context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not get context of %s", filename)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePerms(sepgsqlGetClientLabel(),
|
|
+ context,
|
|
+ tclass,
|
|
+ perms,
|
|
+ filename, true);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(context);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlCheckFileRead(int fdesc, const char *filename)
|
|
+{
|
|
+ checkFileCommon(fdesc, filename, SEPG_FILE__READ);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlCheckFileWrite(int fdesc, const char *filename)
|
|
+{
|
|
+ checkFileCommon(fdesc, filename, SEPG_FILE__WRITE);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlAllowFunctionInlined
|
|
+ * It provides the optimizer a hint whether the given SQL function
|
|
+ * can be inlined, or not. If it can be configured as a trusted
|
|
+ * procedure, we should not allow it inlined.
|
|
+ */
|
|
+bool
|
|
+sepgsqlAllowFunctionInlined(HeapTuple proc_tuple)
|
|
+{
|
|
+ security_context_t context;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+
|
|
+ context = sepgsqlClientCreateLabel(HeapTupleGetSecLabel(proc_tuple),
|
|
+ SEPG_CLASS_PROCESS);
|
|
+ /*
|
|
+ * If the security context of client is unchange
|
|
+ * before or after invocation of the functions,
|
|
+ * it is not a trusted procedure, so it can be
|
|
+ * inlined due to performance purpose.
|
|
+ */
|
|
+ if (strcmp(sepgsqlGetClientLabel(), context) == 0)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/label.c sepgsql-new/src/backend/security/sepgsql/label.c
|
|
--- base/src/backend/security/sepgsql/label.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/sepgsql/label.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,339 @@
|
|
+/*
|
|
+ * src/backend/security/sepgsql/label.c
|
|
+ * SE-PostgreSQL security label management
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/xact.h"
|
|
+#include "catalog/catalog.h"
|
|
+#include "catalog/indexing.h"
|
|
+#include "catalog/pg_attribute.h"
|
|
+#include "catalog/pg_class.h"
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_proc.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "catalog/pg_type.h"
|
|
+#include "miscadmin.h"
|
|
+#include "nodes/makefuncs.h"
|
|
+#include "security/sepgsql.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/memutils.h"
|
|
+#include "utils/syscache.h"
|
|
+
|
|
+/*
|
|
+ * sepgsqlTupleDescHasSecLabel
|
|
+ * controls TupleDesc->tdhasseclabel
|
|
+ */
|
|
+bool sepostgresql_row_level;
|
|
+
|
|
+bool
|
|
+sepgsqlTupleDescHasSecLabel(Relation rel)
|
|
+{
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return false;
|
|
+
|
|
+ if (rel != NULL &&
|
|
+ RelationGetForm(rel)->relkind != RELKIND_RELATION)
|
|
+ return false;
|
|
+
|
|
+ if (rel != NULL &&
|
|
+ (RelationGetRelid(rel) == DatabaseRelationId || /* db_database */
|
|
+ RelationGetRelid(rel) == RelationRelationId || /* db_table */
|
|
+ RelationGetRelid(rel) == AttributeRelationId || /* db_column */
|
|
+ RelationGetRelid(rel) == ProcedureRelationId || /* db_procedure */
|
|
+ RelationGetRelid(rel) == LargeObjectRelationId)) /* db_blob */
|
|
+ return true;
|
|
+
|
|
+ return sepostgresql_row_level; /* db_tuple class depends on a GUC parameter */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlSetDefaultSecLabel
|
|
+ *
|
|
+ * It assigns a default security label on a tuple newly created.
|
|
+ * The default security label depends on the security policy, and
|
|
+ * its object class.
|
|
+ * The db_class and db_tuple class inherits the parent table's one,
|
|
+ * but we cannot refer system cache in very early phase, so it assumes
|
|
+ * nobody relabels the default one during initdb.
|
|
+ */
|
|
+void
|
|
+sepgsqlSetDefaultSecLabel(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ Form_pg_attribute attform;
|
|
+ security_context_t context;
|
|
+ security_class_t tclass;
|
|
+ sepgsql_sid_t newsid, table_sid;
|
|
+ HeapTuple reltup;
|
|
+
|
|
+ Assert(HeapTupleHasSecLabel(tuple));
|
|
+ tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple);
|
|
+
|
|
+ switch (tclass)
|
|
+ {
|
|
+ case SEPG_CLASS_DB_DATABASE:
|
|
+ context = sepgsqlComputeCreate(sepgsqlGetClientLabel(),
|
|
+ sepgsqlGetClientLabel(),
|
|
+ SEPG_CLASS_DB_DATABASE);
|
|
+ newsid = securityTransSecLabelIn(context);
|
|
+ break;
|
|
+
|
|
+ case SEPG_CLASS_DB_TABLE:
|
|
+ newsid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(),
|
|
+ SEPG_CLASS_DB_TABLE);
|
|
+ break;
|
|
+
|
|
+ case SEPG_CLASS_DB_PROCEDURE:
|
|
+ newsid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(),
|
|
+ SEPG_CLASS_DB_PROCEDURE);
|
|
+ break;
|
|
+ case SEPG_CLASS_DB_COLUMN:
|
|
+ attform = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ if (IsBootstrapProcessingMode() &&
|
|
+ (attform->attrelid == TypeRelationId ||
|
|
+ attform->attrelid == ProcedureRelationId ||
|
|
+ attform->attrelid == AttributeRelationId ||
|
|
+ attform->attrelid == RelationRelationId))
|
|
+ {
|
|
+ table_sid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(),
|
|
+ SEPG_CLASS_DB_TABLE);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ reltup = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(attform->attrelid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(reltup))
|
|
+ elog(ERROR, "SELinux: cache lookup failed fro relation: %u",
|
|
+ attform->attrelid);
|
|
+
|
|
+ table_sid = HeapTupleGetSecLabel(reltup);
|
|
+
|
|
+ ReleaseSysCache(reltup);
|
|
+ }
|
|
+ newsid = sepgsqlClientCreate(table_sid, SEPG_CLASS_DB_COLUMN);
|
|
+ break;
|
|
+
|
|
+ case SEPG_CLASS_DB_BLOB:
|
|
+ /*
|
|
+ * NOTE:
|
|
+ * A object within db_blob class has a characteristic.
|
|
+ * It does not have one-to-one mapping on a object and
|
|
+ * a tuple, in other word, a large object consists of
|
|
+ * multiple tuples. In most cases, user accesses them
|
|
+ * via several certain interfaces, like loread().
|
|
+ * So, we assume user don't touch pg_largeobject system
|
|
+ * catalog by hand, and it does not give us any degradation
|
|
+ * at interface incompatibility.
|
|
+ *
|
|
+ * Thus, all the tuples modified are come from internal
|
|
+ * interfaces, like simple_heap_insert(). The backend
|
|
+ * implementation has to set correct security context
|
|
+ * prior to insert a tuple. A security context of
|
|
+ * largeobject is cached on LargeObjectDesc->secid
|
|
+ * The only exception is inv_create(). It invoked
|
|
+ * simple_heap_insert() with no security context to
|
|
+ * assign a default one here.
|
|
+ */
|
|
+ newsid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(),
|
|
+ SEPG_CLASS_DB_BLOB);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ if (IsBootstrapProcessingMode() &&
|
|
+ (RelationGetRelid(rel) == TypeRelationId ||
|
|
+ RelationGetRelid(rel) == ProcedureRelationId ||
|
|
+ RelationGetRelid(rel) == AttributeRelationId ||
|
|
+ RelationGetRelid(rel) == RelationRelationId))
|
|
+ {
|
|
+ table_sid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(),
|
|
+ SEPG_CLASS_DB_TABLE);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ reltup = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(RelationGetRelid(rel)),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(reltup))
|
|
+ elog(ERROR, "SELinux: cache lookup failed fro relation: %u",
|
|
+ RelationGetRelid(rel));
|
|
+
|
|
+ table_sid = HeapTupleGetSecLabel(reltup);
|
|
+
|
|
+ ReleaseSysCache(reltup);
|
|
+ }
|
|
+ newsid = sepgsqlClientCreate(table_sid, SEPG_CLASS_DB_TUPLE);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ HeapTupleSetSecLabel(tuple, newsid);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlMetaSecurityLabel
|
|
+ * returns a security context of tuples within pg_security
|
|
+ */
|
|
+char *
|
|
+sepgsqlMetaSecurityLabel(void)
|
|
+{
|
|
+ security_context_t tcontext;
|
|
+ sepgsql_sid_t tsid;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(SecurityRelationId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation %u",
|
|
+ SecurityRelationId);
|
|
+
|
|
+ tsid = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ tcontext = securityLookupSecurityLabel(tsid);
|
|
+ if (!tcontext || !sepgsqlCheckValidSecurityLabel(tcontext))
|
|
+ tcontext = sepgsqlGetUnlabeledLabel();
|
|
+
|
|
+ return sepgsqlComputeCreate(sepgsqlGetServerLabel(),
|
|
+ tcontext,
|
|
+ SEPG_CLASS_DB_TUPLE);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlInputGivenSecLabel
|
|
+ * translate a given security label in text form into a security
|
|
+ * identifier. It can raise an error, if its format is violated,
|
|
+ * but permission checks are done later.
|
|
+ */
|
|
+Oid
|
|
+sepgsqlInputGivenSecLabel(DefElem *defel)
|
|
+{
|
|
+ if (!defel)
|
|
+ return InvalidOid;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: disabled now")));
|
|
+
|
|
+ return securityTransSecLabelIn(strVal(defel->arg));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlInputGivenSecLabelRelation
|
|
+ * organize a set of given security labels on CREATE TABLE statement.
|
|
+ * User can specify a security label for individual table/columns.
|
|
+ * It returns a list of DefElem. !defel->defname means a specified one
|
|
+ * for the table, rest of them means one for columns.
|
|
+ */
|
|
+List *
|
|
+sepgsqlInputGivenSecLabelRelation(CreateStmt *stmt)
|
|
+{
|
|
+ List *results = NIL;
|
|
+ ListCell *l;
|
|
+ DefElem *defel, *newel;
|
|
+
|
|
+ if (stmt->secLabel)
|
|
+ {
|
|
+ defel = (DefElem *) stmt->secLabel;
|
|
+
|
|
+ Assert(IsA(defel, DefElem));
|
|
+
|
|
+ newel = makeDefElem(NULL, copyObject(defel->arg));
|
|
+ results = lappend(results, newel);
|
|
+ }
|
|
+
|
|
+ foreach (l, stmt->tableElts)
|
|
+ {
|
|
+ ColumnDef *cdef = lfirst(l);
|
|
+
|
|
+ if (cdef->secLabel)
|
|
+ {
|
|
+ defel = (DefElem *) cdef->secLabel;
|
|
+
|
|
+ Assert(IsA(defel, DefElem));
|
|
+
|
|
+ newel = makeDefElem(pstrdup(cdef->colname),
|
|
+ copyObject(defel->arg));
|
|
+ results = lappend(results, newel);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return results;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlSecurityLabelTransIn()
|
|
+ * translate external security label into internal one
|
|
+ */
|
|
+security_context_t
|
|
+sepgsqlSecurityLabelTransIn(security_context_t context)
|
|
+{
|
|
+ security_context_t raw_context, result;
|
|
+
|
|
+ if (selinux_trans_to_raw_context(context, &raw_context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not translate external label: %s", context)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(raw_context);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(raw_context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ freecon(raw_context);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlSecurityLabelTransOut()
|
|
+ * translate internal security label into external one
|
|
+ */
|
|
+security_context_t
|
|
+sepgsqlSecurityLabelTransOut(security_context_t context)
|
|
+{
|
|
+ security_context_t trans_context, result;
|
|
+
|
|
+ if (selinux_raw_to_trans_context(context, &trans_context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not translate internal label: %s", context)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(trans_context);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(trans_context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ freecon(trans_context);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckValidSecurityLabel()
|
|
+ * checks whether the given security context is a valid one, or not
|
|
+ */
|
|
+bool
|
|
+sepgsqlCheckValidSecurityLabel(security_context_t context)
|
|
+{
|
|
+ if (security_check_context_raw(context) < 0)
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/perms.c sepgsql-new/src/backend/security/sepgsql/perms.c
|
|
--- base/src/backend/security/sepgsql/perms.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/sepgsql/perms.c 2009-03-15 17:09:41.000000000 +0900
|
|
@@ -0,0 +1,410 @@
|
|
+/*
|
|
+ * src/backend/utils/sepgsql/perms.c
|
|
+ * SE-PostgreSQL permission checks
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "catalog/indexing.h"
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_proc.h"
|
|
+#include "catalog/pg_language.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_type.h"
|
|
+#include "miscadmin.h"
|
|
+#include "security/sepgsql.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/lsyscache.h"
|
|
+#include "utils/syscache.h"
|
|
+#include <sys/stat.h>
|
|
+
|
|
+/*
|
|
+ * Dynamic object class/permissions mapping
|
|
+ *
|
|
+ * SELinux exports the list of object classes and permissions at
|
|
+ * /selinux/class. The libselinux provides an interface to translate
|
|
+ * between their names and codes.
|
|
+ */
|
|
+static struct
|
|
+{
|
|
+ const char *class_name;
|
|
+ security_class_t class_code;
|
|
+ struct
|
|
+ {
|
|
+ const char *perm_name;
|
|
+ access_vector_t perm_code;
|
|
+ } av[sizeof(access_vector_t) * 8];
|
|
+} selinux_catalog[] = {
|
|
+ {
|
|
+ "process", SEPG_CLASS_PROCESS,
|
|
+ {
|
|
+ {"translation", SEPG_PROCESS__TRANSITION },
|
|
+ {NULL, 0}
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "file", SEPG_CLASS_FILE,
|
|
+ {
|
|
+ {"read", SEPG_FILE__READ },
|
|
+ {"write", SEPG_FILE__WRITE },
|
|
+ {NULL, 0}
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "dir", SEPG_CLASS_DIR,
|
|
+ {
|
|
+ {"read", SEPG_DIR__READ },
|
|
+ {"write", SEPG_DIR__WRITE },
|
|
+ {NULL,0}
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "lnk_file", SEPG_CLASS_LNK_FILE,
|
|
+ {
|
|
+ {"read", SEPG_LNK_FILE__READ },
|
|
+ {"write", SEPG_LNK_FILE__WRITE },
|
|
+ {NULL,0}
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "chr_file", SEPG_CLASS_CHR_FILE,
|
|
+ {
|
|
+ {"read", SEPG_CHR_FILE__READ },
|
|
+ {"write", SEPG_CHR_FILE__WRITE },
|
|
+ {NULL,0}
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "blk_file", SEPG_CLASS_BLK_FILE,
|
|
+ {
|
|
+ {"read", SEPG_BLK_FILE__READ },
|
|
+ {"write", SEPG_BLK_FILE__WRITE },
|
|
+ {NULL,0}
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "sock_file", SEPG_CLASS_SOCK_FILE,
|
|
+ {
|
|
+ {"read", SEPG_SOCK_FILE__READ },
|
|
+ {"write", SEPG_SOCK_FILE__WRITE },
|
|
+ {NULL,0}
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "fifo_file", SEPG_CLASS_FIFO_FILE,
|
|
+ {
|
|
+ {"read", SEPG_FIFO_FILE__READ },
|
|
+ {"write", SEPG_FIFO_FILE__WRITE },
|
|
+ {NULL, 0UL }
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_database", SEPG_CLASS_DB_DATABASE,
|
|
+ {
|
|
+ { "create", SEPG_DB_DATABASE__CREATE },
|
|
+ { "drop", SEPG_DB_DATABASE__DROP },
|
|
+ { "getattr", SEPG_DB_DATABASE__GETATTR },
|
|
+ { "setattr", SEPG_DB_DATABASE__SETATTR },
|
|
+ { "relabelfrom", SEPG_DB_DATABASE__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_DATABASE__RELABELTO },
|
|
+ { "access", SEPG_DB_DATABASE__ACCESS },
|
|
+ { "install_module", SEPG_DB_DATABASE__INSTALL_MODULE },
|
|
+ { "load_module", SEPG_DB_DATABASE__LOAD_MODULE },
|
|
+ { "superuser", SEPG_DB_DATABASE__SUPERUSER },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_table", SEPG_CLASS_DB_TABLE,
|
|
+ {
|
|
+ { "create", SEPG_DB_TABLE__CREATE },
|
|
+ { "drop", SEPG_DB_TABLE__DROP },
|
|
+ { "getattr", SEPG_DB_TABLE__GETATTR },
|
|
+ { "setattr", SEPG_DB_TABLE__SETATTR },
|
|
+ { "relabelfrom", SEPG_DB_TABLE__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_TABLE__RELABELTO },
|
|
+ { "select", SEPG_DB_TABLE__SELECT },
|
|
+ { "update", SEPG_DB_TABLE__UPDATE },
|
|
+ { "insert", SEPG_DB_TABLE__INSERT },
|
|
+ { "delete", SEPG_DB_TABLE__DELETE },
|
|
+ { "lock", SEPG_DB_TABLE__LOCK },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_procedure", SEPG_CLASS_DB_PROCEDURE,
|
|
+ {
|
|
+ { "create", SEPG_DB_PROCEDURE__CREATE },
|
|
+ { "drop", SEPG_DB_PROCEDURE__DROP },
|
|
+ { "getattr", SEPG_DB_PROCEDURE__GETATTR },
|
|
+ { "setattr", SEPG_DB_PROCEDURE__SETATTR },
|
|
+ { "relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_PROCEDURE__RELABELTO },
|
|
+ { "execute", SEPG_DB_PROCEDURE__EXECUTE },
|
|
+ { "entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT },
|
|
+ { "install", SEPG_DB_PROCEDURE__INSTALL },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_column", SEPG_CLASS_DB_COLUMN,
|
|
+ {
|
|
+ { "create", SEPG_DB_COLUMN__CREATE },
|
|
+ { "drop", SEPG_DB_COLUMN__DROP },
|
|
+ { "getattr", SEPG_DB_COLUMN__GETATTR },
|
|
+ { "setattr", SEPG_DB_COLUMN__SETATTR },
|
|
+ { "relabelfrom", SEPG_DB_COLUMN__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_COLUMN__RELABELTO },
|
|
+ { "select", SEPG_DB_COLUMN__SELECT },
|
|
+ { "update", SEPG_DB_COLUMN__UPDATE },
|
|
+ { "insert", SEPG_DB_COLUMN__INSERT },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_tuple", SEPG_CLASS_DB_TUPLE,
|
|
+ {
|
|
+ { "relabelfrom", SEPG_DB_TUPLE__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_TUPLE__RELABELTO },
|
|
+ { "select", SEPG_DB_TUPLE__SELECT },
|
|
+ { "update", SEPG_DB_TUPLE__UPDATE },
|
|
+ { "insert", SEPG_DB_TUPLE__INSERT },
|
|
+ { "delete", SEPG_DB_TUPLE__DELETE },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_blob", SEPG_CLASS_DB_BLOB,
|
|
+ {
|
|
+ { "create", SEPG_DB_BLOB__CREATE },
|
|
+ { "drop", SEPG_DB_BLOB__DROP },
|
|
+ { "getattr", SEPG_DB_BLOB__GETATTR },
|
|
+ { "setattr", SEPG_DB_BLOB__SETATTR },
|
|
+ { "relabelfrom", SEPG_DB_BLOB__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_BLOB__RELABELTO },
|
|
+ { "read", SEPG_DB_BLOB__READ },
|
|
+ { "write", SEPG_DB_BLOB__WRITE },
|
|
+ { "import", SEPG_DB_BLOB__IMPORT },
|
|
+ { "export", SEPG_DB_BLOB__EXPORT },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ }
|
|
+};
|
|
+
|
|
+/*
|
|
+ * sepgsqlTransToExternalClass
|
|
+ * It translate the given class code (defined as SEPGCLASS_(class)) into
|
|
+ * external code which is necessary to communicate in-kernel SELinux
|
|
+ */
|
|
+extern security_class_t
|
|
+sepgsqlTransToExternalClass(security_class_t tclass)
|
|
+{
|
|
+ security_class_t tclass_ex;
|
|
+
|
|
+ Assert(tclass < SEPG_CLASS_MAX);
|
|
+
|
|
+ tclass_ex = string_to_security_class(selinux_catalog[tclass].class_name);
|
|
+ if (!tclass_ex)
|
|
+ ereport(FATAL,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: \"%s\" class is not defined in the policy",
|
|
+ selinux_catalog[tclass].class_name)));
|
|
+ return tclass_ex;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlTransToInternalPerms
|
|
+ * It translate the given permission masks into internal representation
|
|
+ * defined as SEPG_(class)_(permission).
|
|
+ */
|
|
+extern void
|
|
+sepgsqlTransToInternalPerms(security_class_t tclass, struct av_decision *avd)
|
|
+{
|
|
+ security_class_t tclass_ex;
|
|
+ struct av_decision i_avd;
|
|
+ int i;
|
|
+
|
|
+ Assert(tclass < SEPG_CLASS_MAX);
|
|
+
|
|
+ memset(&i_avd, 0, sizeof(struct av_decision));
|
|
+
|
|
+ tclass_ex = sepgsqlTransToExternalClass(tclass);
|
|
+ for (i=0; selinux_catalog[tclass].av[i].perm_name; i++)
|
|
+ {
|
|
+ const char *perm_name = selinux_catalog[tclass].av[i].perm_name;
|
|
+ access_vector_t perm_code = selinux_catalog[tclass].av[i].perm_code;
|
|
+ access_vector_t perm_code_ex;
|
|
+
|
|
+ perm_code_ex = string_to_av_perm(tclass_ex, perm_name);
|
|
+ if (!perm_code_ex)
|
|
+ {
|
|
+ /* permission is undefined */
|
|
+ i_avd.allowed |= perm_code;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (avd->allowed & perm_code_ex)
|
|
+ i_avd.allowed |= perm_code;
|
|
+ if (avd->decided & perm_code_ex)
|
|
+ i_avd.decided |= perm_code;
|
|
+ if (avd->auditallow & perm_code_ex)
|
|
+ i_avd.auditallow |= perm_code;
|
|
+ if (avd->auditdeny & perm_code_ex)
|
|
+ i_avd.auditdeny |= perm_code;
|
|
+ }
|
|
+
|
|
+ avd->allowed = i_avd.allowed;
|
|
+ avd->decided = i_avd.decided;
|
|
+ avd->auditallow = i_avd.auditallow;
|
|
+ avd->auditdeny = i_avd.auditdeny;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlGetClassString
|
|
+ * sepgsqlGetPermissionString
|
|
+ * It returns text representation of object classes/permissions
|
|
+ */
|
|
+const char *
|
|
+sepgsqlGetClassString(security_class_t tclass)
|
|
+{
|
|
+ Assert(tclass < SEPG_CLASS_MAX);
|
|
+
|
|
+ return selinux_catalog[tclass].class_name;
|
|
+}
|
|
+
|
|
+const char *
|
|
+sepgsqlGetPermissionString(security_class_t tclass, access_vector_t av)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ Assert(tclass < SEPG_CLASS_MAX);
|
|
+
|
|
+ for (i=0; selinux_catalog[tclass].av[i].perm_name; i++)
|
|
+ {
|
|
+ if (selinux_catalog[tclass].av[i].perm_code == av)
|
|
+ return selinux_catalog[tclass].av[i].perm_name;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlAuditName
|
|
+ * returns an identifier string to generate audit record for
|
|
+ * the given tuple. Please note that its results can indicate
|
|
+ * an address within the given tuple, so we should not refer
|
|
+ * the returned pointer after HeapTuple is released.
|
|
+ */
|
|
+const char *
|
|
+sepgsqlAuditName(Oid relid, HeapTuple tuple)
|
|
+{
|
|
+ static char buffer[NAMEDATALEN * 2 + 10];
|
|
+
|
|
+ switch (relid)
|
|
+ {
|
|
+ case DatabaseRelationId:
|
|
+ return NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname);
|
|
+
|
|
+ case RelationRelationId:
|
|
+ return NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname);
|
|
+
|
|
+ case AttributeRelationId:
|
|
+ if (!IsBootstrapProcessingMode())
|
|
+ {
|
|
+ Form_pg_attribute attForm
|
|
+ = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ char *relname
|
|
+ = get_rel_name(attForm->attrelid);
|
|
+
|
|
+ if (relname)
|
|
+ {
|
|
+ snprintf(buffer, sizeof(buffer), "%s.%s",
|
|
+ relname, NameStr(attForm->attname));
|
|
+ pfree(relname);
|
|
+ return buffer;
|
|
+ }
|
|
+ }
|
|
+ return NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname);
|
|
+
|
|
+ case ProcedureRelationId:
|
|
+ return NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname);
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlFileObjectClass
|
|
+ *
|
|
+ * It returns proper object class of filesystem object already opened.
|
|
+ * It is necessary to check privileges voluntarily.
|
|
+ */
|
|
+security_class_t
|
|
+sepgsqlFileObjectClass(int fdesc)
|
|
+{
|
|
+ struct stat stbuf;
|
|
+
|
|
+ if (fstat(fdesc, &stbuf) != 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not stat file descriptor: %d", fdesc)));
|
|
+
|
|
+ if (S_ISDIR(stbuf.st_mode))
|
|
+ return SEPG_CLASS_DIR;
|
|
+ else if (S_ISCHR(stbuf.st_mode))
|
|
+ return SEPG_CLASS_CHR_FILE;
|
|
+ else if (S_ISBLK(stbuf.st_mode))
|
|
+ return SEPG_CLASS_BLK_FILE;
|
|
+ else if (S_ISFIFO(stbuf.st_mode))
|
|
+ return SEPG_CLASS_FIFO_FILE;
|
|
+ else if (S_ISLNK(stbuf.st_mode))
|
|
+ return SEPG_CLASS_LNK_FILE;
|
|
+ else if (S_ISSOCK(stbuf.st_mode))
|
|
+ return SEPG_CLASS_SOCK_FILE;
|
|
+
|
|
+ return SEPG_CLASS_FILE;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlTupleObjectClass
|
|
+ *
|
|
+ * It returns correct object class of given tuple
|
|
+ */
|
|
+security_class_t
|
|
+sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple)
|
|
+{
|
|
+ Form_pg_class clsForm;
|
|
+ Form_pg_attribute attForm;
|
|
+
|
|
+ switch (relid)
|
|
+ {
|
|
+ case DatabaseRelationId:
|
|
+ return SEPG_CLASS_DB_DATABASE;
|
|
+
|
|
+ case RelationRelationId:
|
|
+ clsForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+ if (clsForm->relkind == RELKIND_RELATION)
|
|
+ return SEPG_CLASS_DB_TABLE;
|
|
+ break;
|
|
+
|
|
+ case AttributeRelationId:
|
|
+ attForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ if (IsBootstrapProcessingMode() &&
|
|
+ (attForm->attrelid == TypeRelationId ||
|
|
+ attForm->attrelid == ProcedureRelationId ||
|
|
+ attForm->attrelid == AttributeRelationId ||
|
|
+ attForm->attrelid == RelationRelationId))
|
|
+ return SEPG_CLASS_DB_COLUMN;
|
|
+
|
|
+ if (get_rel_relkind(attForm->attrelid) == RELKIND_RELATION)
|
|
+ return SEPG_CLASS_DB_COLUMN;
|
|
+ break;
|
|
+
|
|
+ case ProcedureRelationId:
|
|
+ return SEPG_CLASS_DB_PROCEDURE;
|
|
+
|
|
+ case LargeObjectRelationId:
|
|
+ return SEPG_CLASS_DB_BLOB;
|
|
+ }
|
|
+ return SEPG_CLASS_DB_TUPLE;
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/policy/Makefile sepgsql-new/src/backend/security/sepgsql/policy/Makefile
|
|
--- base/src/backend/security/sepgsql/policy/Makefile 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/sepgsql/policy/Makefile 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,28 @@
|
|
+#
|
|
+# Makefile for SE-PostgreSQL security policy module
|
|
+#
|
|
+top_builddir = ../../../../..
|
|
+include $(top_builddir)/src/Makefile.global
|
|
+
|
|
+POLICY_BASEDIR := $(DESTDIR)/usr/share/selinux
|
|
+POLICY_MAKEFILE := $(POLICY_BASEDIR)/devel/Makefile
|
|
+POLICY_TYPES := targeted mls
|
|
+POLICY_TARGET := $(strip $(shell $(AWK) -F= '/^SELINUXTYPE/{ print $$2 }' /etc/selinux/config))
|
|
+PREFIX_RULE := "s/%%__prefix__%%/$(shell echo $(prefix)|sed 's/\//\\\//g')/g"
|
|
+BINDIR_RULE := "s/%%__bindir__%%/$(shell echo $(bindir)|sed 's/\//\\\//g')/g"
|
|
+LIBDIR_RULE := "s/%%__libdir__%%/$(shell echo $(pkglibdir)|sed 's/\//\\\//g')/g"
|
|
+
|
|
+all: $(addprefix sepostgresql-devel.pp., $(POLICY_TYPES))
|
|
+ ln -sf sepostgresql-devel.pp.$(POLICY_TARGET) sepostgresql-devel.pp
|
|
+
|
|
+sepostgresql-devel.pp.%: sepostgresql-devel.te sepostgresql-devel.fc
|
|
+ $(MAKE) NAME=$(POLICY_TARGET) -f $(POLICY_MAKEFILE) clean
|
|
+ $(MAKE) NAME=$(POLICY_TARGET) -f $(POLICY_MAKEFILE)
|
|
+ mv $(basename $@) $@
|
|
+
|
|
+sepostgresql-devel.fc: sepostgresql-devel.fc.template
|
|
+ cat $< | sed -e $(PREFIX_RULE) -e $(BINDIR_RULE) -e $(LIBDIR_RULE) > $@
|
|
+
|
|
+clean:
|
|
+ $(MAKE) -f $(POLICY_MAKEFILE) clean
|
|
+ rm -f *.pp *.pp.* *.if *.fc
|
|
diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template sepgsql-new/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template
|
|
--- base/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,12 @@
|
|
+#
|
|
+# SE-PostgreSQL install path
|
|
+#
|
|
+%%__prefix__%%(/.*)? -- gen_context(system_u:object_r:usr_t,s0)
|
|
+
|
|
+%%__bindir__%%/(se)?postgres -- gen_context(system_u:object_r:postgresql_exec_t,s0)
|
|
+%%__bindir__%%/(se)?pg_ctl -- gen_context(system_u:object_r:initrc_exec_t,s0)
|
|
+%%__bindir__%%/initdb(\.sepgsql)? -- gen_context(system_u:object_r:postgresql_exec_t,s0)
|
|
+%%__bindir__%%(/.*)? -- gen_context(system_u:object_r:bin_t,s0)
|
|
+
|
|
+%%__libdir__%%(/.*)? -- gen_context(system_u:object_r:lib_t,s0)
|
|
+
|
|
diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgsql-new/src/backend/security/sepgsql/policy/sepostgresql-devel.te
|
|
--- base/src/backend/security/sepgsql/policy/sepostgresql-devel.te 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/security/sepgsql/policy/sepostgresql-devel.te 2009-03-28 11:17:32.000000000 +0900
|
|
@@ -0,0 +1,128 @@
|
|
+policy_module(sepostgresql-devel, 3.27)
|
|
+
|
|
+gen_require(`
|
|
+ class db_database all_db_database_perms;
|
|
+ class db_table all_db_table_perms;
|
|
+ class db_procedure all_db_procedure_perms;
|
|
+ class db_column all_db_column_perms;
|
|
+ class db_tuple all_db_tuple_perms;
|
|
+ class db_blob all_db_blob_perms;
|
|
+
|
|
+ attribute sepgsql_client_type;
|
|
+ attribute sepgsql_unconfined_type;
|
|
+
|
|
+ attribute sepgsql_database_type;
|
|
+ attribute sepgsql_table_type;
|
|
+ attribute sepgsql_sysobj_table_type;
|
|
+ attribute sepgsql_procedure_type;
|
|
+ attribute sepgsql_blob_type;
|
|
+ attribute sepgsql_module_type;
|
|
+
|
|
+ # for regression test
|
|
+ type bin_t;
|
|
+ type user_home_t;
|
|
+ type sepgsql_trusted_proc_t;
|
|
+
|
|
+ attribute tmpfile;
|
|
+ attribute ptynode;
|
|
+')
|
|
+
|
|
+#################################
|
|
+#
|
|
+# Domain for Testcases
|
|
+#
|
|
+
|
|
+role sepgsql_test_r;
|
|
+
|
|
+userdom_unpriv_user_template(sepgsql_test)
|
|
+
|
|
+ifdef(`postgresql_role', `
|
|
+ postgresql_role(sepgsql_test_r, sepgsql_test_t)
|
|
+',`
|
|
+ postgresql_userdom_template(sepgsql_test, sepgsql_test_t, sepgsql_test_r)
|
|
+')
|
|
+
|
|
+# workaround for sepgsql tests
|
|
+allow sepgsql_test_t user_sepgsql_blob_t : db_blob { import export };
|
|
+dontaudit sepgsql_test_t sepgsql_blob_type : db_blob *;
|
|
+
|
|
+allow sepgsql_test_t tmpfile : dir search_dir_perms;
|
|
+allow sepgsql_test_t tmpfile : file rw_file_perms;
|
|
+allow sepgsql_test_t ptynode : chr_file rw_file_perms;
|
|
+
|
|
+optional_policy(`
|
|
+ gen_require(`
|
|
+ type unconfined_t;
|
|
+ role unconfined_r;
|
|
+ ')
|
|
+
|
|
+ tunable_policy(`sepgsql_regression_test_mode',`
|
|
+ allow unconfined_t sepgsql_test_t : process transition;
|
|
+ ')
|
|
+ allow sepgsql_test_t unconfined_t : fifo_file read_file_perms;
|
|
+ role unconfined_r types sepgsql_test_t;
|
|
+ role unconfined_r types sepgsql_trusted_proc_t;
|
|
+')
|
|
+
|
|
+#################################
|
|
+#
|
|
+# SE-PostgreSQL Declarations
|
|
+#
|
|
+
|
|
+## <desc>
|
|
+## <p>
|
|
+## Allow to generate auditallow logs
|
|
+## </p>
|
|
+## </desc>
|
|
+gen_tunable(sepgsql_enable_auditallow, false)
|
|
+
|
|
+## <desc>
|
|
+## <p>
|
|
+## Allow to generate auditdeny logs
|
|
+## </p>
|
|
+## </desc>
|
|
+gen_tunable(sepgsql_enable_auditdeny, true)
|
|
+
|
|
+## <desc>
|
|
+## <p>
|
|
+## Allow widespread permissions for regression test
|
|
+## Don't set TRUE on operation phase
|
|
+## </p>
|
|
+## </desc>
|
|
+gen_tunable(sepgsql_regression_test_mode, false)
|
|
+
|
|
+########################################
|
|
+#
|
|
+# SE-PostgreSQL audit switch for debugging
|
|
+#
|
|
+tunable_policy(`sepgsql_enable_auditallow',`
|
|
+ auditallow domain sepgsql_database_type : db_database *;
|
|
+ auditallow domain sepgsql_table_type : db_table *;
|
|
+ auditallow domain sepgsql_table_type : db_column *;
|
|
+ auditallow domain sepgsql_table_type : db_tuple { relabelfrom relabelto };
|
|
+ auditallow domain sepgsql_procedure_type : db_procedure *;
|
|
+ auditallow domain sepgsql_blob_type : db_blob *;
|
|
+ auditallow domain sepgsql_module_type : db_database { install_module };
|
|
+ auditallow sepgsql_database_type sepgsql_module_type : db_database { load_module };
|
|
+')
|
|
+
|
|
+tunable_policy(`! sepgsql_enable_auditdeny',`
|
|
+ dontaudit domain sepgsql_database_type : db_database *;
|
|
+ dontaudit domain sepgsql_table_type : db_table *;
|
|
+ dontaudit domain sepgsql_table_type : db_column *;
|
|
+ dontaudit domain sepgsql_table_type : db_tuple { relabelfrom relabelto };
|
|
+ dontaudit domain sepgsql_procedure_type : db_procedure *;
|
|
+ dontaudit domain sepgsql_blob_type : db_blob *;
|
|
+ dontaudit domain sepgsql_module_type : db_database { install_module };
|
|
+ dontaudit sepgsql_database_type sepgsql_module_type : db_database { load_module };
|
|
+')
|
|
+
|
|
+########################################
|
|
+#
|
|
+# SE-PostgreSQL regression test mode switch
|
|
+#
|
|
+tunable_policy(`sepgsql_regression_test_mode',`
|
|
+ allow sepgsql_client_type user_home_t : db_database { install_module };
|
|
+ allow sepgsql_unconfined_type user_home_t : db_database { install_module };
|
|
+ allow sepgsql_database_type user_home_t : db_database { load_module };
|
|
+')
|
|
diff -rpNU3 base/src/backend/storage/file/fd.c sepgsql-new/src/backend/storage/file/fd.c
|
|
--- base/src/backend/storage/file/fd.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/storage/file/fd.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -1241,6 +1241,13 @@ FileTruncate(File file, long offset)
|
|
return returnCode;
|
|
}
|
|
|
|
+int
|
|
+FileRawDescriptor(File file)
|
|
+{
|
|
+ Assert(FileIsValid(file));
|
|
+
|
|
+ return VfdCache[file].fd;
|
|
+}
|
|
|
|
/*
|
|
* Routines that want to use stdio (ie, FILE*) should use AllocateFile
|
|
diff -rpNU3 base/src/backend/storage/ipc/ipci.c sepgsql-new/src/backend/storage/ipc/ipci.c
|
|
--- base/src/backend/storage/ipc/ipci.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/storage/ipc/ipci.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -25,6 +25,7 @@
|
|
#include "postmaster/autovacuum.h"
|
|
#include "postmaster/bgwriter.h"
|
|
#include "postmaster/postmaster.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/freespace.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/pg_shmem.h"
|
|
@@ -117,6 +118,7 @@ CreateSharedMemoryAndSemaphores(bool mak
|
|
#ifdef EXEC_BACKEND
|
|
size = add_size(size, ShmemBackendArraySize());
|
|
#endif
|
|
+ size = add_size(size, sepgsqlShmemSize());
|
|
|
|
/* freeze the addin request size and include it */
|
|
addin_request_allowed = false;
|
|
diff -rpNU3 base/src/backend/storage/large_object/inv_api.c sepgsql-new/src/backend/storage/large_object/inv_api.c
|
|
--- base/src/backend/storage/large_object/inv_api.c 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql-new/src/backend/storage/large_object/inv_api.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -39,6 +39,7 @@
|
|
#include "catalog/pg_largeobject.h"
|
|
#include "commands/comment.h"
|
|
#include "libpq/libpq-fs.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/large_object.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/resowner.h"
|
|
@@ -134,12 +135,13 @@ close_lo_relation(bool isCommit)
|
|
* read with can be specified.
|
|
*/
|
|
static bool
|
|
-myLargeObjectExists(Oid loid, Snapshot snapshot)
|
|
+myLargeObjectExists(LargeObjectDesc *lobj)
|
|
{
|
|
bool retval = false;
|
|
Relation pg_largeobject;
|
|
ScanKeyData skey[1];
|
|
SysScanDesc sd;
|
|
+ HeapTuple tuple;
|
|
|
|
/*
|
|
* See if we can find any tuples belonging to the specified LO
|
|
@@ -147,15 +149,19 @@ myLargeObjectExists(Oid loid, Snapshot s
|
|
ScanKeyInit(&skey[0],
|
|
Anum_pg_largeobject_loid,
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
- ObjectIdGetDatum(loid));
|
|
+ ObjectIdGetDatum(lobj->id));
|
|
|
|
pg_largeobject = heap_open(LargeObjectRelationId, AccessShareLock);
|
|
|
|
sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndexId, true,
|
|
- snapshot, 1, skey);
|
|
+ lobj->snapshot, 1, skey);
|
|
|
|
- if (systable_getnext(sd) != NULL)
|
|
+ tuple = systable_getnext(sd);
|
|
+ if (HeapTupleIsValid(tuple))
|
|
+ {
|
|
retval = true;
|
|
+ lobj->secid = HeapTupleGetSecLabel(tuple);
|
|
+ }
|
|
|
|
systable_endscan(sd);
|
|
|
|
@@ -254,7 +260,7 @@ inv_open(Oid lobjId, int flags, MemoryCo
|
|
elog(ERROR, "invalid flags: %d", flags);
|
|
|
|
/* Can't use LargeObjectExists here because it always uses SnapshotNow */
|
|
- if (!myLargeObjectExists(lobjId, retval->snapshot))
|
|
+ if (!myLargeObjectExists(retval))
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
errmsg("large object %u does not exist", lobjId)));
|
|
@@ -676,6 +682,8 @@ inv_write(LargeObjectDesc *obj_desc, con
|
|
values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
|
|
values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
|
|
newtup = heap_formtuple(lo_heap_r->rd_att, values, nulls);
|
|
+ if (HeapTupleHasSecLabel(newtup))
|
|
+ HeapTupleSetSecLabel(newtup, obj_desc->secid);
|
|
simple_heap_insert(lo_heap_r, newtup);
|
|
CatalogIndexInsert(indstate, newtup);
|
|
heap_freetuple(newtup);
|
|
@@ -836,6 +844,8 @@ inv_truncate(LargeObjectDesc *obj_desc,
|
|
values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
|
|
values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
|
|
newtup = heap_formtuple(lo_heap_r->rd_att, values, nulls);
|
|
+ if (HeapTupleHasSecLabel(newtup))
|
|
+ HeapTupleSetSecLabel(newtup, obj_desc->secid);
|
|
simple_heap_insert(lo_heap_r, newtup);
|
|
CatalogIndexInsert(indstate, newtup);
|
|
heap_freetuple(newtup);
|
|
@@ -859,3 +869,99 @@ inv_truncate(LargeObjectDesc *obj_desc,
|
|
*/
|
|
CommandCounterIncrement();
|
|
}
|
|
+
|
|
+Oid
|
|
+inv_get_security(Oid loid)
|
|
+{
|
|
+ Relation rel;
|
|
+ ScanKeyData skey;
|
|
+ SysScanDesc scan;
|
|
+ HeapTuple tuple;
|
|
+ Oid secid = InvalidOid;
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber,
|
|
+ F_OIDEQ, ObjectIdGetDatum(loid));
|
|
+
|
|
+ rel = heap_open(LargeObjectRelationId, AccessShareLock);
|
|
+
|
|
+ scan = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
|
|
+ SnapshotNow, 1, &skey);
|
|
+ tuple = systable_getnext(scan);
|
|
+
|
|
+ if (HeapTupleIsValid(tuple))
|
|
+ {
|
|
+ /*
|
|
+ * SELinux: check db_blob:{getattr}
|
|
+ */
|
|
+ sepgsqlCheckBlobGetattr(tuple);
|
|
+ secid = HeapTupleGetSecLabel(tuple);
|
|
+ }
|
|
+ systable_endscan(scan);
|
|
+
|
|
+ heap_close(rel, AccessShareLock);
|
|
+
|
|
+ return secid;
|
|
+}
|
|
+
|
|
+void
|
|
+inv_set_security(Oid loid, Oid secid)
|
|
+{
|
|
+ Relation rel;
|
|
+ ScanKeyData skey;
|
|
+ SysScanDesc scan;
|
|
+ HeapTuple tuple;
|
|
+ CatalogIndexState ind;
|
|
+ bool found = false;
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber,
|
|
+ F_OIDEQ, ObjectIdGetDatum(loid));
|
|
+
|
|
+ rel = heap_open(LargeObjectRelationId, RowExclusiveLock);
|
|
+
|
|
+ ind = CatalogOpenIndexes(rel);
|
|
+
|
|
+ scan = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
|
|
+ SnapshotNow, 1, &skey);
|
|
+ while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
|
+ {
|
|
+ HeapTuple newtuple;
|
|
+ Datum values[Natts_pg_largeobject];
|
|
+ bool nulls[Natts_pg_largeobject];
|
|
+ bool replaces[Natts_pg_largeobject];
|
|
+
|
|
+ memset(replaces, false, sizeof(replaces));
|
|
+
|
|
+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
|
|
+ values, nulls, replaces);
|
|
+ if (!HeapTupleHasSecLabel(newtuple))
|
|
+ elog(ERROR, "Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(rel));
|
|
+ HeapTupleSetSecLabel(newtuple, secid);
|
|
+
|
|
+ /*
|
|
+ * SELinux: check db_blob:{setattr relabelfrom relabelto}
|
|
+ */
|
|
+ if (!found)
|
|
+ sepgsqlCheckBlobRelabel(tuple, newtuple);
|
|
+
|
|
+ simple_heap_update(rel, &tuple->t_self, newtuple);
|
|
+ CatalogUpdateIndexes(rel, newtuple);
|
|
+ found = true;
|
|
+ }
|
|
+ systable_endscan(scan);
|
|
+
|
|
+ CatalogCloseIndexes(ind);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+
|
|
+ CommandCounterIncrement();
|
|
+
|
|
+ if (!found)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
+ errmsg("large object %u does not exist", loid)));
|
|
+}
|
|
diff -rpNU3 base/src/backend/tcop/pquery.c sepgsql-new/src/backend/tcop/pquery.c
|
|
--- base/src/backend/tcop/pquery.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/tcop/pquery.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -560,7 +560,7 @@ PortalStart(Portal portal, ParamListInfo
|
|
Assert(pstmt->returningLists);
|
|
portal->tupDesc =
|
|
ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
|
|
- false);
|
|
+ false, false);
|
|
}
|
|
|
|
/*
|
|
diff -rpNU3 base/src/backend/tcop/utility.c sepgsql-new/src/backend/tcop/utility.c
|
|
--- base/src/backend/tcop/utility.c 2008-11-05 09:57:00.000000000 +0900
|
|
+++ sepgsql-new/src/backend/tcop/utility.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -49,6 +49,7 @@
|
|
#include "postmaster/bgwriter.h"
|
|
#include "rewrite/rewriteDefine.h"
|
|
#include "rewrite/rewriteRemove.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/fd.h"
|
|
#include "tcop/pquery.h"
|
|
#include "tcop/utility.h"
|
|
@@ -1022,6 +1023,10 @@ ProcessUtility(Node *parsetree,
|
|
LoadStmt *stmt = (LoadStmt *) parsetree;
|
|
|
|
closeAllVfds(); /* probably not necessary... */
|
|
+
|
|
+ /* SELinux checks db_database:{install_module} priv */
|
|
+ sepgsqlCheckDatabaseInstallModule(stmt->filename);
|
|
+
|
|
/* Allowed names are restricted if you're not superuser */
|
|
load_file(stmt->filename, !superuser());
|
|
}
|
|
diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql-new/src/backend/utils/adt/ri_triggers.c
|
|
--- base/src/backend/utils/adt/ri_triggers.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/adt/ri_triggers.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -37,6 +37,7 @@
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_relation.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/rowlevel.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -3256,6 +3257,7 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPl
|
|
int spi_result;
|
|
Oid save_userid;
|
|
bool save_secdefcxt;
|
|
+ bool save_rowlv_bahavior;
|
|
Datum vals[RI_MAX_NUMKEYS * 2];
|
|
char nulls[RI_MAX_NUMKEYS * 2];
|
|
|
|
@@ -3336,11 +3338,29 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPl
|
|
GetUserIdAndContext(&save_userid, &save_secdefcxt);
|
|
SetUserIdAndContext(RelationGetForm(query_rel)->relowner, true);
|
|
|
|
- /* Finally we can run the query. */
|
|
- spi_result = SPI_execute_snapshot(qplan,
|
|
- vals, nulls,
|
|
- test_snapshot, crosscheck_snapshot,
|
|
- false, false, limit);
|
|
+ /*
|
|
+ * Switch internal state of row-level security features
|
|
+ *
|
|
+ * NOTE: when a user tries to update/delete a PK which
|
|
+ * is refered by invisible FKs, it need to be aborted
|
|
+ * due to the referencial integrity.
|
|
+ */
|
|
+ save_rowlv_bahavior = rowlvBehaviorSwitchTo(detectNewRows);
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ /* Finally we can run the query. */
|
|
+ spi_result = SPI_execute_snapshot(qplan,
|
|
+ vals, nulls,
|
|
+ test_snapshot, crosscheck_snapshot,
|
|
+ false, false, limit);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ rowlvBehaviorSwitchTo(save_rowlv_bahavior);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
|
|
/* Restore UID */
|
|
SetUserIdAndContext(save_userid, save_secdefcxt);
|
|
diff -rpNU3 base/src/backend/utils/adt/varlena.c sepgsql-new/src/backend/utils/adt/varlena.c
|
|
--- base/src/backend/utils/adt/varlena.c 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/adt/varlena.c 2009-03-13 13:09:47.000000000 +0900
|
|
@@ -70,6 +70,103 @@ static text *text_substring(Datum str,
|
|
|
|
static void appendStringInfoText(StringInfo str, const text *t);
|
|
|
|
+/*****************************************************************************
|
|
+ * CONVERSION ROUTINES EXPORTED FOR USE BY C CODE *
|
|
+ *****************************************************************************/
|
|
+
|
|
+/*
|
|
+ * cstring_to_text
|
|
+ *
|
|
+ * Create a text value from a null-terminated C string.
|
|
+ *
|
|
+ * The new text value is freshly palloc'd with a full-size VARHDR.
|
|
+ */
|
|
+text *
|
|
+cstring_to_text(const char *s)
|
|
+{
|
|
+ return cstring_to_text_with_len(s, strlen(s));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * cstring_to_text_with_len
|
|
+ *
|
|
+ * Same as cstring_to_text except the caller specifies the string length;
|
|
+ * the string need not be null_terminated.
|
|
+ */
|
|
+text *
|
|
+cstring_to_text_with_len(const char *s, int len)
|
|
+{
|
|
+ text *result = (text *) palloc(len + VARHDRSZ);
|
|
+
|
|
+ SET_VARSIZE(result, len + VARHDRSZ);
|
|
+ memcpy(VARDATA(result), s, len);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * text_to_cstring
|
|
+ *
|
|
+ * Create a palloc'd, null-terminated C string from a text value.
|
|
+ *
|
|
+ * We support being passed a compressed or toasted text value.
|
|
+ * This is a bit bogus since such values shouldn't really be referred to as
|
|
+ * "text *", but it seems useful for robustness. If we didn't handle that
|
|
+ * case here, we'd need another routine that did, anyway.
|
|
+ */
|
|
+char *
|
|
+text_to_cstring(const text *t)
|
|
+{
|
|
+ /* must cast away the const, unfortunately */
|
|
+ text *tunpacked = pg_detoast_datum_packed((struct varlena *) t);
|
|
+ int len = VARSIZE_ANY_EXHDR(tunpacked);
|
|
+ char *result;
|
|
+
|
|
+ result = (char *) palloc(len + 1);
|
|
+ memcpy(result, VARDATA_ANY(tunpacked), len);
|
|
+ result[len] = '\0';
|
|
+
|
|
+ if (tunpacked != t)
|
|
+ pfree(tunpacked);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * text_to_cstring_buffer
|
|
+ *
|
|
+ * Copy a text value into a caller-supplied buffer of size dst_len.
|
|
+ *
|
|
+ * The text string is truncated if necessary to fit. The result is
|
|
+ * guaranteed null-terminated (unless dst_len == 0).
|
|
+ *
|
|
+ * We support being passed a compressed or toasted text value.
|
|
+ * This is a bit bogus since such values shouldn't really be referred to as
|
|
+ * "text *", but it seems useful for robustness. If we didn't handle that
|
|
+ * case here, we'd need another routine that did, anyway.
|
|
+ */
|
|
+void
|
|
+text_to_cstring_buffer(const text *src, char *dst, size_t dst_len)
|
|
+{
|
|
+ /* must cast away the const, unfortunately */
|
|
+ text *srcunpacked = pg_detoast_datum_packed((struct varlena *) src);
|
|
+ size_t src_len = VARSIZE_ANY_EXHDR(srcunpacked);
|
|
+
|
|
+ if (dst_len > 0)
|
|
+ {
|
|
+ dst_len--;
|
|
+ if (dst_len >= src_len)
|
|
+ dst_len = src_len;
|
|
+ else /* ensure truncation is encoding-safe */
|
|
+ dst_len = pg_mbcliplen(VARDATA_ANY(srcunpacked), src_len, dst_len);
|
|
+ memcpy(dst, VARDATA_ANY(srcunpacked), dst_len);
|
|
+ dst[dst_len] = '\0';
|
|
+ }
|
|
+
|
|
+ if (srcunpacked != src)
|
|
+ pfree(srcunpacked);
|
|
+}
|
|
+
|
|
|
|
/*****************************************************************************
|
|
* USER I/O ROUTINES *
|
|
diff -rpNU3 base/src/backend/utils/cache/catcache.c sepgsql-new/src/backend/utils/cache/catcache.c
|
|
--- base/src/backend/utils/cache/catcache.c 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/cache/catcache.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -1313,6 +1313,38 @@ ReleaseCatCache(HeapTuple tuple)
|
|
CatCacheRemoveCTup(ct->my_cache, ct);
|
|
}
|
|
|
|
+/*
|
|
+ * InsertCatCache
|
|
+ *
|
|
+ * This function enables to refer a tuple recently inserted, using catcache
|
|
+ * until next CommandCounterIncrement.
|
|
+ */
|
|
+void InsertCatCache(CatCache *cache, HeapTuple tuple)
|
|
+{
|
|
+ ScanKeyData skey[4];
|
|
+ uint32 hashValue;
|
|
+ Index hashIndex;
|
|
+ bool isnull;
|
|
+ int i;
|
|
+
|
|
+ /* initialize the search key information */
|
|
+ memcpy(skey, cache->cc_skey, sizeof(skey));
|
|
+ for (i=0; i < cache->cc_nkeys; i++)
|
|
+ {
|
|
+ skey[i].sk_argument = heap_getattr(tuple, cache->cc_key[i],
|
|
+ cache->cc_tupdesc, &isnull);
|
|
+ Assert(!isnull);
|
|
+ }
|
|
+
|
|
+ /* find the hash bucket in which to look for the tuple */
|
|
+ if (cache->cc_tupdesc == NULL)
|
|
+ CatalogCacheInitializeCache(cache);
|
|
+ hashValue = CatalogCacheComputeHashValue(cache, cache->cc_nkeys, skey);
|
|
+ hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
|
|
+
|
|
+ /* Insert a new tuple */
|
|
+ CatalogCacheCreateEntry(cache, tuple, hashValue, hashIndex, false);
|
|
+}
|
|
|
|
/*
|
|
* SearchCatCacheList
|
|
diff -rpNU3 base/src/backend/utils/cache/plancache.c sepgsql-new/src/backend/utils/cache/plancache.c
|
|
--- base/src/backend/utils/cache/plancache.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/cache/plancache.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -880,12 +880,14 @@ PlanCacheComputeResultDesc(List *stmt_li
|
|
if (IsA(node, Query))
|
|
{
|
|
query = (Query *) node;
|
|
- return ExecCleanTypeFromTL(query->targetList, false);
|
|
+ return ExecCleanTypeFromTL(query->targetList,
|
|
+ false, false);
|
|
}
|
|
if (IsA(node, PlannedStmt))
|
|
{
|
|
pstmt = (PlannedStmt *) node;
|
|
- return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false);
|
|
+ return ExecCleanTypeFromTL(pstmt->planTree->targetlist,
|
|
+ false, false);
|
|
}
|
|
/* other cases shouldn't happen, but return NULL */
|
|
break;
|
|
@@ -896,13 +898,15 @@ PlanCacheComputeResultDesc(List *stmt_li
|
|
{
|
|
query = (Query *) node;
|
|
Assert(query->returningList);
|
|
- return ExecCleanTypeFromTL(query->returningList, false);
|
|
+ return ExecCleanTypeFromTL(query->returningList,
|
|
+ false, false);
|
|
}
|
|
if (IsA(node, PlannedStmt))
|
|
{
|
|
pstmt = (PlannedStmt *) node;
|
|
Assert(pstmt->returningLists);
|
|
- return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), false);
|
|
+ return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
|
|
+ false, false);
|
|
}
|
|
/* other cases shouldn't happen, but return NULL */
|
|
break;
|
|
diff -rpNU3 base/src/backend/utils/cache/relcache.c sepgsql-new/src/backend/utils/cache/relcache.c
|
|
--- base/src/backend/utils/cache/relcache.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/cache/relcache.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -46,6 +46,7 @@
|
|
#include "catalog/pg_opclass.h"
|
|
#include "catalog/pg_proc.h"
|
|
#include "catalog/pg_rewrite.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "commands/trigger.h"
|
|
#include "miscadmin.h"
|
|
@@ -324,7 +325,13 @@ AllocateRelationDesc(Relation relation,
|
|
/* initialize relation tuple form */
|
|
relation->rd_rel = relationForm;
|
|
|
|
- /* and allocate attribute tuple form storage */
|
|
+ /*
|
|
+ * and allocate attribute tuple form storage
|
|
+ *
|
|
+ * Please note that relation->rd_att->tdhasrowacl and tdhasseclabel
|
|
+ * have to be fixed up correctly at RelationBuildTupleDesc(), because
|
|
+ * security module may need reloptions info to make its decision.
|
|
+ */
|
|
relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts,
|
|
relationForm->relhasoids);
|
|
/* which we mark as a reference-counted tupdesc */
|
|
@@ -877,6 +884,10 @@ RelationBuildDesc(Oid targetRelId, Relat
|
|
/* extract reloptions if any */
|
|
RelationParseRelOptions(relation, pg_class_tuple);
|
|
|
|
+ /* fixup relation->rd_att->tdhasseclabel */
|
|
+ relation->rd_att->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(relation);
|
|
+
|
|
/*
|
|
* initialize the relation lock manager information
|
|
*/
|
|
@@ -1462,6 +1473,12 @@ formrdesc(const char *relationName, Oid
|
|
relation->rd_rel->relfilenode = RelationGetRelid(relation);
|
|
|
|
/*
|
|
+ * Fixup relation->rd_att->tdhasrowacl and tdhasseclabel
|
|
+ */
|
|
+ RelationGetDescr(relation)->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(relation);
|
|
+
|
|
+ /*
|
|
* initialize the relation lock manager information
|
|
*/
|
|
RelationInitLockInfo(relation); /* see lmgr.c */
|
|
@@ -2687,6 +2704,13 @@ BuildHardcodedDescriptor(int natts, Form
|
|
|
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
|
|
|
+ /*
|
|
+ * NOTE: we assume the returned TupleDesc is only used for
|
|
+ * references to toast'ed data, and it is not delivered to
|
|
+ * heap_form_tuple(), so TupleDesc->tdhasrowacl and tdhasseclabel
|
|
+ * don't give us any effect.
|
|
+ * We omit to invoke securityTupleDescHasSecLabel() here.
|
|
+ */
|
|
result = CreateTemplateTupleDesc(natts, hasoids);
|
|
result->tdtypeid = RECORDOID; /* not right, but we don't care */
|
|
result->tdtypmod = -1;
|
|
@@ -3446,6 +3470,12 @@ load_relcache_init_file(void)
|
|
rel->rd_options = NULL;
|
|
}
|
|
|
|
+ /*
|
|
+ * fixup rel->rd_att->tdhassecurity
|
|
+ */
|
|
+ rel->rd_att->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(rel);
|
|
+
|
|
/* mark not-null status */
|
|
if (has_not_null)
|
|
{
|
|
diff -rpNU3 base/src/backend/utils/cache/syscache.c sepgsql-new/src/backend/utils/cache/syscache.c
|
|
--- base/src/backend/utils/cache/syscache.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/cache/syscache.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -39,6 +39,7 @@
|
|
#include "catalog/pg_opfamily.h"
|
|
#include "catalog/pg_proc.h"
|
|
#include "catalog/pg_rewrite.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_statistic.h"
|
|
#include "catalog/pg_ts_config.h"
|
|
#include "catalog/pg_ts_config_map.h"
|
|
@@ -533,6 +534,30 @@ static const struct cachedesc cacheinfo[
|
|
},
|
|
1024
|
|
},
|
|
+ {SecurityRelationId, /* SECURITYLABEL */
|
|
+ SecuritySeclabelIndexId,
|
|
+ 0,
|
|
+ 1,
|
|
+ {
|
|
+ Anum_pg_security_seclabel,
|
|
+ 0,
|
|
+ 0,
|
|
+ 0
|
|
+ },
|
|
+ 128
|
|
+ },
|
|
+ {SecurityRelationId, /*SECURITYOID */
|
|
+ SecurityOidIndexId,
|
|
+ 0,
|
|
+ 1,
|
|
+ {
|
|
+ ObjectIdAttributeNumber,
|
|
+ 0,
|
|
+ 0,
|
|
+ 0
|
|
+ },
|
|
+ 128
|
|
+ },
|
|
{StatisticRelationId, /* STATRELATT */
|
|
StatisticRelidAttnumIndexId,
|
|
Anum_pg_statistic_starelid,
|
|
@@ -784,6 +809,21 @@ ReleaseSysCache(HeapTuple tuple)
|
|
}
|
|
|
|
/*
|
|
+ * InsertSysCache
|
|
+ * interts a tuple temporary until next CommandCounterIncrement
|
|
+ */
|
|
+void InsertSysCache(Oid relid, HeapTuple tuple)
|
|
+{
|
|
+ int cacheId;
|
|
+
|
|
+ for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
|
|
+ {
|
|
+ if (SysCache[cacheId]->cc_reloid == relid)
|
|
+ InsertCatCache(SysCache[cacheId], tuple);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
* SearchSysCacheCopy
|
|
*
|
|
* A convenience routine that does SearchSysCache and (if successful)
|
|
diff -rpNU3 base/src/backend/utils/fmgr/dfmgr.c sepgsql-new/src/backend/utils/fmgr/dfmgr.c
|
|
--- base/src/backend/utils/fmgr/dfmgr.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/fmgr/dfmgr.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -22,6 +22,7 @@
|
|
#include "port/dynloader/win32.h"
|
|
#endif
|
|
#include "miscadmin.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "utils/dynamic_loader.h"
|
|
#include "utils/hsearch.h"
|
|
|
|
@@ -73,7 +74,6 @@ char *Dynamic_library_path;
|
|
static void *internal_load_library(const char *libname);
|
|
static void internal_unload_library(const char *libname);
|
|
static bool file_exists(const char *name);
|
|
-static char *expand_dynamic_library_name(const char *name);
|
|
static void check_restricted_library_name(const char *name);
|
|
static char *substitute_libpath_macro(const char *name);
|
|
static char *find_in_dynamic_libpath(const char *basename);
|
|
@@ -106,6 +106,9 @@ load_external_function(char *filename, c
|
|
/* Expand the possibly-abbreviated filename to an exact path name */
|
|
fullname = expand_dynamic_library_name(filename);
|
|
|
|
+ /* SELinux checks db_database:{load_module} permission */
|
|
+ sepgsqlCheckDatabaseLoadModule(fullname);
|
|
+
|
|
/* Load the shared library, unless we already did */
|
|
lib_handle = internal_load_library(fullname);
|
|
|
|
@@ -146,6 +149,9 @@ load_file(const char *filename, bool res
|
|
/* Expand the possibly-abbreviated filename to an exact path name */
|
|
fullname = expand_dynamic_library_name(filename);
|
|
|
|
+ /* SELinux checks db_database:{load_module} */
|
|
+ sepgsqlCheckDatabaseLoadModule(fullname);
|
|
+
|
|
/* Unload the library if currently loaded */
|
|
internal_unload_library(fullname);
|
|
|
|
@@ -395,7 +401,7 @@ file_exists(const char *name)
|
|
*
|
|
* The result will always be freshly palloc'd.
|
|
*/
|
|
-static char *
|
|
+char *
|
|
expand_dynamic_library_name(const char *name)
|
|
{
|
|
bool have_slash;
|
|
diff -rpNU3 base/src/backend/utils/fmgr/fmgr.c sepgsql-new/src/backend/utils/fmgr/fmgr.c
|
|
--- base/src/backend/utils/fmgr/fmgr.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/fmgr/fmgr.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -23,6 +23,7 @@
|
|
#include "executor/spi.h"
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_expr.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgrtab.h"
|
|
#include "utils/guc.h"
|
|
@@ -227,6 +228,12 @@ fmgr_info_cxt_security(Oid functionId, F
|
|
finfo->fn_addr = fmgr_security_definer;
|
|
finfo->fn_oid = functionId;
|
|
ReleaseSysCache(procedureTuple);
|
|
+ /*
|
|
+ * NOTE: It is not necessary to set up Trusted Procedure
|
|
+ * here, because fmgr_security_definer() invokes this
|
|
+ * function with ignore_security=true again. It is set up
|
|
+ * later.
|
|
+ */
|
|
return;
|
|
}
|
|
|
|
@@ -274,6 +281,7 @@ fmgr_info_cxt_security(Oid functionId, F
|
|
}
|
|
|
|
finfo->fn_oid = functionId;
|
|
+ sepgsqlCheckProcedureEntrypoint(finfo, procedureTuple);
|
|
ReleaseSysCache(procedureTuple);
|
|
}
|
|
|
|
diff -rpNU3 base/src/backend/utils/init/postinit.c sepgsql-new/src/backend/utils/init/postinit.c
|
|
--- base/src/backend/utils/init/postinit.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/init/postinit.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -31,6 +31,7 @@
|
|
#include "pgstat.h"
|
|
#include "postmaster/autovacuum.h"
|
|
#include "postmaster/postmaster.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/backendid.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/ipc.h"
|
|
@@ -194,12 +195,9 @@ CheckMyDatabase(const char *name, bool a
|
|
name)));
|
|
|
|
/*
|
|
- * Check privilege to connect to the database. (The am_superuser test
|
|
- * is redundant, but since we have the flag, might as well check it
|
|
- * and save a few cycles.)
|
|
+ * Check privilege to connect to the database.
|
|
*/
|
|
- if (!am_superuser &&
|
|
- pg_database_aclcheck(MyDatabaseId, GetUserId(),
|
|
+ if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
|
|
ACL_CONNECT) != ACLCHECK_OK)
|
|
ereport(FATAL,
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
@@ -541,6 +539,9 @@ InitPostgres(const char *in_dbname, Oid
|
|
*/
|
|
RelationCacheInitializePhase2();
|
|
|
|
+ /* initialize SE-PostgreSQL feature */
|
|
+ sepgsqlInitialize();
|
|
+
|
|
/*
|
|
* Figure out our postgres user id, and see if we are a superuser.
|
|
*
|
|
diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql-new/src/backend/utils/misc/guc.c
|
|
--- base/src/backend/utils/misc/guc.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/misc/guc.c 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -54,6 +54,7 @@
|
|
#include "postmaster/postmaster.h"
|
|
#include "postmaster/syslogger.h"
|
|
#include "postmaster/walwriter.h"
|
|
+#include "security/sepgsql.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/freespace.h"
|
|
#include "tcop/tcopprot.h"
|
|
@@ -1091,6 +1092,24 @@ static struct config_bool ConfigureNames
|
|
&IgnoreSystemIndexes,
|
|
false, NULL, NULL
|
|
},
|
|
+#ifdef HAVE_SELINUX
|
|
+ {
|
|
+ {"sepostgresql", PGC_POSTMASTER, CONN_AUTH_SECURITY,
|
|
+ gettext_noop("SE-PostgreSQL activation option to be turned on/off"),
|
|
+ NULL,
|
|
+ },
|
|
+ &sepostgresql_is_enabled,
|
|
+ false, NULL, NULL
|
|
+ },
|
|
+ {
|
|
+ {"sepostgresql_row_level", PGC_POSTMASTER, CONN_AUTH_SECURITY,
|
|
+ gettext_noop("Row-level access controls on SE-PostgreSQL"),
|
|
+ NULL,
|
|
+ },
|
|
+ &sepostgresql_row_level,
|
|
+ true, NULL, NULL
|
|
+ },
|
|
+#endif
|
|
|
|
/* End-of-list marker */
|
|
{
|
|
diff -rpNU3 base/src/backend/utils/misc/postgresql.conf.sample sepgsql-new/src/backend/utils/misc/postgresql.conf.sample
|
|
--- base/src/backend/utils/misc/postgresql.conf.sample 2008-02-03 01:11:28.000000000 +0900
|
|
+++ sepgsql-new/src/backend/utils/misc/postgresql.conf.sample 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -48,7 +48,7 @@
|
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
-# CONNECTIONS AND AUTHENTICATION
|
|
+# CONNECTIONS, AUTHENTICATION AND SECURITY
|
|
#------------------------------------------------------------------------------
|
|
|
|
# - Connection Settings -
|
|
@@ -96,7 +96,7 @@
|
|
# 0 selects the system default
|
|
#tcp_keepalives_count = 0 # TCP_KEEPCNT;
|
|
# 0 selects the system default
|
|
-
|
|
+#sepostgresql = off # SE-PostgreSQL support
|
|
|
|
#------------------------------------------------------------------------------
|
|
# RESOURCE USAGE (except WAL)
|
|
diff -rpNU3 base/src/include/access/heapam.h sepgsql-new/src/include/access/heapam.h
|
|
--- base/src/include/access/heapam.h 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql-new/src/include/access/heapam.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -249,7 +249,7 @@ extern void heap_free_minimal_tuple(Mini
|
|
extern MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup);
|
|
extern HeapTuple heap_tuple_from_minimal_tuple(MinimalTuple mtup);
|
|
extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup);
|
|
-extern HeapTuple heap_addheader(int natts, bool withoid,
|
|
+extern HeapTuple heap_addheader(int natts, bool withoid, bool withseclabel,
|
|
Size structlen, void *structure);
|
|
|
|
/* in heap/pruneheap.c */
|
|
diff -rpNU3 base/src/include/access/htup.h sepgsql-new/src/include/access/htup.h
|
|
--- base/src/include/access/htup.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/access/htup.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -161,7 +161,7 @@ typedef HeapTupleHeaderData *HeapTupleHe
|
|
#define HEAP_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */
|
|
#define HEAP_HASEXTERNAL 0x0004 /* has external stored attribute(s) */
|
|
#define HEAP_HASOID 0x0008 /* has an object-id field */
|
|
-/* bit 0x0010 is available */
|
|
+#define HEAP_HAS_SECLABEL 0x0010 /* has an security label field */
|
|
#define HEAP_COMBOCID 0x0020 /* t_cid is a combo cid */
|
|
#define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */
|
|
#define HEAP_XMAX_SHARED_LOCK 0x0080 /* xmax is shared locker */
|
|
@@ -288,6 +288,9 @@ do { \
|
|
(tup)->t_choice.t_datum.datum_typmod = (typmod) \
|
|
)
|
|
|
|
+#define HeapTupleHeaderHasOid(tup) \
|
|
+ ((tup)->t_infomask & HEAP_HASOID)
|
|
+
|
|
#define HeapTupleHeaderGetOid(tup) \
|
|
( \
|
|
((tup)->t_infomask & HEAP_HASOID) ? \
|
|
@@ -347,6 +350,34 @@ do { \
|
|
(tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \
|
|
)
|
|
|
|
+#define HeapTupleHeaderHasSecLabel(tup) \
|
|
+ ((tup)->t_infomask & HEAP_HAS_SECLABEL)
|
|
+
|
|
+#define HeapTupleHeaderGetSecLabel(tup) \
|
|
+ ( \
|
|
+ HeapTupleHeaderHasSecLabel(tup) \
|
|
+ ? (*((Oid *)((char *)(tup) + (tup)->t_hoff \
|
|
+ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \
|
|
+ - sizeof(Oid)))) \
|
|
+ : InvalidOid \
|
|
+ )
|
|
+
|
|
+#define HeapTupleHeaderSetSecLabel(tup, seclabel) \
|
|
+ do { \
|
|
+ Assert(HeapTupleHeaderHasSecLabel(tup)); \
|
|
+ *((Oid *)((char *)(tup) + (tup)->t_hoff \
|
|
+ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \
|
|
+ - sizeof(Oid))) = (seclabel); \
|
|
+ } while(0)
|
|
+
|
|
+#define HeapTupleHasSecLabel(tuple) \
|
|
+ HeapTupleHeaderHasSecLabel((tuple)->t_data)
|
|
+
|
|
+#define HeapTupleGetSecLabel(tuple) \
|
|
+ HeapTupleHeaderGetSecLabel((tuple)->t_data)
|
|
+
|
|
+#define HeapTupleSetSecLabel(tuple, seclabel) \
|
|
+ HeapTupleHeaderSetSecLabel((tuple)->t_data, (seclabel))
|
|
|
|
/*
|
|
* BITMAPLEN(NATTS) -
|
|
@@ -402,8 +433,13 @@ do { \
|
|
#define MaxTransactionIdAttributeNumber (-5)
|
|
#define MaxCommandIdAttributeNumber (-6)
|
|
#define TableOidAttributeNumber (-7)
|
|
-#define FirstLowInvalidHeapAttributeNumber (-8)
|
|
+#define SecurityLabelAttributeNumber (-8)
|
|
+#define FirstLowInvalidHeapAttributeNumber (-9)
|
|
|
|
+/*
|
|
+ * Attribute names for the system-defined attributes
|
|
+ */
|
|
+#define SecurityLabelAttributeName "security_context"
|
|
|
|
/*
|
|
* MinimalTuple is an alternative representation that is used for transient
|
|
@@ -548,6 +584,9 @@ typedef HeapTupleData *HeapTuple;
|
|
#define HeapTupleClearHeapOnly(tuple) \
|
|
HeapTupleHeaderClearHeapOnly((tuple)->t_data)
|
|
|
|
+#define HeapTupleHasOid(tuple) \
|
|
+ HeapTupleHeaderHasOid((tuple)->t_data)
|
|
+
|
|
#define HeapTupleGetOid(tuple) \
|
|
HeapTupleHeaderGetOid((tuple)->t_data)
|
|
|
|
diff -rpNU3 base/src/include/access/tupdesc.h sepgsql-new/src/include/access/tupdesc.h
|
|
--- base/src/include/access/tupdesc.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/access/tupdesc.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -75,6 +75,7 @@ typedef struct tupleDesc
|
|
Oid tdtypeid; /* composite type ID for tuple type */
|
|
int32 tdtypmod; /* typmod for tuple type */
|
|
bool tdhasoid; /* tuple has oid attribute in its header */
|
|
+ bool tdhasseclabel; /* tuple has security label in its header */
|
|
int tdrefcount; /* reference count, or -1 if not counting */
|
|
} *TupleDesc;
|
|
|
|
diff -rpNU3 base/src/include/catalog/heap.h sepgsql-new/src/include/catalog/heap.h
|
|
--- base/src/include/catalog/heap.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/catalog/heap.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -52,7 +52,8 @@ extern Oid heap_create_with_catalog(cons
|
|
int oidinhcount,
|
|
OnCommitAction oncommit,
|
|
Datum reloptions,
|
|
- bool allow_system_table_mods);
|
|
+ bool allow_system_table_mods,
|
|
+ List *selblList);
|
|
|
|
extern void heap_drop_with_catalog(Oid relid);
|
|
|
|
@@ -65,7 +66,8 @@ extern List *heap_truncate_find_FKs(List
|
|
extern void InsertPgClassTuple(Relation pg_class_desc,
|
|
Relation new_rel_desc,
|
|
Oid new_rel_oid,
|
|
- Datum reloptions);
|
|
+ Datum reloptions,
|
|
+ Oid relselabel);
|
|
|
|
extern List *AddRelationRawConstraints(Relation rel,
|
|
List *rawColDefaults,
|
|
@@ -96,6 +98,8 @@ extern Form_pg_attribute SystemAttribute
|
|
extern Form_pg_attribute SystemAttributeByName(const char *attname,
|
|
bool relhasoids);
|
|
|
|
+extern bool SystemAttributeIsWritable(AttrNumber attnum);
|
|
+
|
|
extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind);
|
|
|
|
extern void CheckAttributeType(const char *attname, Oid atttypid);
|
|
diff -rpNU3 base/src/include/catalog/indexing.h sepgsql-new/src/include/catalog/indexing.h
|
|
--- base/src/include/catalog/indexing.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/catalog/indexing.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -252,6 +252,11 @@ DECLARE_UNIQUE_INDEX(pg_type_oid_index,
|
|
DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index, 2704, on pg_type using btree(typname name_ops, typnamespace oid_ops));
|
|
#define TypeNameNspIndexId 2704
|
|
|
|
+DECLARE_UNIQUE_INDEX(pg_security_oid_index, 3401, on pg_security using btree(oid oid_ops));
|
|
+#define SecurityOidIndexId 3401
|
|
+DECLARE_UNIQUE_INDEX(pg_security_seclabel_index, 3402, on pg_security using btree(seclabel text_ops));
|
|
+#define SecuritySeclabelIndexId 3402
|
|
+
|
|
/* last step of initialization script: build the indexes declared above */
|
|
BUILD_INDICES
|
|
|
|
diff -rpNU3 base/src/include/catalog/pg_attribute.h sepgsql-new/src/include/catalog/pg_attribute.h
|
|
--- base/src/include/catalog/pg_attribute.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/catalog/pg_attribute.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -282,6 +282,7 @@ DATA(insert ( 1247 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1247 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_proc
|
|
@@ -338,6 +339,7 @@ DATA(insert ( 1255 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1255 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_attribute
|
|
@@ -386,6 +388,7 @@ DATA(insert ( 1249 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1249 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_class
|
|
@@ -454,6 +457,7 @@ DATA(insert ( 1259 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1259 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_index
|
|
diff -rpNU3 base/src/include/catalog/pg_proc.h sepgsql-new/src/include/catalog/pg_proc.h
|
|
--- base/src/include/catalog/pg_proc.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/catalog/pg_proc.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -4113,6 +4113,22 @@ DESCR("I/O");
|
|
DATA(insert OID = 2963 ( uuid_hash PGNSP PGUID 12 1 0 f f t f i 1 23 "2950" _null_ _null_ _null_ uuid_hash - _null_ _null_ ));
|
|
DESCR("hash");
|
|
|
|
+/* PostgreSQL Access Control Extension related functions */
|
|
+DATA(insert OID = 3410 ( lo_get_security PGNSP PGUID 12 1 0 f f t f v 1 25 "26" _null_ _null_ _null_ lo_get_security - _null_ _null_ ));
|
|
+DATA(insert OID = 3411 ( lo_set_security PGNSP PGUID 12 1 0 f f t f v 2 16 "26 25" _null_ _null_ _null_ lo_set_security - _null_ _null_ ));
|
|
+
|
|
+/* SE-PostgreSQL related function */
|
|
+DATA(insert OID = 3450 ( sepgsql_getcon PGNSP PGUID 12 1 0 f f t f v 0 25 "" _null_ _null_ _null_ sepgsql_getcon - _null_ _null_ ));
|
|
+DATA(insert OID = 3451 ( sepgsql_getservcon PGNSP PGUID 12 1 0 f f t f v 0 25 "" _null_ _null_ _null_ sepgsql_getservcon - _null_ _null_ ));
|
|
+DATA(insert OID = 3452 ( sepgsql_get_user PGNSP PGUID 12 1 0 f f t f v 1 25 "25" _null_ _null_ _null_ sepgsql_get_user - _null_ _null_ ));
|
|
+DATA(insert OID = 3453 ( sepgsql_set_user PGNSP PGUID 12 1 0 f f t f v 2 25 "25 25" _null_ _null_ _null_ sepgsql_set_user - _null_ _null_ ));
|
|
+DATA(insert OID = 3454 ( sepgsql_get_role PGNSP PGUID 12 1 0 f f t f v 1 25 "25" _null_ _null_ _null_ sepgsql_get_role - _null_ _null_ ));
|
|
+DATA(insert OID = 3455 ( sepgsql_set_role PGNSP PGUID 12 1 0 f f t f v 2 25 "25 25" _null_ _null_ _null_ sepgsql_set_role - _null_ _null_ ));
|
|
+DATA(insert OID = 3456 ( sepgsql_get_type PGNSP PGUID 12 1 0 f f t f v 1 25 "25" _null_ _null_ _null_ sepgsql_get_type - _null_ _null_ ));
|
|
+DATA(insert OID = 3457 ( sepgsql_set_type PGNSP PGUID 12 1 0 f f t f v 2 25 "25 25" _null_ _null_ _null_ sepgsql_set_type - _null_ _null_ ));
|
|
+DATA(insert OID = 3458 ( sepgsql_get_range PGNSP PGUID 12 1 0 f f t f v 1 25 "25" _null_ _null_ _null_ sepgsql_get_range - _null_ _null_ ));
|
|
+DATA(insert OID = 3459 ( sepgsql_set_range PGNSP PGUID 12 1 0 f f t f v 2 25 "25 25" _null_ _null_ _null_ sepgsql_set_range - _null_ _null_ ));
|
|
+
|
|
/* enum related procs */
|
|
DATA(insert OID = 3504 ( anyenum_in PGNSP PGUID 12 1 0 f f t f i 1 3500 "2275" _null_ _null_ _null_ anyenum_in - _null_ _null_ ));
|
|
DESCR("I/O");
|
|
@@ -4460,7 +4476,8 @@ extern Oid ProcedureCreate(const char *p
|
|
Datum parameterNames,
|
|
Datum proconfig,
|
|
float4 procost,
|
|
- float4 prorows);
|
|
+ float4 prorows,
|
|
+ Oid proselabel);
|
|
|
|
extern bool function_parse_error_transpose(const char *prosrc);
|
|
|
|
diff -rpNU3 base/src/include/catalog/pg_security.h sepgsql-new/src/include/catalog/pg_security.h
|
|
--- base/src/include/catalog/pg_security.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/include/catalog/pg_security.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,58 @@
|
|
+/*
|
|
+ * src/include/catalog/pg_security.h
|
|
+ * Definition of the security label relation (pg_security)
|
|
+ *
|
|
+ * Copyright (c) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+ */
|
|
+#ifndef PG_SECURITY_H
|
|
+#define PG_SECURITY_H
|
|
+
|
|
+#include "access/htup.h"
|
|
+#include "utils/relcache.h"
|
|
+
|
|
+#define SecurityRelationId 3400
|
|
+
|
|
+CATALOG(pg_security,3400) BKI_SHARED_RELATION
|
|
+{
|
|
+ text seclabel; /* text representation of security label */
|
|
+} FormData_pg_security;
|
|
+
|
|
+/* ----------------
|
|
+ * Form_pg_security corresponds to a pointer to a tuple with
|
|
+ * the format of pg_security relation.
|
|
+ * ----------------
|
|
+ */
|
|
+typedef FormData_pg_security *Form_pg_security;
|
|
+
|
|
+/* ----------------
|
|
+ * compiler constants for pg_selinux
|
|
+ * ----------------
|
|
+ */
|
|
+#define Natts_pg_security 1
|
|
+#define Anum_pg_security_seclabel 1
|
|
+
|
|
+/*
|
|
+ * functions to translate between security label and identifier
|
|
+ */
|
|
+extern void
|
|
+securityPostBootstrapingMode(void);
|
|
+
|
|
+extern bool
|
|
+securityTupleDescHasSecLabel(Relation rel);
|
|
+
|
|
+extern Oid
|
|
+securityLookupSecurityId(const char *seclabel);
|
|
+
|
|
+extern char *
|
|
+securityLookupSecurityLabel(Oid secid);
|
|
+
|
|
+extern Oid
|
|
+securityTransSecLabelIn(char *seclabel);
|
|
+
|
|
+extern char *
|
|
+securityTransSecLabelOut(Oid secid);
|
|
+
|
|
+extern Datum
|
|
+securityHeapGetSecLabelSysattr(HeapTuple tuple);
|
|
+
|
|
+#endif /* PG_SELINUX_H */
|
|
diff -rpNU3 base/src/include/executor/executor.h sepgsql-new/src/include/executor/executor.h
|
|
--- base/src/include/executor/executor.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/executor/executor.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -117,7 +117,7 @@ extern TupleHashEntry FindTupleHashEntry
|
|
* prototypes from functions in execJunk.c
|
|
*/
|
|
extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid,
|
|
- TupleTableSlot *slot);
|
|
+ bool hasseclabel, TupleTableSlot *slot);
|
|
extern JunkFilter *ExecInitJunkFilterConversion(List *targetList,
|
|
TupleDesc cleanTupType,
|
|
TupleTableSlot *slot);
|
|
@@ -140,6 +140,7 @@ extern void ExecutorEnd(QueryDesc *query
|
|
extern void ExecutorRewind(QueryDesc *queryDesc);
|
|
extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
|
|
extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
|
|
+extern bool ExecContextForcesSecLabel(PlanState *planstate, bool *hasseclabel);
|
|
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
|
|
TupleTableSlot *slot, EState *estate);
|
|
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
|
@@ -199,8 +200,8 @@ extern void ExecInitScanTupleSlot(EState
|
|
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
|
|
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
|
|
TupleDesc tupType);
|
|
-extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
|
|
-extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid);
|
|
+extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid, bool hasseclabel);
|
|
+extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hasseclabel);
|
|
extern TupleDesc ExecTypeFromExprList(List *exprList);
|
|
extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);
|
|
|
|
diff -rpNU3 base/src/include/executor/tuptable.h sepgsql-new/src/include/executor/tuptable.h
|
|
--- base/src/include/executor/tuptable.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/executor/tuptable.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -118,6 +118,9 @@ typedef struct TupleTableSlot
|
|
MinimalTuple tts_mintuple; /* set if it's a minimal tuple, else NULL */
|
|
HeapTupleData tts_minhdr; /* workspace if it's a minimal tuple */
|
|
long tts_off; /* saved state for slot_deform_tuple */
|
|
+
|
|
+ /* temporary storages for writable system columns */
|
|
+ Oid tts_seclabel;
|
|
} TupleTableSlot;
|
|
|
|
/*
|
|
diff -rpNU3 base/src/include/fmgr.h sepgsql-new/src/include/fmgr.h
|
|
--- base/src/include/fmgr.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/fmgr.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -52,6 +52,15 @@ typedef struct FmgrInfo
|
|
void *fn_extra; /* extra space for use by handler */
|
|
MemoryContext fn_mcxt; /* memory context to store fn_extra in */
|
|
fmNodePtr fn_expr; /* expression parse tree for call, or NULL */
|
|
+
|
|
+#ifdef HAVE_SELINUX
|
|
+ /*
|
|
+ * Note: SELinux allows to switch the security context of client
|
|
+ * inside the specific functions labeled as trusted procedure.
|
|
+ */
|
|
+ PGFunction sepgsql_addr; /* address of original pointer */
|
|
+ char *sepgsql_label; /* temporary security context */
|
|
+#endif
|
|
} FmgrInfo;
|
|
|
|
/*
|
|
@@ -511,6 +520,7 @@ extern Oid get_call_expr_argtype(fmNodeP
|
|
*/
|
|
extern char *Dynamic_library_path;
|
|
|
|
+extern char *expand_dynamic_library_name(const char *name);
|
|
extern PGFunction load_external_function(char *filename, char *funcname,
|
|
bool signalNotFound, void **filehandle);
|
|
extern PGFunction lookup_external_function(void *filehandle, char *funcname);
|
|
diff -rpNU3 base/src/include/libpq/be-fsstubs.h sepgsql-new/src/include/libpq/be-fsstubs.h
|
|
--- base/src/include/libpq/be-fsstubs.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/libpq/be-fsstubs.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -36,6 +36,9 @@ extern Datum lo_tell(PG_FUNCTION_ARGS);
|
|
extern Datum lo_unlink(PG_FUNCTION_ARGS);
|
|
extern Datum lo_truncate(PG_FUNCTION_ARGS);
|
|
|
|
+extern Datum lo_get_security(PG_FUNCTION_ARGS);
|
|
+extern Datum lo_set_security(PG_FUNCTION_ARGS);
|
|
+
|
|
/*
|
|
* These are not fmgr-callable, but are available to C code.
|
|
* Probably these should have had the underscore-free names,
|
|
diff -rpNU3 base/src/include/nodes/parsenodes.h sepgsql-new/src/include/nodes/parsenodes.h
|
|
--- base/src/include/nodes/parsenodes.h 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql-new/src/include/nodes/parsenodes.h 2009-03-15 17:38:39.000000000 +0900
|
|
@@ -14,6 +14,7 @@
|
|
#ifndef PARSENODES_H
|
|
#define PARSENODES_H
|
|
|
|
+#include "nodes/bitmapset.h"
|
|
#include "nodes/primnodes.h"
|
|
#include "nodes/value.h"
|
|
|
|
@@ -65,10 +66,11 @@ typedef uint32 AclMode; /* a bitmask o
|
|
#define ACL_CREATE (1<<9) /* for namespaces and databases */
|
|
#define ACL_CREATE_TEMP (1<<10) /* for databases */
|
|
#define ACL_CONNECT (1<<11) /* for databases */
|
|
-#define N_ACL_RIGHTS 12 /* 1 plus the last 1<<x */
|
|
+/* Currently, ACL_SELECT_FOR_UPDATE is integrated into ACL_UPDATE */
|
|
+#define ACL_SELECT_FOR_UPDATE (1<<12)
|
|
+#define N_ACL_RIGHTS 13 /* 1 plus the last 1<<x */
|
|
#define ACL_NO_RIGHTS 0
|
|
-/* Currently, SELECT ... FOR UPDATE/FOR SHARE requires UPDATE privileges */
|
|
-#define ACL_SELECT_FOR_UPDATE ACL_UPDATE
|
|
+#define ACL_ALL_RIGHTS ((1<<N_ACL_RIGHTS) - 1)
|
|
|
|
|
|
/*****************************************************************************
|
|
@@ -391,6 +393,7 @@ typedef struct ColumnDef
|
|
Node *raw_default; /* default value (untransformed parse tree) */
|
|
char *cooked_default; /* nodeToString representation */
|
|
List *constraints; /* other constraints on column */
|
|
+ Node *secLabel; /* explicitly specified security label */
|
|
} ColumnDef;
|
|
|
|
/*
|
|
@@ -602,6 +605,8 @@ typedef struct RangeTblEntry
|
|
bool inFromCl; /* present in FROM clause? */
|
|
AclMode requiredPerms; /* bitmask of required access permissions */
|
|
Oid checkAsUser; /* if valid, check access as this role */
|
|
+ Bitmapset *selectedCols; /* columns needing SELECT permission */
|
|
+ Bitmapset *modifiedCols; /* columns needing INSERT/UPDATE permission */
|
|
} RangeTblEntry;
|
|
|
|
/*
|
|
@@ -917,7 +922,8 @@ typedef enum AlterTableType
|
|
AT_EnableReplicaRule, /* ENABLE REPLICA RULE name */
|
|
AT_DisableRule, /* DISABLE RULE name */
|
|
AT_AddInherit, /* INHERIT parent */
|
|
- AT_DropInherit /* NO INHERIT parent */
|
|
+ AT_DropInherit, /* NO INHERIT parent */
|
|
+ AT_SetSecurityLabel, /* SECURITY_LABEL <new label> */
|
|
} AlterTableType;
|
|
|
|
typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
|
|
@@ -1108,6 +1114,7 @@ typedef struct CreateStmt
|
|
List *options; /* options from WITH clause */
|
|
OnCommitAction oncommit; /* what do we do at COMMIT? */
|
|
char *tablespacename; /* table space to use, or NULL */
|
|
+ Node *secLabel; /* explicitly specified security label */
|
|
} CreateStmt;
|
|
|
|
/* ----------
|
|
diff -rpNU3 base/src/include/nodes/plannodes.h sepgsql-new/src/include/nodes/plannodes.h
|
|
--- base/src/include/nodes/plannodes.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/nodes/plannodes.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -16,6 +16,7 @@
|
|
|
|
#include "access/sdir.h"
|
|
#include "nodes/bitmapset.h"
|
|
+#include "nodes/parsenodes.h"
|
|
#include "nodes/primnodes.h"
|
|
|
|
|
|
@@ -73,6 +74,8 @@ typedef struct PlannedStmt
|
|
List *relationOids; /* OIDs of relations the plan depends on */
|
|
|
|
int nParamExec; /* number of PARAM_EXEC Params used */
|
|
+
|
|
+ List *selinuxItems; /* list of SelinuxEvalItem */
|
|
} PlannedStmt;
|
|
|
|
/* macro for fetching the Plan associated with a SubPlan node */
|
|
@@ -216,6 +219,8 @@ typedef struct Scan
|
|
{
|
|
Plan plan;
|
|
Index scanrelid; /* relid is index into the range table */
|
|
+
|
|
+ AclMode requiredPerms; /* permissions in row-level access controls */
|
|
} Scan;
|
|
|
|
/* ----------------
|
|
diff -rpNU3 base/src/include/nodes/relation.h sepgsql-new/src/include/nodes/relation.h
|
|
--- base/src/include/nodes/relation.h 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql-new/src/include/nodes/relation.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -366,6 +366,15 @@ typedef struct RelOptInfo
|
|
* list just to avoid recomputing the best inner indexscan repeatedly for
|
|
* similar outer relations. See comments for InnerIndexscanInfo.
|
|
*/
|
|
+
|
|
+ /*
|
|
+ * Row-level access controls (both DAC and MAC) requires tuplePerms
|
|
+ * holds proper required permissions for each fetched tuples. It is
|
|
+ * similar to conditional scan on relations so, optimizar have to
|
|
+ * check whether tuplePerms is zero, or not. The tuplePerms with zero
|
|
+ * means we have no row-level security in this relation.
|
|
+ */
|
|
+ AclMode requiredPerms;
|
|
} RelOptInfo;
|
|
|
|
/*
|
|
diff -rpNU3 base/src/include/parser/parse_node.h sepgsql-new/src/include/parser/parse_node.h
|
|
--- base/src/include/parser/parse_node.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/parser/parse_node.h 2009-03-13 13:09:47.000000000 +0900
|
|
@@ -64,6 +64,7 @@ typedef struct ParseState
|
|
struct ParseState *parentParseState; /* stack link */
|
|
const char *p_sourcetext; /* source text, or NULL if not available */
|
|
List *p_rtable; /* range table so far */
|
|
+ List *p_joinexprs; /* JoinExprs for RTE_JOIN p_rtable entries */
|
|
List *p_joinlist; /* join items so far (will become FromExpr
|
|
* node's fromlist) */
|
|
List *p_relnamespace; /* current namespace for relations */
|
|
diff -rpNU3 base/src/include/parser/parse_relation.h sepgsql-new/src/include/parser/parse_relation.h
|
|
--- base/src/include/parser/parse_relation.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/parser/parse_relation.h 2009-03-13 13:09:47.000000000 +0900
|
|
@@ -40,6 +40,8 @@ extern Node *qualifiedNameToVar(ParseSta
|
|
char *colname,
|
|
bool implicitRTEOK,
|
|
int location);
|
|
+extern void markVarForSelectPriv(ParseState *pstate, Var *var,
|
|
+ RangeTblEntry *rte);
|
|
extern RangeTblEntry *addRangeTableEntry(ParseState *pstate,
|
|
RangeVar *relation,
|
|
Alias *alias,
|
|
diff -rpNU3 base/src/include/pg_config.h.in sepgsql-new/src/include/pg_config.h.in
|
|
--- base/src/include/pg_config.h.in 2008-01-28 16:06:37.000000000 +0900
|
|
+++ sepgsql-new/src/include/pg_config.h.in 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -366,6 +366,9 @@
|
|
/* Define to 1 if you have the <security/pam_appl.h> header file. */
|
|
#undef HAVE_SECURITY_PAM_APPL_H
|
|
|
|
+/* Define to 1 if you enable SELinux support */
|
|
+#undef HAVE_SELINUX
|
|
+
|
|
/* Define to 1 if you have the `setproctitle' function. */
|
|
#undef HAVE_SETPROCTITLE
|
|
|
|
diff -rpNU3 base/src/include/security/rowlevel.h sepgsql-new/src/include/security/rowlevel.h
|
|
--- base/src/include/security/rowlevel.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/include/security/rowlevel.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,34 @@
|
|
+/*
|
|
+ * src/include/security/rowlevel.h
|
|
+ * Definition of the facility of row-level access controls
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#ifndef ROWLEVEL_H
|
|
+#define ROWLEVEL_H
|
|
+
|
|
+#include "access/htup.h"
|
|
+#include "executor/tuptable.h"
|
|
+#include "nodes/plannodes.h"
|
|
+#include "utils/relcache.h"
|
|
+
|
|
+extern bool
|
|
+rowlvBehaviorSwitchTo(bool new_abort);
|
|
+
|
|
+extern bool
|
|
+rowlvExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort);
|
|
+
|
|
+extern bool
|
|
+rowlvHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal);
|
|
+
|
|
+extern bool
|
|
+rowlvHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup, bool internal);
|
|
+
|
|
+extern bool
|
|
+rowlvHeapTupleDelete(Relation rel, ItemPointer otid, bool internal);
|
|
+
|
|
+extern bool
|
|
+rowlvCopyToTuple(Relation rel, HeapTuple tuple);
|
|
+
|
|
+#endif /* PG_SELINUX_H */
|
|
diff -rpNU3 base/src/include/security/sepgsql.h sepgsql-new/src/include/security/sepgsql.h
|
|
--- base/src/include/security/sepgsql.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql-new/src/include/security/sepgsql.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -0,0 +1,397 @@
|
|
+/*
|
|
+ * src/include/utils/sepgsql.h
|
|
+ * Headers of SE-PostgreSQL
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+#ifndef SEPGSQL_H
|
|
+#define SEPGSQL_H
|
|
+
|
|
+#include "access/htup.h"
|
|
+#include "commands/trigger.h"
|
|
+#include "executor/execdesc.h"
|
|
+#include "fmgr.h"
|
|
+#include "nodes/parsenodes.h"
|
|
+#include "storage/large_object.h"
|
|
+#include "utils/relcache.h"
|
|
+
|
|
+typedef Oid sepgsql_sid_t;
|
|
+
|
|
+#ifdef HAVE_SELINUX
|
|
+
|
|
+#include <selinux/selinux.h>
|
|
+
|
|
+/* GUC parameter to turn on/off SE-PostgreSQL */
|
|
+extern bool sepostgresql_is_enabled;
|
|
+
|
|
+/* GUC parameter to turn on/off Row-level controls */
|
|
+extern bool sepostgresql_row_level;
|
|
+
|
|
+/* Objject classes and permissions internally used */
|
|
+enum SepgsqlClasses
|
|
+{
|
|
+ SEPG_CLASS_PROCESS = 0,
|
|
+ SEPG_CLASS_FILE,
|
|
+ SEPG_CLASS_DIR,
|
|
+ SEPG_CLASS_LNK_FILE,
|
|
+ SEPG_CLASS_CHR_FILE,
|
|
+ SEPG_CLASS_BLK_FILE,
|
|
+ SEPG_CLASS_SOCK_FILE,
|
|
+ SEPG_CLASS_FIFO_FILE,
|
|
+ SEPG_CLASS_DB_DATABASE,
|
|
+ SEPG_CLASS_DB_TABLE,
|
|
+ SEPG_CLASS_DB_PROCEDURE,
|
|
+ SEPG_CLASS_DB_COLUMN,
|
|
+ SEPG_CLASS_DB_TUPLE,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_CLASS_MAX,
|
|
+};
|
|
+
|
|
+#define SEPG_PROCESS__TRANSITION (1<<0)
|
|
+
|
|
+#define SEPG_FILE__READ (1<<0)
|
|
+#define SEPG_FILE__WRITE (1<<1)
|
|
+
|
|
+#define SEPG_DIR__READ (SEPG_FILE__READ)
|
|
+#define SEPG_DIR__WRITE (SEPG_FILE__WRITE)
|
|
+
|
|
+#define SEPG_LNK_FILE__READ (SEPG_FILE__READ)
|
|
+#define SEPG_LNK_FILE__WRITE (SEPG_FILE__WRITE)
|
|
+
|
|
+#define SEPG_CHR_FILE__READ (SEPG_FILE__READ)
|
|
+#define SEPG_CHR_FILE__WRITE (SEPG_FILE__WRITE)
|
|
+
|
|
+#define SEPG_BLK_FILE__READ (SEPG_FILE__READ)
|
|
+#define SEPG_BLK_FILE__WRITE (SEPG_FILE__WRITE)
|
|
+
|
|
+#define SEPG_SOCK_FILE__READ (SEPG_FILE__READ)
|
|
+#define SEPG_SOCK_FILE__WRITE (SEPG_FILE__WRITE)
|
|
+
|
|
+#define SEPG_FIFO_FILE__READ (SEPG_FILE__READ)
|
|
+#define SEPG_FIFO_FILE__WRITE (SEPG_FILE__WRITE)
|
|
+
|
|
+#define SEPG_DB_DATABASE__CREATE (1<<0)
|
|
+#define SEPG_DB_DATABASE__DROP (1<<1)
|
|
+#define SEPG_DB_DATABASE__GETATTR (1<<2)
|
|
+#define SEPG_DB_DATABASE__SETATTR (1<<3)
|
|
+#define SEPG_DB_DATABASE__RELABELFROM (1<<4)
|
|
+#define SEPG_DB_DATABASE__RELABELTO (1<<5)
|
|
+#define SEPG_DB_DATABASE__ACCESS (1<<6)
|
|
+#define SEPG_DB_DATABASE__INSTALL_MODULE (1<<7)
|
|
+#define SEPG_DB_DATABASE__LOAD_MODULE (1<<8)
|
|
+#define SEPG_DB_DATABASE__SUPERUSER (1<<9)
|
|
+
|
|
+#define SEPG_DB_TABLE__CREATE (SEPG_DB_DATABASE__CREATE)
|
|
+#define SEPG_DB_TABLE__DROP (SEPG_DB_DATABASE__DROP)
|
|
+#define SEPG_DB_TABLE__GETATTR (SEPG_DB_DATABASE__GETATTR)
|
|
+#define SEPG_DB_TABLE__SETATTR (SEPG_DB_DATABASE__SETATTR)
|
|
+#define SEPG_DB_TABLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
|
|
+#define SEPG_DB_TABLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
|
|
+#define SEPG_DB_TABLE__SELECT (1<<6)
|
|
+#define SEPG_DB_TABLE__UPDATE (1<<7)
|
|
+#define SEPG_DB_TABLE__INSERT (1<<8)
|
|
+#define SEPG_DB_TABLE__DELETE (1<<9)
|
|
+#define SEPG_DB_TABLE__LOCK (1<<10)
|
|
+
|
|
+#define SEPG_DB_PROCEDURE__CREATE (SEPG_DB_DATABASE__CREATE)
|
|
+#define SEPG_DB_PROCEDURE__DROP (SEPG_DB_DATABASE__DROP)
|
|
+#define SEPG_DB_PROCEDURE__GETATTR (SEPG_DB_DATABASE__GETATTR)
|
|
+#define SEPG_DB_PROCEDURE__SETATTR (SEPG_DB_DATABASE__SETATTR)
|
|
+#define SEPG_DB_PROCEDURE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
|
|
+#define SEPG_DB_PROCEDURE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
|
|
+#define SEPG_DB_PROCEDURE__EXECUTE (1<<6)
|
|
+#define SEPG_DB_PROCEDURE__ENTRYPOINT (1<<7)
|
|
+#define SEPG_DB_PROCEDURE__INSTALL (1<<8)
|
|
+
|
|
+#define SEPG_DB_COLUMN__CREATE (SEPG_DB_DATABASE__CREATE)
|
|
+#define SEPG_DB_COLUMN__DROP (SEPG_DB_DATABASE__DROP)
|
|
+#define SEPG_DB_COLUMN__GETATTR (SEPG_DB_DATABASE__GETATTR)
|
|
+#define SEPG_DB_COLUMN__SETATTR (SEPG_DB_DATABASE__SETATTR)
|
|
+#define SEPG_DB_COLUMN__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
|
|
+#define SEPG_DB_COLUMN__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
|
|
+#define SEPG_DB_COLUMN__SELECT (1<<6)
|
|
+#define SEPG_DB_COLUMN__UPDATE (1<<7)
|
|
+#define SEPG_DB_COLUMN__INSERT (1<<8)
|
|
+
|
|
+#define SEPG_DB_TUPLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
|
|
+#define SEPG_DB_TUPLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
|
|
+#define SEPG_DB_TUPLE__SELECT (SEPG_DB_DATABASE__GETATTR)
|
|
+#define SEPG_DB_TUPLE__UPDATE (SEPG_DB_DATABASE__SETATTR)
|
|
+#define SEPG_DB_TUPLE__INSERT (SEPG_DB_DATABASE__CREATE)
|
|
+#define SEPG_DB_TUPLE__DELETE (SEPG_DB_DATABASE__DROP)
|
|
+
|
|
+#define SEPG_DB_BLOB__CREATE (SEPG_DB_DATABASE__CREATE)
|
|
+#define SEPG_DB_BLOB__DROP (SEPG_DB_DATABASE__DROP)
|
|
+#define SEPG_DB_BLOB__GETATTR (SEPG_DB_DATABASE__GETATTR)
|
|
+#define SEPG_DB_BLOB__SETATTR (SEPG_DB_DATABASE__SETATTR)
|
|
+#define SEPG_DB_BLOB__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
|
|
+#define SEPG_DB_BLOB__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
|
|
+#define SEPG_DB_BLOB__READ (1<<6)
|
|
+#define SEPG_DB_BLOB__WRITE (1<<7)
|
|
+#define SEPG_DB_BLOB__IMPORT (1<<8)
|
|
+#define SEPG_DB_BLOB__EXPORT (1<<9)
|
|
+
|
|
+/*
|
|
+ * avc.c : userspace access vector cache
|
|
+ */
|
|
+extern Size sepgsqlShmemSize(void);
|
|
+
|
|
+extern void sepgsqlAvcInit(void);
|
|
+
|
|
+extern pid_t sepgsqlStartupWorkerProcess(void);
|
|
+
|
|
+extern void sepgsqlAvcSwitchClient(void);
|
|
+
|
|
+extern bool
|
|
+sepgsqlClientHasPerms(sepgsql_sid_t tcontext,
|
|
+ security_class_t tclass,
|
|
+ access_vector_t required,
|
|
+ const char *audit_name, bool abort);
|
|
+extern sepgsql_sid_t
|
|
+sepgsqlClientCreate(sepgsql_sid_t tcontext,
|
|
+ security_class_t tclass);
|
|
+
|
|
+extern security_context_t
|
|
+sepgsqlClientCreateLabel(sepgsql_sid_t tcontext,
|
|
+ security_class_t tclass);
|
|
+
|
|
+extern bool
|
|
+sepgsqlComputePerms(security_context_t scontext,
|
|
+ security_context_t tcontext,
|
|
+ security_class_t tclass,
|
|
+ access_vector_t required,
|
|
+ const char *audit_name, bool abort);
|
|
+
|
|
+extern security_context_t
|
|
+sepgsqlComputeCreate(security_context_t scontext,
|
|
+ security_context_t tcontext,
|
|
+ security_class_t tclass);
|
|
+
|
|
+/*
|
|
+ * checker.c : pick up all the appeared objects and apply checks
|
|
+ */
|
|
+extern void
|
|
+sepgsqlCheckRTEPerms(RangeTblEntry *rte);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckCopyTable(Relation rel, List *attnumlist, bool is_from);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckSelectInto(Oid relaionId);
|
|
+
|
|
+extern bool
|
|
+sepgsqlExecScan(Relation rel, HeapTuple tuple, AclMode required, bool abort);
|
|
+
|
|
+extern bool
|
|
+sepgsqlHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal);
|
|
+
|
|
+extern bool
|
|
+sepgsqlHeapTupleUpdate(Relation rel, HeapTuple oldtup, HeapTuple newtup, bool internal);
|
|
+
|
|
+extern bool
|
|
+sepgsqlHeapTupleDelete(Relation rel, HeapTuple oldtup, bool internal);
|
|
+
|
|
+/*
|
|
+ * core.c : core facilities
|
|
+ */
|
|
+extern security_context_t
|
|
+sepgsqlGetServerLabel(void);
|
|
+
|
|
+extern security_context_t
|
|
+sepgsqlGetClientLabel(void);
|
|
+
|
|
+extern security_context_t
|
|
+sepgsqlGetUnlabeledLabel(void);
|
|
+
|
|
+extern security_context_t
|
|
+sepgsqlGetDatabaseLabel(void);
|
|
+
|
|
+extern sepgsql_sid_t
|
|
+sepgsqlGetDatabaseSid(void);
|
|
+
|
|
+extern security_context_t
|
|
+sepgsqlSwitchClient(security_context_t new_client);
|
|
+
|
|
+extern bool
|
|
+sepgsqlIsEnabled(void);
|
|
+
|
|
+extern void
|
|
+sepgsqlInitialize(void);
|
|
+
|
|
+/*
|
|
+ * hooks.c : security hooks
|
|
+ */
|
|
+extern bool
|
|
+sepgsqlCheckDatabaseAccess(Oid db_oid);
|
|
+
|
|
+extern bool
|
|
+sepgsqlCheckDatabaseSuperuser(void);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckDatabaseInstallModule(const char *filename);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckDatabaseLoadModule(const char *filename);
|
|
+
|
|
+extern bool
|
|
+sepgsqlCheckTableLock(Oid table_oid);
|
|
+
|
|
+extern bool
|
|
+sepgsqlCheckTableTruncate(Relation rel);
|
|
+
|
|
+extern bool
|
|
+sepgsqlCheckProcedureExecute(Oid proc_oid);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckProcedureEntrypoint(FmgrInfo *finfo, HeapTuple protup);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckProcedureInstall(Relation rel, HeapTuple newtup, HeapTuple oldtup);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckBlobDrop(HeapTuple lotup);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckBlobRead(LargeObjectDesc *lobj);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckBlobWrite(LargeObjectDesc *lobj);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckBlobGetattr(HeapTuple tuple);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckBlobSetattr(HeapTuple tuple);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckBlobExport(LargeObjectDesc *lobj, int fdesc, const char *filename);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckBlobImport(LargeObjectDesc *lobj, int fdesc, const char *filename);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckBlobRelabel(HeapTuple oldtup, HeapTuple newtup);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckFileRead(int fdesc, const char *filename);
|
|
+
|
|
+extern void
|
|
+sepgsqlCheckFileWrite(int fdesc, const char *filename);
|
|
+
|
|
+extern bool
|
|
+sepgsqlAllowFunctionInlined(HeapTuple protup);
|
|
+
|
|
+/*
|
|
+ * label.c : security label management
|
|
+ */
|
|
+extern bool
|
|
+sepgsqlTupleDescHasSecLabel(Relation rel);
|
|
+
|
|
+extern void
|
|
+sepgsqlSetDefaultSecLabel(Relation rel, HeapTuple tuple);
|
|
+
|
|
+extern char *
|
|
+sepgsqlMetaSecurityLabel(void);
|
|
+
|
|
+extern sepgsql_sid_t
|
|
+sepgsqlInputGivenSecLabel(DefElem *defel);
|
|
+
|
|
+extern List *
|
|
+sepgsqlInputGivenSecLabelRelation(CreateStmt *stmt);
|
|
+
|
|
+extern security_context_t
|
|
+sepgsqlSecurityLabelTransIn(security_context_t label);
|
|
+
|
|
+extern security_context_t
|
|
+sepgsqlSecurityLabelTransOut(security_context_t label);
|
|
+
|
|
+extern bool
|
|
+sepgsqlCheckValidSecurityLabel(security_context_t label);
|
|
+
|
|
+/*
|
|
+ * perms.c : SE-PostgreSQL permission checks
|
|
+ */
|
|
+extern const char *
|
|
+sepgsqlAuditName(Oid relid, HeapTuple tuple);
|
|
+
|
|
+extern security_class_t
|
|
+sepgsqlFileObjectClass(int fdesc);
|
|
+
|
|
+extern security_class_t
|
|
+sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple);
|
|
+
|
|
+extern security_class_t
|
|
+sepgsqlTransToExternalClass(security_class_t tclass_in);
|
|
+
|
|
+extern void
|
|
+sepgsqlTransToInternalPerms(security_class_t tclass_ex, struct av_decision *avd);
|
|
+
|
|
+extern const char *
|
|
+sepgsqlGetClassString(security_class_t tclass);
|
|
+
|
|
+extern const char *
|
|
+sepgsqlGetPermissionString(security_class_t tclass, access_vector_t av);
|
|
+
|
|
+extern bool
|
|
+sepgsqlCheckObjectPerms(Relation rel, HeapTuple tuple,
|
|
+ access_vector_t required, bool abort);
|
|
+
|
|
+#else /* HAVE_SELINUX */
|
|
+
|
|
+// avc.c
|
|
+#define sepgsqlShmemSize() (0)
|
|
+#define sepgsqlStartupWorkerProcess() (0)
|
|
+// checker.c
|
|
+#define sepgsqlCheckRTEPerms(a) do {} while(0)
|
|
+#define sepgsqlCheckSelectInto(a) do {} while(0)
|
|
+#define sepgsqlExecScan(a,b,c,d) (true)
|
|
+#define sepgsqlHeapTupleInsert(a,b,c) (true)
|
|
+#define sepgsqlHeapTupleUpdate(a,b,c,d) (true)
|
|
+#define sepgsqlHeapTupleDelete(a,b,c) (true)
|
|
+// core.c
|
|
+#define sepgsqlIsEnabled() (false)
|
|
+#define sepgsqlInitialize() do {} while(0)
|
|
+// hooks.c
|
|
+#define sepgsqlCheckDatabaseAccess(a) (true)
|
|
+#define sepgsqlCheckDatabaseSuperuser() (true)
|
|
+#define sepgsqlCheckDatabaseInstallModule(a) do {} while(0)
|
|
+#define sepgsqlCheckDatabaseLoadModule(a) do {} while(0)
|
|
+#define sepgsqlCheckTableLock(a) (true)
|
|
+#define sepgsqlCheckTableTruncate(a) (true)
|
|
+#define sepgsqlCheckProcedureExecute(a) (true)
|
|
+#define sepgsqlCheckProcedureEntrypoint(a,b) do {} while(0)
|
|
+#define sepgsqlCheckBlobDrop(a) do {} while(0)
|
|
+#define sepgsqlCheckBlobRead(a) do {} while(0)
|
|
+#define sepgsqlCheckBlobWrite(a) do {} while(0)
|
|
+#define sepgsqlCheckBlobGetattr(a) do {} while(0)
|
|
+#define sepgsqlCheckBlobSetattr(a) do {} while(0)
|
|
+#define sepgsqlCheckBlobExport(a,b,c) do {} while(0)
|
|
+#define sepgsqlCheckBlobImport(a,b,c) do {} while(0)
|
|
+#define sepgsqlCheckBlobRelabel(a,b) do {} while(0)
|
|
+#define sepgsqlCheckFileRead(a,b) do {} while(0)
|
|
+#define sepgsqlCheckFileWrite(a,b) do {} while(0)
|
|
+#define sepgsqlAllowFunctionInlined(a) (true)
|
|
+// label.c
|
|
+#define sepgsqlTupleDescHasSecLabel(a) (false)
|
|
+#define sepgsqlMetaSecurityLabel() (NULL)
|
|
+#define sepgsqlInputGivenSecLabel(a) (InvalidOid)
|
|
+#define sepgsqlInputGivenSecLabelRelation(a) (NIL)
|
|
+#define sepgsqlSecurityLabelTransIn(a) (a)
|
|
+#define sepgsqlSecurityLabelTransOut(a) (a)
|
|
+#define sepgsqlCheckValidSecurityLabel(a) (false)
|
|
+
|
|
+#endif /* HAVE_SELINUX */
|
|
+
|
|
+extern Datum sepgsql_getcon(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_getservcon(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_get_user(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_get_role(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_get_type(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_get_range(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_set_user(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_set_role(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_set_type(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_set_range(PG_FUNCTION_ARGS);
|
|
+
|
|
+#endif /* SEPGSQL_H */
|
|
diff -rpNU3 base/src/include/storage/fd.h sepgsql-new/src/include/storage/fd.h
|
|
--- base/src/include/storage/fd.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/storage/fd.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -67,6 +67,7 @@ extern int FileWrite(File file, char *bu
|
|
extern int FileSync(File file);
|
|
extern long FileSeek(File file, long offset, int whence);
|
|
extern int FileTruncate(File file, long offset);
|
|
+extern int FileRawDescriptor(File file);
|
|
|
|
/* Operations that allow use of regular stdio --- USE WITH CAUTION */
|
|
extern FILE *AllocateFile(const char *name, const char *mode);
|
|
diff -rpNU3 base/src/include/storage/large_object.h sepgsql-new/src/include/storage/large_object.h
|
|
--- base/src/include/storage/large_object.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/storage/large_object.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -44,6 +44,7 @@ typedef struct LargeObjectDesc
|
|
#define IFS_RDLOCK (1 << 0)
|
|
#define IFS_WRLOCK (1 << 1)
|
|
|
|
+ Oid secid; /* security id of the largeobject */
|
|
} LargeObjectDesc;
|
|
|
|
|
|
@@ -79,5 +80,7 @@ extern int inv_tell(LargeObjectDesc *obj
|
|
extern int inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes);
|
|
extern int inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes);
|
|
extern void inv_truncate(LargeObjectDesc *obj_desc, int len);
|
|
+extern Oid inv_get_security(Oid loid);
|
|
+extern void inv_set_security(Oid loid, Oid secid);
|
|
|
|
#endif /* LARGE_OBJECT_H */
|
|
diff -rpNU3 base/src/include/storage/lwlock.h sepgsql-new/src/include/storage/lwlock.h
|
|
--- base/src/include/storage/lwlock.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/storage/lwlock.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -63,6 +63,7 @@ typedef enum LWLockId
|
|
AutovacuumLock,
|
|
AutovacuumScheduleLock,
|
|
SyncScanLock,
|
|
+ SepgsqlAvcLock,
|
|
/* Individual lock IDs end here */
|
|
FirstBufMappingLock,
|
|
FirstLockMgrLock = FirstBufMappingLock + NUM_BUFFER_PARTITIONS,
|
|
diff -rpNU3 base/src/include/utils/builtins.h sepgsql-new/src/include/utils/builtins.h
|
|
--- base/src/include/utils/builtins.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/utils/builtins.h 2009-03-13 13:09:47.000000000 +0900
|
|
@@ -617,6 +617,14 @@ extern Datum varchartypmodout(PG_FUNCTIO
|
|
extern Datum varchar(PG_FUNCTION_ARGS);
|
|
|
|
/* varlena.c */
|
|
+extern text *cstring_to_text(const char *s);
|
|
+extern text *cstring_to_text_with_len(const char *s, int len);
|
|
+extern char *text_to_cstring(const text *t);
|
|
+extern void text_to_cstring_buffer(const text *src, char *dst, size_t dst_len);
|
|
+
|
|
+#define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s))
|
|
+#define TextDatumGetCString(d) text_to_cstring((text *) DatumGetPointer(d))
|
|
+
|
|
extern Datum textin(PG_FUNCTION_ARGS);
|
|
extern Datum textout(PG_FUNCTION_ARGS);
|
|
extern Datum textrecv(PG_FUNCTION_ARGS);
|
|
diff -rpNU3 base/src/include/utils/catcache.h sepgsql-new/src/include/utils/catcache.h
|
|
--- base/src/include/utils/catcache.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/utils/catcache.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -172,6 +172,7 @@ extern HeapTuple SearchCatCache(CatCache
|
|
Datum v1, Datum v2,
|
|
Datum v3, Datum v4);
|
|
extern void ReleaseCatCache(HeapTuple tuple);
|
|
+extern void InsertCatCache(CatCache *cache, HeapTuple tuple);
|
|
|
|
extern CatCList *SearchCatCacheList(CatCache *cache, int nkeys,
|
|
Datum v1, Datum v2,
|
|
diff -rpNU3 base/src/include/utils/errcodes.h sepgsql-new/src/include/utils/errcodes.h
|
|
--- base/src/include/utils/errcodes.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/utils/errcodes.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -339,6 +339,11 @@
|
|
#define ERRCODE_NO_DATA_FOUND MAKE_SQLSTATE('P','0', '0','0','2')
|
|
#define ERRCODE_TOO_MANY_ROWS MAKE_SQLSTATE('P','0', '0','0','3')
|
|
|
|
+/* Class SE - SE-PostgreSQL Error */
|
|
+#define ERRCODE_SELINUX_ERROR MAKE_SQLSTATE('S','E', '0','0','1')
|
|
+#define ERRCODE_SELINUX_AUDIT MAKE_SQLSTATE('S','E', '0','0','2')
|
|
+#define ERRCODE_SELINUX_INFO MAKE_SQLSTATE('S','E', '0','0','3')
|
|
+
|
|
/* Class XX - Internal Error (PostgreSQL-specific error class) */
|
|
/* (this is for "can't-happen" conditions and software bugs) */
|
|
#define ERRCODE_INTERNAL_ERROR MAKE_SQLSTATE('X','X', '0','0','0')
|
|
diff -rpNU3 base/src/include/utils/syscache.h sepgsql-new/src/include/utils/syscache.h
|
|
--- base/src/include/utils/syscache.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql-new/src/include/utils/syscache.h 2009-03-13 18:14:33.000000000 +0900
|
|
@@ -64,18 +64,20 @@
|
|
#define RELNAMENSP 33
|
|
#define RELOID 34
|
|
#define RULERELNAME 35
|
|
-#define STATRELATT 36
|
|
-#define TSCONFIGMAP 37
|
|
-#define TSCONFIGNAMENSP 38
|
|
-#define TSCONFIGOID 39
|
|
-#define TSDICTNAMENSP 40
|
|
-#define TSDICTOID 41
|
|
-#define TSPARSERNAMENSP 42
|
|
-#define TSPARSEROID 43
|
|
-#define TSTEMPLATENAMENSP 44
|
|
-#define TSTEMPLATEOID 45
|
|
-#define TYPENAMENSP 46
|
|
-#define TYPEOID 47
|
|
+#define SECURITYLABEL 36
|
|
+#define SECURITYOID 37
|
|
+#define STATRELATT 38
|
|
+#define TSCONFIGMAP 39
|
|
+#define TSCONFIGNAMENSP 40
|
|
+#define TSCONFIGOID 41
|
|
+#define TSDICTNAMENSP 42
|
|
+#define TSDICTOID 43
|
|
+#define TSPARSERNAMENSP 44
|
|
+#define TSPARSEROID 45
|
|
+#define TSTEMPLATENAMENSP 46
|
|
+#define TSTEMPLATEOID 47
|
|
+#define TYPENAMENSP 48
|
|
+#define TYPEOID 49
|
|
|
|
extern void InitCatalogCache(void);
|
|
extern void InitCatalogCachePhase2(void);
|
|
@@ -84,6 +86,8 @@ extern HeapTuple SearchSysCache(int cach
|
|
Datum key1, Datum key2, Datum key3, Datum key4);
|
|
extern void ReleaseSysCache(HeapTuple tuple);
|
|
|
|
+extern void InsertSysCache(Oid relid, HeapTuple tuple);
|
|
+
|
|
/* convenience routines */
|
|
extern HeapTuple SearchSysCacheCopy(int cacheId,
|
|
Datum key1, Datum key2, Datum key3, Datum key4);
|