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