1#include <unistd.h>
2#include <fcntl.h>
3#include <string.h>
4#include <stdlib.h>
5#include <errno.h>
6#include <ctype.h>
7#include <stdio.h>
8#include <stdio_ext.h>
9#include <dlfcn.h>
10#include <sys/statvfs.h>
11#include <sys/vfs.h>
12#include <stdint.h>
13#include <limits.h>
14#include <sys/mount.h>
15
16#include "dso.h"
17#include "policy.h"
18#include "selinux_internal.h"
19#include "setrans_internal.h"
20
21char *selinux_mnt = NULL;
22int selinux_page_size = 0;
23int obj_class_compat = 1;
24
25int has_selinux_config = 0;
26
27/* Verify the mount point for selinux file system has a selinuxfs.
28   If the file system:
29   * Exist,
30   * Is mounted with an selinux file system,
31   * The file system is read/write
32   * then set this as the default file system.
33*/
34static int verify_selinuxmnt(const char *mnt)
35{
36	struct statfs sfbuf;
37	int rc;
38
39	do {
40		rc = statfs(mnt, &sfbuf);
41	} while (rc < 0 && errno == EINTR);
42	if (rc == 0) {
43		if ((uint32_t)sfbuf.f_type == (uint32_t)SELINUX_MAGIC) {
44			struct statvfs vfsbuf;
45			rc = statvfs(mnt, &vfsbuf);
46			if (rc == 0) {
47				if (!(vfsbuf.f_flag & ST_RDONLY)) {
48					set_selinuxmnt(mnt);
49				}
50				return 0;
51			}
52		}
53	}
54
55	return -1;
56}
57
58int selinuxfs_exists(void)
59{
60	int exists = 0, mnt_rc = 0;
61	FILE *fp = NULL;
62	char *buf = NULL;
63	size_t len;
64	ssize_t num;
65
66	mnt_rc = mount("proc", "/proc", "proc", 0, 0);
67
68	fp = fopen("/proc/filesystems", "r");
69	if (!fp) {
70		exists = 1; /* Fail as if it exists */
71		goto out;
72	}
73
74	__fsetlocking(fp, FSETLOCKING_BYCALLER);
75
76	num = getline(&buf, &len, fp);
77	while (num != -1) {
78		if (strstr(buf, SELINUXFS)) {
79			exists = 1;
80			break;
81		}
82		num = getline(&buf, &len, fp);
83	}
84
85	free(buf);
86	fclose(fp);
87
88out:
89#ifndef MNT_DETACH
90#define MNT_DETACH 2
91#endif
92	if (mnt_rc == 0)
93		umount2("/proc", MNT_DETACH);
94
95	return exists;
96}
97hidden_def(selinuxfs_exists)
98
99static void init_selinuxmnt(void)
100{
101	char *buf=NULL, *p;
102	FILE *fp=NULL;
103	size_t len;
104	ssize_t num;
105
106	if (selinux_mnt)
107		return;
108
109	if (verify_selinuxmnt(SELINUXMNT) == 0) return;
110
111	if (verify_selinuxmnt(OLDSELINUXMNT) == 0) return;
112
113	/* Drop back to detecting it the long way. */
114	if (!selinuxfs_exists())
115		goto out;
116
117	/* At this point, the usual spot doesn't have an selinuxfs so
118	 * we look around for it */
119	fp = fopen("/proc/mounts", "r");
120	if (!fp)
121		goto out;
122
123	__fsetlocking(fp, FSETLOCKING_BYCALLER);
124	while ((num = getline(&buf, &len, fp)) != -1) {
125		char *tmp;
126		p = strchr(buf, ' ');
127		if (!p)
128			goto out;
129		p++;
130		tmp = strchr(p, ' ');
131		if (!tmp)
132			goto out;
133		if (!strncmp(tmp + 1, SELINUXFS" ", strlen(SELINUXFS)+1)) {
134			*tmp = '\0';
135			break;
136		}
137	}
138
139	/* If we found something, dup it */
140	if (num > 0)
141		verify_selinuxmnt(p);
142
143      out:
144	free(buf);
145	if (fp)
146		fclose(fp);
147	return;
148}
149
150void fini_selinuxmnt(void)
151{
152	free(selinux_mnt);
153	selinux_mnt = NULL;
154}
155
156hidden_def(fini_selinuxmnt)
157
158void set_selinuxmnt(const char *mnt)
159{
160	selinux_mnt = strdup(mnt);
161}
162
163hidden_def(set_selinuxmnt)
164
165static void init_lib(void) __attribute__ ((constructor));
166static void init_lib(void)
167{
168	selinux_page_size = sysconf(_SC_PAGE_SIZE);
169	init_selinuxmnt();
170#ifndef ANDROID
171	has_selinux_config = (access(SELINUXCONFIG, F_OK) == 0);
172#endif
173}
174
175static void fini_lib(void) __attribute__ ((destructor));
176static void fini_lib(void)
177{
178	fini_selinuxmnt();
179}
180