diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h index 73f5db03..08aa2462 100644 --- a/libselinux/include/selinux/selinux.h +++ b/libselinux/include/selinux/selinux.h @@ -130,8 +130,12 @@ struct av_decision { access_vector_t auditallow; access_vector_t auditdeny; unsigned int seqno; + unsigned int flags; }; +/* Definitions of av_decision.flags */ +#define SELINUX_AVD_FLAGS_PERMISSIVE 0x0001 + /* Structure for passing options, used by AVC and label subsystems */ struct selinux_opt { int type; @@ -186,6 +190,17 @@ extern int security_compute_av_raw(security_context_t scon, access_vector_t requested, struct av_decision *avd); +extern int security_compute_av_flags(security_context_t scon, + security_context_t tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd); +extern int security_compute_av_flags_raw(security_context_t scon, + security_context_t tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd); + /* Compute a labeling decision and set *newcon to refer to it. Caller must free via freecon. */ extern int security_compute_create(security_context_t scon, diff --git a/libselinux/man/man3/security_compute_av.3 b/libselinux/man/man3/security_compute_av.3 index 885719fc..3298ed83 100644 --- a/libselinux/man/man3/security_compute_av.3 +++ b/libselinux/man/man3/security_compute_av.3 @@ -1,6 +1,6 @@ .TH "security_compute_av" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" .SH "NAME" -security_compute_av, security_compute_create, security_compute_relabel, +security_compute_av, security_compute_av_flags, security_compute_create, security_compute_relabel, security_compute_member, security_compute_user, security_get_initial_context \- query the SELinux policy database in the kernel. @@ -11,6 +11,8 @@ the SELinux policy database in the kernel. .sp .BI "int security_compute_av(security_context_t "scon ", security_context_t "tcon ", security_class_t "tclass ", access_vector_t "requested ", struct av_decision *" avd ); .sp +.BI "int security_compute_av_flags(security_context_t "scon ", security_context_t "tcon ", security_class_t "tclass ", access_vector_t "requested ", struct av_decision *" avd ); +.sp .BI "int security_compute_create(security_context_t "scon ", security_context_t "tcon ", security_class_t "tclass ", security_context_t *" newcon ); .sp .BI "int security_compute_relabel(security_context_t "scon ", security_context_t "tcon ", security_class_t "tclass ", security_context_t *" newcon ); @@ -34,7 +36,19 @@ via class .B tclass with the .B requested -access vector. See the cron source for a usage example. +access vector. The decision is returned in +.BR avd . + +.B security_compute_av_flags +is identical to +.B security_compute_av +but additionally sets the +.B flags +field of +.BR avd . +Currently one flag is supported: +.BR SELINUX_AVD_FLAGS_PERMISSIVE , +which indicates the decision is computed on a permissive domain. .B security_compute_create is used to compute a context to use for labeling a new object in a particular diff --git a/libselinux/man/man3/security_compute_av_flags.3 b/libselinux/man/man3/security_compute_av_flags.3 new file mode 100644 index 00000000..a60bca4d --- /dev/null +++ b/libselinux/man/man3/security_compute_av_flags.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/libselinux/src/avc.c b/libselinux/src/avc.c index 1545dd32..f0e2d334 100644 --- a/libselinux/src/avc.c +++ b/libselinux/src/avc.c @@ -849,9 +849,9 @@ int avc_has_perm_noaudit(security_id_t ssid, rc = -1; goto out; } - rc = security_compute_av_raw(ssid->ctx, tsid->ctx, - tclass, requested, - &entry.avd); + rc = security_compute_av_flags_raw(ssid->ctx, tsid->ctx, + tclass, requested, + &entry.avd); if (rc) goto out; rc = avc_insert(ssid, tsid, tclass, &entry, aeref); @@ -867,11 +867,13 @@ int avc_has_perm_noaudit(security_id_t ssid, denied = requested & ~(ae->avd.allowed); if (!requested || denied) { - if (avc_enforcing) { + if (!avc_enforcing || + (ae->avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE)) + ae->avd.allowed |= requested; + else { errno = EACCES; rc = -1; - } else - ae->avd.allowed |= requested; + } } out: @@ -885,9 +887,11 @@ 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) { - struct av_decision avd = { 0, 0, 0, 0, 0 }; + struct av_decision avd; int errsave, rc; + memset(&avd, 0, sizeof(avd)); + rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd); errsave = errno; avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); @@ -917,8 +921,8 @@ int avc_compute_create(security_id_t ssid, security_id_t tsid, rc = avc_lookup(ssid, tsid, tclass, 0, &aeref); if (rc) { /* need to make a cache entry for this tuple */ - rc = security_compute_av_raw(ssid->ctx, tsid->ctx, - tclass, 0, &entry.avd); + rc = security_compute_av_flags_raw(ssid->ctx, tsid->ctx, + tclass, 0, &entry.avd); if (rc) goto out; rc = avc_insert(ssid, tsid, tclass, &entry, &aeref); diff --git a/libselinux/src/compute_av.c b/libselinux/src/compute_av.c index 45cd0db0..a821d178 100644 --- a/libselinux/src/compute_av.c +++ b/libselinux/src/compute_av.c @@ -10,10 +10,11 @@ #include "policy.h" #include "mapping.h" -int security_compute_av_raw(security_context_t scon, - security_context_t tcon, - security_class_t tclass, - access_vector_t requested, struct av_decision *avd) +int security_compute_av_flags_raw(security_context_t scon, + security_context_t tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd) { char path[PATH_MAX]; char *buf; @@ -49,12 +50,15 @@ int security_compute_av_raw(security_context_t scon, if (ret < 0) goto out2; - if (sscanf(buf, "%x %x %x %x %u", &avd->allowed, - &avd->decided, &avd->auditallow, &avd->auditdeny, - &avd->seqno) != 5) { + ret = sscanf(buf, "%x %x %x %x %u %x", + &avd->allowed, &avd->decided, + &avd->auditallow, &avd->auditdeny, + &avd->seqno, &avd->flags); + if (ret < 5) { ret = -1; goto out2; - } + } else if (ret < 6) + avd->flags = 0; map_decision(tclass, avd); @@ -66,16 +70,44 @@ int security_compute_av_raw(security_context_t scon, return ret; } +hidden_def(security_compute_av_flags_raw) + +int security_compute_av_raw(security_context_t scon, + security_context_t tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd) +{ + struct av_decision lavd; + int ret; + + ret = security_compute_av_flags_raw(scon, tcon, tclass, + requested, &lavd); + if (ret == 0) { + avd->allowed = lavd.allowed; + avd->decided = lavd.decided; + avd->auditallow = lavd.auditallow; + avd->auditdeny = lavd.auditdeny; + avd->seqno = lavd.seqno; + /* NOTE: + * We should not return avd->flags via the interface + * due to the binary compatibility. + */ + } + return ret; +} + hidden_def(security_compute_av_raw) -int security_compute_av(security_context_t scon, - security_context_t tcon, - security_class_t tclass, - access_vector_t requested, struct av_decision *avd) +int security_compute_av_flags(security_context_t scon, + security_context_t tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd) { - int ret; security_context_t rscon = scon; security_context_t rtcon = tcon; + int ret; if (selinux_trans_to_raw_context(scon, &rscon)) return -1; @@ -83,8 +115,8 @@ int security_compute_av(security_context_t scon, freecon(rscon); return -1; } - - ret = security_compute_av_raw(rscon, rtcon, tclass, requested, avd); + ret = security_compute_av_flags_raw(rscon, rtcon, tclass, + requested, avd); freecon(rscon); freecon(rtcon); @@ -92,4 +124,32 @@ int security_compute_av(security_context_t scon, return ret; } +hidden_def(security_compute_av_flags) + +int security_compute_av(security_context_t scon, + security_context_t tcon, + security_class_t tclass, + access_vector_t requested, struct av_decision *avd) +{ + struct av_decision lavd; + int ret; + + ret = security_compute_av_flags(scon, tcon, tclass, + requested, &lavd); + if (ret == 0) + { + avd->allowed = lavd.allowed; + avd->decided = lavd.decided; + avd->auditallow = lavd.auditallow; + avd->auditdeny = lavd.auditdeny; + avd->seqno = lavd.seqno; + /* NOTE: + * We should not return avd->flags via the interface + * due to the binary compatibility. + */ + } + + return ret; +} + hidden_def(security_compute_av) diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h index 8b4c6d49..cfb18a54 100644 --- a/libselinux/src/selinux_internal.h +++ b/libselinux/src/selinux_internal.h @@ -16,6 +16,8 @@ hidden_proto(selinux_mkload_policy) hidden_proto(security_canonicalize_context_raw) hidden_proto(security_compute_av) hidden_proto(security_compute_av_raw) + hidden_proto(security_compute_av_flags) + hidden_proto(security_compute_av_flags_raw) hidden_proto(security_compute_user) hidden_proto(security_compute_user_raw) hidden_proto(security_compute_create)