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