@@ -264,6 +264,43 @@ int avc_has_perm_noaudit(security_id_t ssid,
struct avc_entry_ref *aeref, struct av_decision *avd);
/**
+ * avc_has_perm_noaudit_flags - Check permissions but perform no auditing,
+ * return avd flags.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @aeref: AVC entry reference
+ * @avd: access vector decisions
+ * @flags: returned avd flags. Currently two flags are supported:
+ * SELINUX_AVD_FLAGS_UNDEFINED This is typically set when the
+ * source or target context is not valid in policy, or the
+ * avc is in permissive mode, or the returned entry could not be
+ * inserted into the avc cache.
+ * SELINUX_AVD_FLAGS_PERMISSIVE, which indicates the decision is
+ * computed on a policy defined permissive domain.
+ *
+ * Check the AVC to determine whether the @requested permissions are granted
+ * for the SID pair (@ssid, @tsid), interpreting the permissions
+ * based on @tclass, and call the security server on a cache miss to obtain
+ * a new decision and add it to the cache. Update @aeref to refer to an AVC
+ * entry with the resulting decisions, and return a copy of the decisions
+ * in @avd. Return %0 if all @requested permissions are granted, -%1 with
+ * @errno set to %EACCES if any permissions are denied, or to another value
+ * upon other errors. This function is typically called by avc_has_perm(),
+ * but may also be called directly to separate permission checking from
+ * auditing, e.g. in cases where a lock must be held for the check but
+ * should be released for the auditing.
+ */
+int avc_has_perm_noaudit_flags(security_id_t ssid,
+ security_id_t tsid,
+ security_class_t tclass,
+ access_vector_t requested,
+ struct avc_entry_ref *aeref,
+ struct av_decision *avd,
+ unsigned int *flags);
+
+/**
* avc_has_perm - Check permissions and perform any appropriate auditing.
* @ssid: source security identifier
* @tsid: target security identifier
@@ -286,6 +323,37 @@ int avc_has_perm(security_id_t ssid, security_id_t tsid,
struct avc_entry_ref *aeref, void *auditdata);
/**
+ * avc_has_perm_flags - Check permissions, returning avd flags and perform any
+ * appropriate auditing.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @aeref: AVC entry reference
+ * @auditdata: auxiliary audit data
+ * @flags: returned avd flags. Currently two flags are supported:
+ * SELINUX_AVD_FLAGS_UNDEFINED This is typically caused when the
+ * source or target context is not valid in policy, or the
+ * avc is in permissive mode, or the returned entry could not be
+ * inserted into the avc cache.
+ * SELINUX_AVD_FLAGS_PERMISSIVE, which indicates the decision is
+ * computed on a policy defined permissive domain.
+ *
+ * Check the AVC to determine whether the @requested permissions are granted
+ * for the SID pair (@ssid, @tsid), interpreting the permissions
+ * based on @tclass, and call the security server on a cache miss to obtain
+ * a new decision and add it to the cache. Update @aeref to refer to an AVC
+ * entry with the resulting decisions. Audit the granting or denial of
+ * permissions in accordance with the policy. Return %0 if all @requested
+ * permissions are granted, -%1 with @errno set to %EACCES if any permissions
+ * are denied or to another value upon other errors.
+ */
+int avc_has_perm_flags(security_id_t ssid, security_id_t tsid,
+ security_class_t tclass, access_vector_t requested,
+ struct avc_entry_ref *aeref, void *auditdata,
+ unsigned int *flags);
+
+/**
* avc_audit - Audit the granting or denial of permissions.
* @ssid: source security identifier
* @tsid: target security identifier
@@ -136,6 +136,7 @@ struct av_decision {
/* Definitions of av_decision.flags */
#define SELINUX_AVD_FLAGS_PERMISSIVE 0x0001
+#define SELINUX_AVD_FLAGS_UNDEFINED 0x8000
/* Structure for passing options, used by AVC and label subsystems */
struct selinux_opt {
@@ -578,6 +579,37 @@ extern const char *selinux_path(void);
*/
extern int selinux_check_access(const char * scon, const char * tcon, const char *tclass, const char *perm, void *auditdata);
+/**
+ * selinux_check_access_flags - Check permissions, returning avd flags and
+ * perform any appropriate auditing.
+ * @scon: source security context
+ * @tcon: target security context
+ * @tclass: target security class string
+ * @perm: requested permissions string, interpreted based on @tclass
+ * @auditdata: auxiliary audit data
+ * @flags: returned avd flags. Currently two flags are supported:
+ * SELINUX_AVD_FLAGS_UNDEFINED, which indicates that the remaining
+ * @flags should not be checked as the avd flags could not be read.
+ * SELINUX_AVD_FLAGS_PERMISSIVE, which indicates the decision is
+ * computed on a policy defined permissive domain.
+ *
+ * Check the AVC to determine whether the @perm permissions are granted
+ * for the SID pair (@scon, @tcon), interpreting the permissions
+ * based on @tclass.
+ * Return %0 if all @perm permissions are granted, -%1 with
+ * @errno set to %EACCES if any permissions are denied or to another
+ * value upon other errors.
+ * If auditing or logging is configured the appropriate callbacks will be
+ * called and passed the auditdata field.
+ * If selinux_check_access_flags() fails before calling the AVC, then @flags
+ * will be returned with a value of SELINUX_AVD_FLAGS_UNDEFINED as the avd
+ * flags could not be read. This will happen when either SELinux is disabled
+ * or there is an unknown class/permission.
+ */
+extern int selinux_check_access_flags(const char *scon, const char *tcon,
+ const char *tclass, const char *perm,
+ void *auditdata, unsigned int *flags);
+
/* Check a permission in the passwd class.
Return 0 if granted or -1 otherwise. */
extern int selinux_check_passwd_access(access_vector_t requested);
@@ -19,6 +19,13 @@ avc_has_perm, avc_has_perm_noaudit, avc_audit, avc_entry_ref_init \- obtain and
.BI "struct avc_entry_ref *" aeref ", void *" auditdata ");"
.in
.sp
+.BI "int avc_has_perm_flags(security_id_t " ssid ", security_id_t " tsid ,
+.in +\w'int avc_has_perm('u
+.BI "security_class_t " tclass ", access_vector_t " requested ,
+.br
+.BI "struct avc_entry_ref *" aeref ", void *" auditdata ", int *" flags ");"
+.in
+.sp
.BI "int avc_has_perm_noaudit(security_id_t " ssid ", security_id_t " tsid ,
.in +\w'int avc_has_perm('u
.BI "security_class_t " tclass ", access_vector_t " requested ,
@@ -60,6 +67,21 @@ parameter is for supplemental auditing; see
.BR avc_audit ()
below.
+.BR avc_has_perm_flags ()
+is identical to
+.BR avc_has_perm ()
+but additionally sets the
+.I flags
+field. On return
+.I flags
+must be tested and if
+.BR SELINUX_AVD_FLAGS_UNDEFINED ,
+then the remaining
+.I flags
+should not be checked. Currently one other flag is supported:
+.BR SELINUX_AVD_FLAGS_PERMISSIVE ,
+which indicates the decision is computed on a policy defined permissive domain.
+
.BR avc_has_perm_noaudit ()
behaves as
.BR avc_has_perm ()
@@ -69,6 +91,15 @@ and can be passed to
.BR avc_audit ()
explicitly.
+.BR avc_has_perm_noaudit_flags ()
+behaves as
+.BR avc_has_perm_flags ()
+without producing an audit message. The access decision is returned in
+.I avd
+and can be passed to
+.BR avc_audit ()
+explicitly.
+
.BR avc_audit ()
produces an audit message for the access query represented by
.IR ssid ,
@@ -101,9 +132,11 @@ After declaring an
structure, use
.BR avc_entry_ref_init ()
to initialize it before passing it to
-.BR avc_has_perm ()
+.BR avc_has_perm (),
+.BR avc_has_perm_flags (),
+.BR avc_has_perm_noaudit ()
or
-.BR \%avc_has_perm_noaudit ()
+.BR avc_has_perm_noaudit_flags ()
for the first time.
Using an uninitialized structure will produce undefined behavior.
.
@@ -39,7 +39,9 @@ the SELinux policy database in the kernel
.sp
.BI "int security_get_initial_context_raw(const char *" name ", char **" con );
.sp
-.BI "int selinux_check_access(const char *" scon ", const char *" tcon ", const char *" class ", const char *" perm ", void *" auditdata);
+.BI "int selinux_check_access(const char *" scon ", const char *" tcon ", const char *" class ", const char *" perm ", void *" auditdata );
+.sp
+.BI "int selinux_check_access_flags(const char *" scon ", const char *" tcon ", const char *" class ", const char *" perm ", void *" auditdata ", int *" flags );
.sp
.BI "int selinux_check_passwd_access(access_vector_t " requested );
.sp
@@ -67,7 +69,7 @@ field of
.IR avd .
Currently one flag is supported:
.BR SELINUX_AVD_FLAGS_PERMISSIVE ,
-which indicates the decision is computed on a permissive domain.
+which indicates the decision is computed on a policy defined permissive domain.
.BR security_compute_create ()
is used to compute a context to use for labeling a new object in a particular
@@ -119,6 +121,21 @@ translation.
.BR selinux_check_access ()
is used to check if the source context has the access permission for the specified class on the target context.
+.BR selinux_check_access_flags ()
+is identical to
+.BR selinux_check_access ()
+but additionally sets the
+.I flags
+field. On return
+.I flags
+must be tested and if
+.BR SELINUX_AVD_FLAGS_UNDEFINED ,
+then the remaining
+.I flags
+should not be checked. Currently one other flag is supported:
+.BR SELINUX_AVD_FLAGS_PERMISSIVE ,
+which indicates the decision is computed on a policy defined permissive domain.
+
.BR selinux_check_passwd_access ()
is used to check for a permission in the
.I passwd
new file mode 100644
@@ -0,0 +1 @@
+.so man3/security_compute_av.3
@@ -741,12 +741,27 @@ static void avd_init(struct av_decision *avd)
avd->flags = 0;
}
+
int avc_has_perm_noaudit(security_id_t ssid,
security_id_t tsid,
security_class_t tclass,
access_vector_t requested,
struct avc_entry_ref *aeref, struct av_decision *avd)
{
+ return avc_has_perm_noaudit_flags(ssid, tsid, tclass,
+ requested, aeref, avd, NULL);
+}
+
+hidden_def(avc_has_perm_noaudit)
+
+int avc_has_perm_noaudit_flags(security_id_t ssid,
+ security_id_t tsid,
+ security_class_t tclass,
+ access_vector_t requested,
+ struct avc_entry_ref *aeref,
+ struct av_decision *avd,
+ unsigned int *flags)
+{
struct avc_entry *ae;
int rc = 0;
struct avc_entry entry;
@@ -790,13 +805,13 @@ int avc_has_perm_noaudit(security_id_t ssid,
&entry.avd);
if (rc && errno == EINVAL && !avc_enforcing) {
rc = errno = 0;
- goto out;
+ goto set_undef;
}
if (rc)
- goto out;
+ goto set_undef;
rc = avc_insert(ssid, tsid, tclass, &entry, aeref);
if (rc)
- goto out;
+ goto set_undef;
}
ae = aeref->ae;
}
@@ -816,21 +831,38 @@ int avc_has_perm_noaudit(security_id_t ssid,
}
}
- out:
+ if (flags)
+ *flags = ae->avd.flags;
+out:
avc_release_lock(avc_lock);
return rc;
+
+set_undef:
+ if (flags)
+ *flags = SELINUX_AVD_FLAGS_UNDEFINED;
+ goto out;
}
-hidden_def(avc_has_perm_noaudit)
+hidden_def(avc_has_perm_noaudit_flags)
int avc_has_perm(security_id_t ssid, security_id_t tsid,
security_class_t tclass, access_vector_t requested,
struct avc_entry_ref *aeref, void *auditdata)
{
+ return avc_has_perm_flags(ssid, tsid, tclass, requested, aeref,
+ auditdata, NULL);
+}
+
+int avc_has_perm_flags(security_id_t ssid, security_id_t tsid,
+ security_class_t tclass, access_vector_t requested,
+ struct avc_entry_ref *aeref, void *auditdata,
+ unsigned int *flags)
+{
struct av_decision avd;
int errsave, rc;
- rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd);
+ rc = avc_has_perm_noaudit_flags(ssid, tsid, tclass,
+ requested, aeref, &avd, flags);
errsave = errno;
avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
errno = errsave;
@@ -179,4 +179,5 @@ hidden_proto(avc_av_stats)
hidden_proto(avc_reset)
hidden_proto(avc_audit)
hidden_proto(avc_has_perm_noaudit)
+ hidden_proto(avc_has_perm_noaudit_flags)
#endif /* _SELINUX_AVC_INTERNAL_H_ */
@@ -1,4 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
@@ -32,7 +31,16 @@ static void avc_init_once(void)
}
}
-int selinux_check_access(const char *scon, const char *tcon, const char *class, const char *perm, void *aux) {
+int selinux_check_access(const char *scon, const char *tcon, const char *class,
+ const char *perm, void *aux)
+{
+ return selinux_check_access_flags(scon, tcon, class, perm, aux, NULL);
+}
+
+int selinux_check_access_flags(const char *scon, const char *tcon,
+ const char *class, const char *perm,
+ void *aux, unsigned int *flags)
+{
int rc;
security_id_t scon_id;
security_id_t tcon_id;
@@ -41,6 +49,13 @@ int selinux_check_access(const char *scon, const char *tcon, const char *class,
__selinux_once(once, avc_init_once);
+ /* Set flags undefined as avc_has_perm_flags may never get called,
+ * as either SELinux is disabled or there is an unknown
+ * class/permission.
+ */
+ if (flags)
+ *flags = SELINUX_AVD_FLAGS_UNDEFINED;
+
if (selinux_enabled != 1)
return 0;
@@ -54,27 +69,29 @@ int selinux_check_access(const char *scon, const char *tcon, const char *class,
(void) avc_netlink_check_nb();
- sclass = string_to_security_class(class);
- if (sclass == 0) {
- rc = errno;
- avc_log(SELINUX_ERROR, "Unknown class %s", class);
- if (security_deny_unknown() == 0)
- return 0;
- errno = rc;
- return -1;
- }
-
- av = string_to_av_perm(sclass, perm);
- if (av == 0) {
- rc = errno;
- avc_log(SELINUX_ERROR, "Unknown permission %s for class %s", perm, class);
- if (security_deny_unknown() == 0)
- return 0;
- errno = rc;
- return -1;
- }
-
- return avc_has_perm (scon_id, tcon_id, sclass, av, NULL, aux);
+ sclass = string_to_security_class(class);
+ if (sclass == 0) {
+ rc = errno;
+ avc_log(SELINUX_ERROR, "Unknown class %s", class);
+ if (security_deny_unknown() == 0)
+ return 0;
+ errno = rc;
+ return -1;
+ }
+
+ av = string_to_av_perm(sclass, perm);
+ if (av == 0) {
+ rc = errno;
+ avc_log(SELINUX_ERROR, "Unknown permission %s for class %s",
+ perm, class);
+ if (security_deny_unknown() == 0)
+ return 0;
+ errno = rc;
+ return -1;
+ }
+
+ return avc_has_perm_flags(scon_id, tcon_id, sclass, av, NULL,
+ aux, flags);
}
int selinux_check_passwd_access(access_vector_t requested)
@@ -25,3 +25,5 @@ selinuxexeccon
setenforce
setfilecon
togglesebool
+avc_has_perm
+selinux_check_access
new file mode 100644
@@ -0,0 +1,235 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#include <selinux/avc.h>
+
+static void usage(char *progname)
+{
+ fprintf(stderr, "usage: %s [-f] [-i] [-p] scon tcon class perm\n"
+ "\nWhere:\n\t"
+ "-f Call avc_has_perm_flags(3) to obtain the avd\n\t"
+ " flags. Currently only the SELINUX_AVD_FLAGS_PERMISSIVE\n\t"
+ " flag is defined. If set, signifies the source type is\n\t"
+ " defined in policy as a PERMISSIVE type.\n\t"
+ " The default is to call avc_has_perm(3) that\n\t"
+ " does not request the avd flags.\n\t"
+ "-i Interactive mode. Once displayed first result, can\n\t"
+ " enter additional entries and display AVC cache info.\n"
+ "-p Set avc_open to permissive mode.\n",
+ progname);
+ exit(1);
+}
+
+static void get_entry(char **buffer)
+{
+ char *buf;
+ int len;
+#define BUF_LEN 81
+
+ buf = malloc(BUF_LEN * sizeof(char));
+ if (!buf) {
+ perror("malloc");
+ exit(1);
+ }
+
+ if (fgets(buf, BUF_LEN - 1, stdin) == NULL) {
+ perror("fgets");
+ exit(1);
+ }
+
+ len = strlen(buf);
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = 0;
+
+ *buffer = buf;
+}
+
+/*
+ * Function to print the AVC statistics. Because no audit logging call back
+ * has been set, the avc_cache_stats will be displayed on stderr.
+ */
+static void print_avc_stats(void)
+{
+ struct avc_cache_stats acs;
+
+ avc_cache_stats(&acs);
+ printf("\nThe avc_cache_stats are as follows:\n");
+ printf("entry_hits: %d\t(Decisions found in aeref)\n",
+ acs.entry_hits);
+ printf("entry_misses: %d\t(Decisions not found in aeref)\n",
+ acs.entry_misses);
+ printf("entry_discards: %d\t(Decisions not found in aeref that were "
+ "also non-NULL)\n", acs.entry_discards);
+ printf("entry_lookups: %d\t(Queries made)\n", acs.entry_lookups);
+ printf("cav_lookups: %d\t(Cache lookups)\n", acs.cav_lookups);
+ printf("cav_hits: %d\t(Cache hits)\n", acs.cav_hits);
+ printf("cav_probes: %d\t(Entries examined searching the cache)\n",
+ acs.cav_probes);
+ printf("cav_misses: %d\t(Cache misses)\n\n", acs.cav_misses);
+}
+
+struct avc_entry_ref aeref;
+static void exec_func(char *scon, char *tcon, char *class, char *perm,
+ bool get_flags)
+{
+ int rc;
+ unsigned int flags;
+ context_t context;
+ const char *type;
+ security_id_t scon_id;
+ security_id_t tcon_id;
+ security_class_t sclass;
+ access_vector_t av;
+
+ rc = avc_context_to_sid(scon, &scon_id);
+ if (rc < 0) {
+ perror("Error scon avc_context_to_sid");
+ exit(1);
+ }
+
+ rc = avc_context_to_sid(tcon, &tcon_id);
+ if (rc < 0) {
+ perror("Error tcon avc_context_to_sid");
+ exit(1);
+ }
+
+ sclass = string_to_security_class(class);
+ av = string_to_av_perm(sclass, perm);
+
+ context = context_new(scon);
+ if (!context) {
+ perror("Error context_new");
+ exit(1);
+ }
+ type = context_type_get(context);
+ if (!type) {
+ perror("Error context_type_get");
+ free(context);
+ exit(1);
+ }
+
+ printf("\nAny avc_log error messages are shown on stderr:\n");
+ if (get_flags)
+ rc = avc_has_perm_flags(scon_id, tcon_id, sclass, av, &aeref,
+ NULL, &flags);
+ else
+ rc = avc_has_perm(scon_id, tcon_id, sclass, av, &aeref, NULL);
+ printf("\nEnd of avc_log error messages.\n\n");
+
+ if (rc < 0) {
+ printf("Error %s: %s\n",
+ get_flags ? "avc_has_perm_flags" : "avc_has_perm",
+ strerror(errno));
+ } else {
+ printf("Permission ALLOWED.\n");
+ }
+
+ if (get_flags) {
+ if (flags & SELINUX_AVD_FLAGS_UNDEFINED)
+ printf("AVD flags are undefined.\n");
+ else if (flags & SELINUX_AVD_FLAGS_PERMISSIVE)
+ printf("%s is defined in policy as a PERMISSIVE "
+ "domain.\n", type);
+ else
+ printf("%s is NOT defined in policy as a PERMISSIVE "
+ "domain.\n", type);
+ }
+ context_free(context);
+}
+
+int main(int argc, char **argv)
+{
+ int opt, rc;
+ bool get_flags = false, interactive = false;
+ char *scon, *tcon, *class, *perm;
+ struct selinux_opt avc_option;
+
+ avc_option.type = AVC_OPT_SETENFORCE;
+ avc_option.value = (char *)1;
+
+ while ((opt = getopt(argc, argv, "fip")) != -1) {
+ switch (opt) {
+ case 'f':
+ get_flags = true;
+ break;
+ case 'i':
+ interactive = true;
+ break;
+ case 'p':
+ avc_option.value = NULL;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if ((argc - optind) != 4)
+ usage(argv[0]);
+
+ rc = is_selinux_enabled();
+ if (rc == 0) {
+ printf("SELinux is not enabled.\n");
+ exit(1);
+ } else if (rc == 1) {
+ printf("SELinux is enabled.\n");
+ } else {
+ perror("Error is_selinux_enabled");
+ exit(1);
+ }
+
+ rc = security_getenforce();
+ if (rc == 0)
+ printf("SELinux running in PERMISSIVE mode.\n");
+ else if (rc == 1)
+ printf("SELinux running in ENFORCING mode.\n");
+ else {
+ perror("Error security_getenforce");
+ exit(1);
+ }
+
+ rc = security_deny_unknown();
+ if (rc == 0)
+ printf("Undefined object classes or permissions: ALLOWED.\n");
+ else if (rc == 1)
+ printf("Undefined object classes or permissions: DENIED.\n");
+ else {
+ perror("Error security_deny_unknown");
+ exit(1);
+ }
+
+ if (avc_open(&avc_option, 1)) {
+ perror("Error avc_open");
+ exit(1);
+ }
+
+ if (avc_option.value == NULL)
+ printf("avc_open - PERMISSIVE mode.\n");
+ else
+ printf("avc_open - ENFORCING mode.\n");
+
+ avc_entry_ref_init(&aeref);
+
+ exec_func(argv[optind], argv[optind + 1], argv[optind + 2],
+ argv[optind + 3], get_flags);
+
+ while (interactive) {
+ printf("\nEnter scon: ");
+ get_entry(&scon);
+ printf("Enter tcon: ");
+ get_entry(&tcon);
+ printf("Enter class: ");
+ get_entry(&class);
+ printf("Enter perm: ");
+ get_entry(&perm);
+
+ exec_func(scon, tcon, class, perm, get_flags);
+ print_avc_stats();
+ }
+
+ exit(0);
+}
new file mode 100644
@@ -0,0 +1,189 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#include <selinux/avc.h>
+
+static void usage(char *progname)
+{
+ fprintf(stderr, "usage: %s [-f] [-i] scon tcon class perm\n"
+ "\nWhere:\n\t"
+ "-f Call selinux_check_access_flags(3) to obtain the avd\n\t"
+ " flags. Currently only the SELINUX_AVD_FLAGS_PERMISSIVE\n\t"
+ " flag is defined. If set, signifies the source type is\n\t"
+ " defined in policy as a PERMISSIVE type.\n\t"
+ " The default is to call selinux_check_access(3) that\n\t"
+ " does not request the avd flags.\n\t"
+ "-i Interactive mode. Once displayed first result, can\n\t"
+ " enter additional entries and display AVC cache info.\n",
+ progname);
+ exit(1);
+}
+
+static void get_entry(char **buffer)
+{
+ char *buf;
+ int len;
+#define BUF_LEN 81
+
+ buf = malloc(BUF_LEN * sizeof(char));
+ if (!buf) {
+ perror("malloc");
+ exit(1);
+ }
+
+ if (fgets(buf, BUF_LEN - 1, stdin) == NULL) {
+ perror("fgets");
+ exit(1);
+ }
+
+ len = strlen(buf);
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = 0;
+
+ *buffer = buf;
+}
+
+/*
+ * Function to print the AVC statistics. Because no audit logging call back
+ * has been set, the avc_cache_stats will be displayed on stderr.
+ * selinux_check_access* sets aeref = NULL, so do not print these stats.
+ */
+static void print_avc_stats(void)
+{
+ struct avc_cache_stats acs;
+
+ avc_cache_stats(&acs);
+ printf("\nThe avc_cache_stats are as follows:\n");
+ printf("entry_lookups: %d\t(Queries made)\n", acs.entry_lookups);
+ printf("cav_lookups: %d\t(Cache lookups)\n", acs.cav_lookups);
+ printf("cav_hits: %d\t(Cache hits)\n", acs.cav_hits);
+ printf("cav_probes: %d\t(Entries examined searching the cache)\n",
+ acs.cav_probes);
+ printf("cav_misses: %d\t(Cache misses)\n\n", acs.cav_misses);
+}
+
+static void exec_func(char *scon, char *tcon, char *class, char *perm,
+ bool get_flags)
+{
+ int rc;
+ unsigned int flags;
+ context_t context;
+ const char *type;
+
+ context = context_new(scon);
+ if (!context) {
+ perror("Error context_new");
+ exit(1);
+ }
+ type = context_type_get(context);
+ if (!type) {
+ perror("Error context_type_get");
+ free(context);
+ exit(1);
+ }
+
+ printf("\nAny avc_log error messages are shown on stderr:\n");
+ if (get_flags)
+ rc = selinux_check_access_flags(scon, tcon, class, perm,
+ NULL, &flags);
+ else
+ rc = selinux_check_access(scon, tcon, class, perm, NULL);
+ printf("\nEnd of avc_log error messages.\n\n");
+
+ if (rc < 0)
+ printf("Error %s: %s\n",
+ get_flags ? "selinux_check_access_flags" :
+ "selinux_check_access", strerror(errno));
+ else
+ printf("Permission ALLOWED.\n");
+
+ if (get_flags) {
+ if (flags & SELINUX_AVD_FLAGS_UNDEFINED)
+ printf("AVD flags are undefined.\n");
+ else if (flags & SELINUX_AVD_FLAGS_PERMISSIVE)
+ printf("%s is defined in policy as a PERMISSIVE "
+ "domain.\n", type);
+ else
+ printf("%s is NOT defined in policy as a PERMISSIVE "
+ "domain.\n", type);
+ }
+ context_free(context);
+}
+
+int main(int argc, char **argv)
+{
+ int opt, rc;
+ bool get_flags = false, interactive = false;
+ char *scon, *tcon, *class, *perm;
+
+ while ((opt = getopt(argc, argv, "fi")) != -1) {
+ switch (opt) {
+ case 'f':
+ get_flags = true;
+ break;
+ case 'i':
+ interactive = true;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if ((argc - optind) != 4)
+ usage(argv[0]);
+
+ rc = is_selinux_enabled();
+ if (rc == 0) {
+ printf("SELinux is not enabled.\n");
+ exit(1);
+ } else if (rc == 1) {
+ printf("SELinux is enabled.\n");
+ } else {
+ perror("Error is_selinux_enabled");
+ exit(1);
+ }
+
+ rc = security_getenforce();
+ if (rc == 0)
+ printf("SELinux running in PERMISSIVE mode.\n");
+ else if (rc == 1)
+ printf("SELinux running in ENFORCING mode.\n");
+ else {
+ perror("Error security_getenforce");
+ exit(1);
+ }
+
+ rc = security_deny_unknown();
+ if (rc == 0)
+ printf("Undefined object classes or permissions: ALLOWED.\n");
+ else if (rc == 1)
+ printf("Undefined object classes or permissions: DENIED.\n");
+ else {
+ perror("Error security_deny_unknown");
+ exit(1);
+ }
+
+ exec_func(argv[optind], argv[optind + 1], argv[optind + 2],
+ argv[optind + 3], get_flags);
+
+ while (interactive) {
+ printf("\nEnter scon: ");
+ get_entry(&scon);
+ printf("Enter tcon: ");
+ get_entry(&tcon);
+ printf("Enter class: ");
+ get_entry(&class);
+ printf("Enter perm: ");
+ get_entry(&perm);
+
+ exec_func(scon, tcon, class, perm, get_flags);
+ print_avc_stats();
+ }
+
+ exit(0);
+}
Add function selinux_check_access_flags() that is the same as selinux_check_access() except that it will also return the avd flags. Currently only the SELINUX_AVD_FLAGS_PERMISSIVE flag is used to signify that the source type is defined as permissive in policy. Because selinux_check_access_flags() can return before the AVC call, and also the AVC call may return with undefined avd flags, the returned flags should be checked for SELINUX_AVD_FLAGS_UNDEFINED, first. If set, the remaining flags are undefined. See the selinux_check_access_flags() man page entry for details. There is a utility for testing the functionality: utils/selinux_check_access -f scon tcon class perm As a consequence of implementing selinux_check_access_flags, additional calls have been added to avc.c: avc_has_perm_flags() and avc_has_perm_noaudit_flags(). The appropriate man pages have been updated. There is a utility for testing the avc_has_perm() and avc_has_perm_flags(): utils/avc_has_perm -f scon tcon class perm Signed-off-by: Richard Haines <richard_c_haines@btinternet.com> --- libselinux/include/selinux/avc.h | 68 +++++++ libselinux/include/selinux/selinux.h | 32 +++ libselinux/man/man3/avc_has_perm.3 | 37 +++- libselinux/man/man3/security_compute_av.3 | 21 +- libselinux/man/man3/selinux_check_access_flags.3 | 1 + libselinux/src/avc.c | 44 ++++- libselinux/src/avc_internal.h | 1 + libselinux/src/checkAccess.c | 63 +++--- libselinux/utils/.gitignore | 2 + libselinux/utils/avc_has_perm.c | 235 +++++++++++++++++++++++ libselinux/utils/selinux_check_access.c | 189 ++++++++++++++++++ 11 files changed, 660 insertions(+), 33 deletions(-) create mode 100644 libselinux/man/man3/selinux_check_access_flags.3 create mode 100644 libselinux/utils/avc_has_perm.c create mode 100644 libselinux/utils/selinux_check_access.c