16cd6a6acSopenharmony_ci#include <unistd.h>
26cd6a6acSopenharmony_ci#include <fcntl.h>
36cd6a6acSopenharmony_ci#include <string.h>
46cd6a6acSopenharmony_ci#include <stdlib.h>
56cd6a6acSopenharmony_ci#include <errno.h>
66cd6a6acSopenharmony_ci#include <ctype.h>
76cd6a6acSopenharmony_ci#include <stdio.h>
86cd6a6acSopenharmony_ci#include <stdio_ext.h>
96cd6a6acSopenharmony_ci#include <dlfcn.h>
106cd6a6acSopenharmony_ci#include <sys/statvfs.h>
116cd6a6acSopenharmony_ci#include <sys/vfs.h>
126cd6a6acSopenharmony_ci#include <stdint.h>
136cd6a6acSopenharmony_ci#include <limits.h>
146cd6a6acSopenharmony_ci
156cd6a6acSopenharmony_ci#include "policy.h"
166cd6a6acSopenharmony_ci#include "selinux_internal.h"
176cd6a6acSopenharmony_ci#include "setrans_internal.h"
186cd6a6acSopenharmony_ci
196cd6a6acSopenharmony_cichar *selinux_mnt = NULL;
206cd6a6acSopenharmony_ciint selinux_page_size = 0;
216cd6a6acSopenharmony_ci
226cd6a6acSopenharmony_ciint has_selinux_config = 0;
236cd6a6acSopenharmony_ci
246cd6a6acSopenharmony_ci/* Verify the mount point for selinux file system has a selinuxfs.
256cd6a6acSopenharmony_ci   If the file system:
266cd6a6acSopenharmony_ci   * Exist,
276cd6a6acSopenharmony_ci   * Is mounted with an selinux file system,
286cd6a6acSopenharmony_ci   * The file system is read/write
296cd6a6acSopenharmony_ci   * then set this as the default file system.
306cd6a6acSopenharmony_ci*/
316cd6a6acSopenharmony_cistatic int verify_selinuxmnt(const char *mnt)
326cd6a6acSopenharmony_ci{
336cd6a6acSopenharmony_ci	struct statfs sfbuf;
346cd6a6acSopenharmony_ci	int rc;
356cd6a6acSopenharmony_ci
366cd6a6acSopenharmony_ci	do {
376cd6a6acSopenharmony_ci		rc = statfs(mnt, &sfbuf);
386cd6a6acSopenharmony_ci	} while (rc < 0 && errno == EINTR);
396cd6a6acSopenharmony_ci	if (rc == 0) {
406cd6a6acSopenharmony_ci		if ((uint32_t)sfbuf.f_type == (uint32_t)SELINUX_MAGIC) {
416cd6a6acSopenharmony_ci			struct statvfs vfsbuf;
426cd6a6acSopenharmony_ci			rc = statvfs(mnt, &vfsbuf);
436cd6a6acSopenharmony_ci			if (rc == 0) {
446cd6a6acSopenharmony_ci				if (!(vfsbuf.f_flag & ST_RDONLY)) {
456cd6a6acSopenharmony_ci					set_selinuxmnt(mnt);
466cd6a6acSopenharmony_ci				}
476cd6a6acSopenharmony_ci				return 0;
486cd6a6acSopenharmony_ci			}
496cd6a6acSopenharmony_ci		}
506cd6a6acSopenharmony_ci	}
516cd6a6acSopenharmony_ci
526cd6a6acSopenharmony_ci	return -1;
536cd6a6acSopenharmony_ci}
546cd6a6acSopenharmony_ci
556cd6a6acSopenharmony_ciint selinuxfs_exists(void)
566cd6a6acSopenharmony_ci{
576cd6a6acSopenharmony_ci	int exists = 0;
586cd6a6acSopenharmony_ci	FILE *fp = NULL;
596cd6a6acSopenharmony_ci	char *buf = NULL;
606cd6a6acSopenharmony_ci	size_t len;
616cd6a6acSopenharmony_ci	ssize_t num;
626cd6a6acSopenharmony_ci
636cd6a6acSopenharmony_ci	fp = fopen("/proc/filesystems", "re");
646cd6a6acSopenharmony_ci	if (!fp)
656cd6a6acSopenharmony_ci		return 1; /* Fail as if it exists */
666cd6a6acSopenharmony_ci	__fsetlocking(fp, FSETLOCKING_BYCALLER);
676cd6a6acSopenharmony_ci
686cd6a6acSopenharmony_ci	num = getline(&buf, &len, fp);
696cd6a6acSopenharmony_ci	while (num != -1) {
706cd6a6acSopenharmony_ci		if (strstr(buf, SELINUXFS)) {
716cd6a6acSopenharmony_ci			exists = 1;
726cd6a6acSopenharmony_ci			break;
736cd6a6acSopenharmony_ci		}
746cd6a6acSopenharmony_ci		num = getline(&buf, &len, fp);
756cd6a6acSopenharmony_ci	}
766cd6a6acSopenharmony_ci
776cd6a6acSopenharmony_ci	free(buf);
786cd6a6acSopenharmony_ci	fclose(fp);
796cd6a6acSopenharmony_ci	return exists;
806cd6a6acSopenharmony_ci}
816cd6a6acSopenharmony_ci
826cd6a6acSopenharmony_cistatic void init_selinuxmnt(void)
836cd6a6acSopenharmony_ci{
846cd6a6acSopenharmony_ci	char *buf = NULL, *p;
856cd6a6acSopenharmony_ci	FILE *fp = NULL;
866cd6a6acSopenharmony_ci	size_t len;
876cd6a6acSopenharmony_ci	ssize_t num;
886cd6a6acSopenharmony_ci
896cd6a6acSopenharmony_ci	if (selinux_mnt)
906cd6a6acSopenharmony_ci		return;
916cd6a6acSopenharmony_ci
926cd6a6acSopenharmony_ci	if (verify_selinuxmnt(SELINUXMNT) == 0) return;
936cd6a6acSopenharmony_ci
946cd6a6acSopenharmony_ci	if (verify_selinuxmnt(OLDSELINUXMNT) == 0) return;
956cd6a6acSopenharmony_ci
966cd6a6acSopenharmony_ci	/* Drop back to detecting it the long way. */
976cd6a6acSopenharmony_ci	if (!selinuxfs_exists())
986cd6a6acSopenharmony_ci		goto out;
996cd6a6acSopenharmony_ci
1006cd6a6acSopenharmony_ci	/* At this point, the usual spot doesn't have an selinuxfs so
1016cd6a6acSopenharmony_ci	 * we look around for it */
1026cd6a6acSopenharmony_ci	fp = fopen("/proc/mounts", "re");
1036cd6a6acSopenharmony_ci	if (!fp)
1046cd6a6acSopenharmony_ci		goto out;
1056cd6a6acSopenharmony_ci
1066cd6a6acSopenharmony_ci	__fsetlocking(fp, FSETLOCKING_BYCALLER);
1076cd6a6acSopenharmony_ci	while ((num = getline(&buf, &len, fp)) != -1) {
1086cd6a6acSopenharmony_ci		char *tmp;
1096cd6a6acSopenharmony_ci		p = strchr(buf, ' ');
1106cd6a6acSopenharmony_ci		if (!p)
1116cd6a6acSopenharmony_ci			goto out;
1126cd6a6acSopenharmony_ci		p++;
1136cd6a6acSopenharmony_ci		tmp = strchr(p, ' ');
1146cd6a6acSopenharmony_ci		if (!tmp)
1156cd6a6acSopenharmony_ci			goto out;
1166cd6a6acSopenharmony_ci		if (!strncmp(tmp + 1, SELINUXFS" ", strlen(SELINUXFS)+1)) {
1176cd6a6acSopenharmony_ci			*tmp = '\0';
1186cd6a6acSopenharmony_ci			break;
1196cd6a6acSopenharmony_ci		}
1206cd6a6acSopenharmony_ci	}
1216cd6a6acSopenharmony_ci
1226cd6a6acSopenharmony_ci	/* If we found something, dup it */
1236cd6a6acSopenharmony_ci	if (num > 0)
1246cd6a6acSopenharmony_ci		verify_selinuxmnt(p);
1256cd6a6acSopenharmony_ci
1266cd6a6acSopenharmony_ci      out:
1276cd6a6acSopenharmony_ci	free(buf);
1286cd6a6acSopenharmony_ci	if (fp)
1296cd6a6acSopenharmony_ci		fclose(fp);
1306cd6a6acSopenharmony_ci	return;
1316cd6a6acSopenharmony_ci}
1326cd6a6acSopenharmony_ci
1336cd6a6acSopenharmony_civoid fini_selinuxmnt(void)
1346cd6a6acSopenharmony_ci{
1356cd6a6acSopenharmony_ci	free(selinux_mnt);
1366cd6a6acSopenharmony_ci	selinux_mnt = NULL;
1376cd6a6acSopenharmony_ci}
1386cd6a6acSopenharmony_ci
1396cd6a6acSopenharmony_ci
1406cd6a6acSopenharmony_civoid set_selinuxmnt(const char *mnt)
1416cd6a6acSopenharmony_ci{
1426cd6a6acSopenharmony_ci	selinux_mnt = strdup(mnt);
1436cd6a6acSopenharmony_ci}
1446cd6a6acSopenharmony_ci
1456cd6a6acSopenharmony_ci
1466cd6a6acSopenharmony_cistatic void init_lib(void) __attribute__ ((constructor));
1476cd6a6acSopenharmony_cistatic void init_lib(void)
1486cd6a6acSopenharmony_ci{
1496cd6a6acSopenharmony_ci	selinux_page_size = sysconf(_SC_PAGE_SIZE);
1506cd6a6acSopenharmony_ci	init_selinuxmnt();
1516cd6a6acSopenharmony_ci#ifndef ANDROID
1526cd6a6acSopenharmony_ci	has_selinux_config = (access(SELINUXCONFIG, F_OK) == 0);
1536cd6a6acSopenharmony_ci#endif
1546cd6a6acSopenharmony_ci}
1556cd6a6acSopenharmony_ci
1566cd6a6acSopenharmony_cistatic void fini_lib(void) __attribute__ ((destructor));
1576cd6a6acSopenharmony_cistatic void fini_lib(void)
1586cd6a6acSopenharmony_ci{
1596cd6a6acSopenharmony_ci	fini_selinuxmnt();
1606cd6a6acSopenharmony_ci}
161