16cd6a6acSopenharmony_ci#include <unistd.h>
26cd6a6acSopenharmony_ci#include <sys/types.h>
36cd6a6acSopenharmony_ci#include <fcntl.h>
46cd6a6acSopenharmony_ci#include <stdlib.h>
56cd6a6acSopenharmony_ci#include <stdio.h>
66cd6a6acSopenharmony_ci#include <errno.h>
76cd6a6acSopenharmony_ci#include <string.h>
86cd6a6acSopenharmony_ci#include <limits.h>
96cd6a6acSopenharmony_ci#include "selinux_internal.h"
106cd6a6acSopenharmony_ci#include "policy.h"
116cd6a6acSopenharmony_ci#include "mapping.h"
126cd6a6acSopenharmony_ci
136cd6a6acSopenharmony_ciint security_compute_av_flags_raw(const char * scon,
146cd6a6acSopenharmony_ci				  const char * tcon,
156cd6a6acSopenharmony_ci				  security_class_t tclass,
166cd6a6acSopenharmony_ci				  access_vector_t requested,
176cd6a6acSopenharmony_ci				  struct av_decision *avd)
186cd6a6acSopenharmony_ci{
196cd6a6acSopenharmony_ci	char path[PATH_MAX];
206cd6a6acSopenharmony_ci	char *buf;
216cd6a6acSopenharmony_ci	size_t len;
226cd6a6acSopenharmony_ci	int fd, ret;
236cd6a6acSopenharmony_ci	security_class_t kclass;
246cd6a6acSopenharmony_ci
256cd6a6acSopenharmony_ci	if (!selinux_mnt) {
266cd6a6acSopenharmony_ci		errno = ENOENT;
276cd6a6acSopenharmony_ci		return -1;
286cd6a6acSopenharmony_ci	}
296cd6a6acSopenharmony_ci
306cd6a6acSopenharmony_ci	snprintf(path, sizeof path, "%s/access", selinux_mnt);
316cd6a6acSopenharmony_ci	fd = open(path, O_RDWR | O_CLOEXEC);
326cd6a6acSopenharmony_ci	if (fd < 0)
336cd6a6acSopenharmony_ci		return -1;
346cd6a6acSopenharmony_ci
356cd6a6acSopenharmony_ci	len = selinux_page_size;
366cd6a6acSopenharmony_ci	buf = malloc(len);
376cd6a6acSopenharmony_ci	if (!buf) {
386cd6a6acSopenharmony_ci		ret = -1;
396cd6a6acSopenharmony_ci		goto out;
406cd6a6acSopenharmony_ci	}
416cd6a6acSopenharmony_ci
426cd6a6acSopenharmony_ci	kclass = unmap_class(tclass);
436cd6a6acSopenharmony_ci
446cd6a6acSopenharmony_ci	ret = snprintf(buf, len, "%s %s %hu %x", scon, tcon,
456cd6a6acSopenharmony_ci		 kclass, unmap_perm(tclass, requested));
466cd6a6acSopenharmony_ci	if (ret < 0 || (size_t)ret >= len) {
476cd6a6acSopenharmony_ci		errno = EOVERFLOW;
486cd6a6acSopenharmony_ci		ret = -1;
496cd6a6acSopenharmony_ci		goto out2;
506cd6a6acSopenharmony_ci	}
516cd6a6acSopenharmony_ci
526cd6a6acSopenharmony_ci	ret = write(fd, buf, strlen(buf));
536cd6a6acSopenharmony_ci	if (ret < 0)
546cd6a6acSopenharmony_ci		goto out2;
556cd6a6acSopenharmony_ci
566cd6a6acSopenharmony_ci	memset(buf, 0, len);
576cd6a6acSopenharmony_ci	ret = read(fd, buf, len - 1);
586cd6a6acSopenharmony_ci	if (ret < 0)
596cd6a6acSopenharmony_ci		goto out2;
606cd6a6acSopenharmony_ci
616cd6a6acSopenharmony_ci	ret = sscanf(buf, "%x %x %x %x %u %x",
626cd6a6acSopenharmony_ci		     &avd->allowed, &avd->decided,
636cd6a6acSopenharmony_ci		     &avd->auditallow, &avd->auditdeny,
646cd6a6acSopenharmony_ci		     &avd->seqno, &avd->flags);
656cd6a6acSopenharmony_ci	if (ret < 5) {
666cd6a6acSopenharmony_ci		ret = -1;
676cd6a6acSopenharmony_ci		goto out2;
686cd6a6acSopenharmony_ci	} else if (ret < 6)
696cd6a6acSopenharmony_ci		avd->flags = 0;
706cd6a6acSopenharmony_ci
716cd6a6acSopenharmony_ci	/*
726cd6a6acSopenharmony_ci	 * If the tclass could not be mapped to a kernel class at all, the
736cd6a6acSopenharmony_ci	 * kernel will have already set avd according to the
746cd6a6acSopenharmony_ci	 * handle_unknown flag and we do not need to do anything further.
756cd6a6acSopenharmony_ci	 * Otherwise, we must map the permissions within the returned
766cd6a6acSopenharmony_ci	 * avd to the userspace permission values.
776cd6a6acSopenharmony_ci	 */
786cd6a6acSopenharmony_ci	if (kclass != 0)
796cd6a6acSopenharmony_ci		map_decision(tclass, avd);
806cd6a6acSopenharmony_ci
816cd6a6acSopenharmony_ci	ret = 0;
826cd6a6acSopenharmony_ci      out2:
836cd6a6acSopenharmony_ci	free(buf);
846cd6a6acSopenharmony_ci      out:
856cd6a6acSopenharmony_ci	close(fd);
866cd6a6acSopenharmony_ci	return ret;
876cd6a6acSopenharmony_ci}
886cd6a6acSopenharmony_ci
896cd6a6acSopenharmony_ci
906cd6a6acSopenharmony_ciint security_compute_av_raw(const char * scon,
916cd6a6acSopenharmony_ci			    const char * tcon,
926cd6a6acSopenharmony_ci			    security_class_t tclass,
936cd6a6acSopenharmony_ci			    access_vector_t requested,
946cd6a6acSopenharmony_ci			    struct av_decision *avd)
956cd6a6acSopenharmony_ci{
966cd6a6acSopenharmony_ci	struct av_decision lavd;
976cd6a6acSopenharmony_ci	int ret;
986cd6a6acSopenharmony_ci
996cd6a6acSopenharmony_ci	ret = security_compute_av_flags_raw(scon, tcon, tclass,
1006cd6a6acSopenharmony_ci					    requested, &lavd);
1016cd6a6acSopenharmony_ci	if (ret == 0) {
1026cd6a6acSopenharmony_ci		avd->allowed = lavd.allowed;
1036cd6a6acSopenharmony_ci		avd->decided = lavd.decided;
1046cd6a6acSopenharmony_ci		avd->auditallow = lavd.auditallow;
1056cd6a6acSopenharmony_ci		avd->auditdeny = lavd.auditdeny;
1066cd6a6acSopenharmony_ci		avd->seqno = lavd.seqno;
1076cd6a6acSopenharmony_ci		/* NOTE:
1086cd6a6acSopenharmony_ci		 * We should not return avd->flags via the interface
1096cd6a6acSopenharmony_ci		 * due to the binary compatibility.
1106cd6a6acSopenharmony_ci		 */
1116cd6a6acSopenharmony_ci	}
1126cd6a6acSopenharmony_ci	return ret;
1136cd6a6acSopenharmony_ci}
1146cd6a6acSopenharmony_ci
1156cd6a6acSopenharmony_ci
1166cd6a6acSopenharmony_ciint security_compute_av_flags(const char * scon,
1176cd6a6acSopenharmony_ci			      const char * tcon,
1186cd6a6acSopenharmony_ci			      security_class_t tclass,
1196cd6a6acSopenharmony_ci			      access_vector_t requested,
1206cd6a6acSopenharmony_ci			      struct av_decision *avd)
1216cd6a6acSopenharmony_ci{
1226cd6a6acSopenharmony_ci	char * rscon;
1236cd6a6acSopenharmony_ci	char * rtcon;
1246cd6a6acSopenharmony_ci	int ret;
1256cd6a6acSopenharmony_ci
1266cd6a6acSopenharmony_ci	if (selinux_trans_to_raw_context(scon, &rscon))
1276cd6a6acSopenharmony_ci		return -1;
1286cd6a6acSopenharmony_ci	if (selinux_trans_to_raw_context(tcon, &rtcon)) {
1296cd6a6acSopenharmony_ci		freecon(rscon);
1306cd6a6acSopenharmony_ci		return -1;
1316cd6a6acSopenharmony_ci	}
1326cd6a6acSopenharmony_ci	ret = security_compute_av_flags_raw(rscon, rtcon, tclass,
1336cd6a6acSopenharmony_ci					    requested, avd);
1346cd6a6acSopenharmony_ci
1356cd6a6acSopenharmony_ci	freecon(rscon);
1366cd6a6acSopenharmony_ci	freecon(rtcon);
1376cd6a6acSopenharmony_ci
1386cd6a6acSopenharmony_ci	return ret;
1396cd6a6acSopenharmony_ci}
1406cd6a6acSopenharmony_ci
1416cd6a6acSopenharmony_ci
1426cd6a6acSopenharmony_ciint security_compute_av(const char * scon,
1436cd6a6acSopenharmony_ci			const char * tcon,
1446cd6a6acSopenharmony_ci			security_class_t tclass,
1456cd6a6acSopenharmony_ci			access_vector_t requested, struct av_decision *avd)
1466cd6a6acSopenharmony_ci{
1476cd6a6acSopenharmony_ci	struct av_decision lavd;
1486cd6a6acSopenharmony_ci	int ret;
1496cd6a6acSopenharmony_ci
1506cd6a6acSopenharmony_ci	ret = security_compute_av_flags(scon, tcon, tclass,
1516cd6a6acSopenharmony_ci					requested, &lavd);
1526cd6a6acSopenharmony_ci	if (ret == 0)
1536cd6a6acSopenharmony_ci	{
1546cd6a6acSopenharmony_ci		avd->allowed = lavd.allowed;
1556cd6a6acSopenharmony_ci		avd->decided = lavd.decided;
1566cd6a6acSopenharmony_ci		avd->auditallow = lavd.auditallow;
1576cd6a6acSopenharmony_ci		avd->auditdeny = lavd.auditdeny;
1586cd6a6acSopenharmony_ci		avd->seqno = lavd.seqno;
1596cd6a6acSopenharmony_ci		/* NOTE:
1606cd6a6acSopenharmony_ci		 * We should not return avd->flags via the interface
1616cd6a6acSopenharmony_ci		 * due to the binary compatibility.
1626cd6a6acSopenharmony_ci		 */
1636cd6a6acSopenharmony_ci	}
1646cd6a6acSopenharmony_ci
1656cd6a6acSopenharmony_ci	return ret;
1666cd6a6acSopenharmony_ci}
1676cd6a6acSopenharmony_ci
168