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 
21 char *selinux_mnt = NULL;
22 int selinux_page_size = 0;
23 int obj_class_compat = 1;
24 
25 int 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 */
verify_selinuxmnt(const char * mnt)34 static 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 
selinuxfs_exists(void)58 int 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 
88 out:
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 }
hidden_def(selinuxfs_exists)97 hidden_def(selinuxfs_exists)
98 
99 static 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 
fini_selinuxmnt(void)150 void fini_selinuxmnt(void)
151 {
152 	free(selinux_mnt);
153 	selinux_mnt = NULL;
154 }
155 
hidden_def(fini_selinuxmnt)156 hidden_def(fini_selinuxmnt)
157 
158 void set_selinuxmnt(const char *mnt)
159 {
160 	selinux_mnt = strdup(mnt);
161 }
162 
163 hidden_def(set_selinuxmnt)
164 
165 static void init_lib(void) __attribute__ ((constructor));
init_lib(void)166 static 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 
175 static void fini_lib(void) __attribute__ ((destructor));
fini_lib(void)176 static void fini_lib(void)
177 {
178 	fini_selinuxmnt();
179 }
180