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