summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2020-05-28 11:24:32 +0100
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2020-05-28 11:24:32 +0100
commit596def7806fe63fe9339eba8b25cc86d7ce80b34 (patch)
treef31a95d60cbe439c41440113f30824b666445521 /src
parenta018f8273fed6549d2fc529e5bb58cba11869ffb (diff)
e system - storage - improve mount/umount code to enforce simple std
all dirs owned by root - so can't be exploited. this code is not acessible at this point so no actual issues. it still needs testing. until other work is done it won't be tested yet. fixes T8671 further comments on umount check.
Diffstat (limited to 'src')
-rw-r--r--src/bin/system/e_system_storage.c206
1 files changed, 131 insertions, 75 deletions
diff --git a/src/bin/system/e_system_storage.c b/src/bin/system/e_system_storage.c
index c243d276e..c696f0e8c 100644
--- a/src/bin/system/e_system_storage.c
+++ b/src/bin/system/e_system_storage.c
@@ -57,7 +57,7 @@ _store_uuid_verify(const char *dev)
57} 57}
58 58
59static Eina_Bool 59static Eina_Bool
60_mkdir(const char *path, uid_t u, gid_t g) 60_mkdir(const char *path)
61{ 61{
62 mode_t um; 62 mode_t um;
63 int ret, e; 63 int ret, e;
@@ -85,112 +85,168 @@ _mkdir(const char *path, uid_t u, gid_t g)
85 ERR("Path is not a dir [%s]\n", path); 85 ERR("Path is not a dir [%s]\n", path);
86 return EINA_FALSE; 86 return EINA_FALSE;
87 } 87 }
88 if (st.st_uid != 0) return EINA_FALSE;
89 if (st.st_gid != 0) return EINA_FALSE;
88 } 90 }
91 else return EINA_FALSE;
89 } 92 }
90 } 93 }
91 if (chown(path, u, g) != 0) 94 return EINA_TRUE;
95}
96
97static Eina_Bool
98_store_is_triplet(const char *mnt, char *dirs[3])
99{ // check that mnt is "/media/xxx/yyy" and nothing more or less. No special
100 // chars or escapes like \ or * oro ; or { or [ etc.
101 // no ../ or ./ or empty path elements. then break up the 3 elements
102 // into dirs[] is we return true
103 const char *s, *s2;
104
105 dirs[0] = NULL;
106 dirs[1] = NULL;
107 dirs[2] = NULL;
108
109 // phase one sanity check
110 if (!mnt) goto err;
111 if (mnt[0] != '/') goto err;
112 for (s = mnt; *s; s++)
92 { 113 {
93 ERR("Can't own [%s] to uid.gid %i.%i\n", path, u, g); 114 if ((*s == '\\') ||
94 return EINA_FALSE; 115 (*s == '(') || (*s == '$') || (*s <= '*') || (*s == '`') ||
116 (*s == ';') || (*s == '<') || (*s == '>') || (*s == '?') ||
117 (*s >= '{') ||
118 ((*s >= '[') && (*s <= '^')))
119 goto err;
95 } 120 }
121 if ((strstr(mnt, "/..")) || (strstr(mnt, "/./")) || (strstr(mnt, "//")))
122 goto err;
123
124 // phase 2 - break up into 3 dir components
125 s = mnt + 1;
126 if (*s == '\0') goto err;
127 s2 = strchr(s, '/');
128 if (!s2) goto err;
129 dirs[0] = malloc(s2 - s + 1);
130 if (!dirs[0]) goto err;
131 memcpy(dirs[0], s, s2 - s);
132 dirs[0][s2 - s] = 0;
133 s = s2 + 1;
134
135 if (*s == '\0') goto err;
136 s2 = strchr(s, '/');
137 if (!s2) goto err;
138 dirs[1] = malloc(s2 - s + 1);
139 if (!dirs[1]) goto err;
140 memcpy(dirs[1], s, s2 - s);
141 dirs[1][s2 - s] = 0;
142 s = s2 + 1;
143
144 if (*s == '\0') goto err;
145 s2 = strchr(s, '/');
146 if (s2) goto err; // different - if there is another / - even trailing
147 for (s2 = s; *s2 != '\0'; s2++); // s2 - walk to nul byte end
148 dirs[1] = malloc(s2 - s + 1);
149 if (!dirs[1]) goto err;
150 memcpy(dirs[1], s, s2 - s);
151 dirs[1][s2 - s] = 0;
152 s = s2 + 1;
153
96 return EINA_TRUE; 154 return EINA_TRUE;
155err:
156 free(dirs[0]);
157 free(dirs[1]);
158 free(dirs[2]);
159 dirs[0] = NULL;
160 dirs[1] = NULL;
161 dirs[2] = NULL;
162 return EINA_FALSE;
97} 163}
98 164
99static Eina_Bool 165static Eina_Bool
100_store_mount_verify(const char *mnt) 166_store_mount_verify(const char *mnt)
101{ 167{
102 char *tmnt, *p, *pp; 168 char *dirs[3] = { NULL, NULL, NULL };
103 const char *s; 169 char *tmp = NULL;
104 struct stat st;
105 170
106 // XXX: we should use /run/media - possibly make this adapt 171 // XXX: we should use /run/media - possibly make this adapt
107 if (!(!strncmp(mnt, "/media/", 7))) return EINA_FALSE; 172 if (!mnt) return EINA_FALSE;
108 for (s = mnt; *s; s++) 173 if (!(!strncmp(mnt, "/media/", 7))) goto err;
109 { 174 if (!_store_is_triplet(mnt, dirs)) goto err;
110 if (*s == '\\') return EINA_FALSE; 175 tmp = malloc(strlen(mnt) + 1);
111 if ((*s <= '*') || (*s == '`') || (*s == ';') || (*s == '<') || 176 if (!tmp)
112 (*s == '>') || (*s == '?') || (*s >= '{') ||
113 ((*s >= '[') && (*s <= '^')))
114 return EINA_FALSE;
115 }
116 if (strstr(mnt, "/..")) return EINA_FALSE;
117 if (strstr(mnt, "/./")) return EINA_FALSE;
118 if (strstr(mnt, "//")) return EINA_FALSE;
119 if (stat(mnt, &st) == 0)
120 { 177 {
121 if (!S_ISDIR(st.st_mode)) return EINA_FALSE; 178 free(dirs[0]);
122 if (st.st_uid != 0) return EINA_FALSE; 179 free(dirs[1]);
123 if (st.st_gid != 0) return EINA_FALSE; 180 free(dirs[2]);
124 } 181 return EINA_FALSE;
125 tmnt = strdup(mnt);
126 if (tmnt)
127 {
128 // /media <- owned by root
129 p = strchr(tmnt + 1, '/');
130 if (!p) goto malformed;
131 *p = '\0';
132 if (!_mkdir(tmnt, 0, 0)) goto err;
133 *p = '/';
134
135 // /media/username <- owned by root
136 p = strchr(p + 1, '/');
137 if (!p) goto malformed;
138 *p = '\0';
139 pp = strrchr(tmnt, '/');
140 if (!pp) goto err;
141 // check if dir name is name of user...
142 if (strcmp(p + 1, user_name)) goto err;
143 if (!_mkdir(tmnt, 0, 0)) goto err;
144 *p = '/';
145
146 // /media/username/dirname <- owned by root
147 if (!_mkdir(tmnt, 0, 0)) goto err;
148 free(tmnt);
149 } 182 }
183 // 2nd path must be username
184 if (!!strcmp(dirs[1], user_name)) goto err;
185
186 tmp[0] = 0;
187 strcat(tmp, "/");
188 strcat(tmp, dirs[0]);
189 if (!_mkdir(tmp)) goto err;
190
191 strcat(tmp, "/");
192 strcat(tmp, dirs[1]);
193 if (!_mkdir(tmp)) goto err;
194
195 strcat(tmp, "/");
196 strcat(tmp, dirs[2]);
197 if (!_mkdir(tmp)) goto err;
198
199 free(tmp);
200 free(dirs[0]);
201 free(dirs[1]);
202 free(dirs[2]);
150 return EINA_TRUE; 203 return EINA_TRUE;
151malformed:
152 ERR("Malformed mount point [%s]\n", mnt);
153err: 204err:
154 free(tmnt); 205 ERR("Malformed mount point or create error [%s]\n", mnt);
206 free(tmp);
207 free(dirs[0]);
208 free(dirs[1]);
209 free(dirs[2]);
155 return EINA_FALSE; 210 return EINA_FALSE;
156} 211}
157 212
158static Eina_Bool 213static Eina_Bool
159_store_umount_verify(const char *mnt) 214_store_umount_verify(const char *mnt)
160{ 215{
161 char *tmnt, *p; 216 char *dirs[3] = { NULL, NULL, NULL };
162 const char *s; 217 char *tmp = NULL;
163 struct stat st; 218 struct stat st;
164 219
165 // XXX: we should use /run/media - possibly make this adapt 220 // XXX: we should use /run/media - possibly make this adapt
166 if (!(!strncmp(mnt, "/media/", 7))) return EINA_FALSE; 221 if (!mnt) return EINA_FALSE;
167 for (s = mnt; *s; s++) 222 if (!(!strncmp(mnt, "/media/", 7))) goto err;
223 if (!_store_is_triplet(mnt, dirs)) goto err;
224 tmp = malloc(strlen(mnt) + 1);
225 if (!tmp)
168 { 226 {
169 if (*s == '\\') return EINA_FALSE; 227 free(dirs[0]);
170 if ((*s <= '*') || (*s == '`') || (*s == ';') || (*s == '<') || 228 free(dirs[1]);
171 (*s == '>') || (*s == '?') || (*s >= '{') || 229 free(dirs[2]);
172 ((*s >= '[') && (*s <= '^'))) 230 return EINA_FALSE;
173 return EINA_FALSE;
174 } 231 }
175 if (strstr(mnt, "/..")) return EINA_FALSE; 232 // 2nd path must be username
176 if (strstr(mnt, "/./")) return EINA_FALSE; 233 if (!!strcmp(dirs[1], user_name)) goto err;
177 if (strstr(mnt, "//")) return EINA_FALSE; 234 if (stat(mnt, &st) != 0) goto err;
178 if (stat(mnt, &st) != 0) return EINA_FALSE; 235 if (!S_ISDIR(st.st_mode)) goto err;
179 if (!S_ISDIR(st.st_mode)) return EINA_FALSE;
180 tmnt = strdup(mnt);
181 if (!tmnt) return EINA_FALSE;
182 p = strchr(tmnt + 7, '/');
183 if (!p) goto err;
184 *p = '\0';
185 if (stat(tmnt, &st) != 0) goto err;
186 if (st.st_uid != 0) goto err; 236 if (st.st_uid != 0) goto err;
187 if (st.st_gid != 0) goto err; 237 if (st.st_gid != 0) goto err;
188 p = tmnt + 7; // after /media/ (so username) 238
189 if (strcmp(p + 1, user_name)) goto err; // not user named dir 239 free(tmp);
190 free(tmnt); 240 free(dirs[0]);
241 free(dirs[1]);
242 free(dirs[2]);
191 return EINA_TRUE; 243 return EINA_TRUE;
192err: 244err:
193 free(tmnt); 245 ERR("Malformed umount point [%s]\n", mnt);
246 free(tmp);
247 free(dirs[0]);
248 free(dirs[1]);
249 free(dirs[2]);
194 return EINA_FALSE; 250 return EINA_FALSE;
195} 251}
196 252