summaryrefslogtreecommitdiff
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
parenta018f8273fed6549d2fc529e5bb58cba11869ffb (diff)
downloadenlightenment-596def7806fe63fe9339eba8b25cc86d7ce80b34.tar.gz
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.
-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 c243d276e5..c696f0e8c1 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)
}
static Eina_Bool
-_mkdir(const char *path, uid_t u, gid_t g)
+_mkdir(const char *path)
{
mode_t um;
int ret, e;
@@ -85,112 +85,168 @@ _mkdir(const char *path, uid_t u, gid_t g)
ERR("Path is not a dir [%s]\n", path);
return EINA_FALSE;
}
+ if (st.st_uid != 0) return EINA_FALSE;
+ if (st.st_gid != 0) return EINA_FALSE;
}
+ else return EINA_FALSE;
}
}
- if (chown(path, u, g) != 0)
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_store_is_triplet(const char *mnt, char *dirs[3])
+{ // check that mnt is "/media/xxx/yyy" and nothing more or less. No special
+ // chars or escapes like \ or * oro ; or { or [ etc.
+ // no ../ or ./ or empty path elements. then break up the 3 elements
+ // into dirs[] is we return true
+ const char *s, *s2;
+
+ dirs[0] = NULL;
+ dirs[1] = NULL;
+ dirs[2] = NULL;
+
+ // phase one sanity check
+ if (!mnt) goto err;
+ if (mnt[0] != '/') goto err;
+ for (s = mnt; *s; s++)
{
- ERR("Can't own [%s] to uid.gid %i.%i\n", path, u, g);
- return EINA_FALSE;
+ if ((*s == '\\') ||
+ (*s == '(') || (*s == '$') || (*s <= '*') || (*s == '`') ||
+ (*s == ';') || (*s == '<') || (*s == '>') || (*s == '?') ||
+ (*s >= '{') ||
+ ((*s >= '[') && (*s <= '^')))
+ goto err;
}
+ if ((strstr(mnt, "/..")) || (strstr(mnt, "/./")) || (strstr(mnt, "//")))
+ goto err;
+
+ // phase 2 - break up into 3 dir components
+ s = mnt + 1;
+ if (*s == '\0') goto err;
+ s2 = strchr(s, '/');
+ if (!s2) goto err;
+ dirs[0] = malloc(s2 - s + 1);
+ if (!dirs[0]) goto err;
+ memcpy(dirs[0], s, s2 - s);
+ dirs[0][s2 - s] = 0;
+ s = s2 + 1;
+
+ if (*s == '\0') goto err;
+ s2 = strchr(s, '/');
+ if (!s2) goto err;
+ dirs[1] = malloc(s2 - s + 1);
+ if (!dirs[1]) goto err;
+ memcpy(dirs[1], s, s2 - s);
+ dirs[1][s2 - s] = 0;
+ s = s2 + 1;
+
+ if (*s == '\0') goto err;
+ s2 = strchr(s, '/');
+ if (s2) goto err; // different - if there is another / - even trailing
+ for (s2 = s; *s2 != '\0'; s2++); // s2 - walk to nul byte end
+ dirs[1] = malloc(s2 - s + 1);
+ if (!dirs[1]) goto err;
+ memcpy(dirs[1], s, s2 - s);
+ dirs[1][s2 - s] = 0;
+ s = s2 + 1;
+
return EINA_TRUE;
+err:
+ free(dirs[0]);
+ free(dirs[1]);
+ free(dirs[2]);
+ dirs[0] = NULL;
+ dirs[1] = NULL;
+ dirs[2] = NULL;
+ return EINA_FALSE;
}
static Eina_Bool
_store_mount_verify(const char *mnt)
{
- char *tmnt, *p, *pp;
- const char *s;
- struct stat st;
+ char *dirs[3] = { NULL, NULL, NULL };
+ char *tmp = NULL;
// XXX: we should use /run/media - possibly make this adapt
- if (!(!strncmp(mnt, "/media/", 7))) return EINA_FALSE;
- for (s = mnt; *s; s++)
- {
- if (*s == '\\') return EINA_FALSE;
- if ((*s <= '*') || (*s == '`') || (*s == ';') || (*s == '<') ||
- (*s == '>') || (*s == '?') || (*s >= '{') ||
- ((*s >= '[') && (*s <= '^')))
- return EINA_FALSE;
- }
- if (strstr(mnt, "/..")) return EINA_FALSE;
- if (strstr(mnt, "/./")) return EINA_FALSE;
- if (strstr(mnt, "//")) return EINA_FALSE;
- if (stat(mnt, &st) == 0)
+ if (!mnt) return EINA_FALSE;
+ if (!(!strncmp(mnt, "/media/", 7))) goto err;
+ if (!_store_is_triplet(mnt, dirs)) goto err;
+ tmp = malloc(strlen(mnt) + 1);
+ if (!tmp)
{
- if (!S_ISDIR(st.st_mode)) return EINA_FALSE;
- if (st.st_uid != 0) return EINA_FALSE;
- if (st.st_gid != 0) return EINA_FALSE;
- }
- tmnt = strdup(mnt);
- if (tmnt)
- {
- // /media <- owned by root
- p = strchr(tmnt + 1, '/');
- if (!p) goto malformed;
- *p = '\0';
- if (!_mkdir(tmnt, 0, 0)) goto err;
- *p = '/';
-
- // /media/username <- owned by root
- p = strchr(p + 1, '/');
- if (!p) goto malformed;
- *p = '\0';
- pp = strrchr(tmnt, '/');
- if (!pp) goto err;
- // check if dir name is name of user...
- if (strcmp(p + 1, user_name)) goto err;
- if (!_mkdir(tmnt, 0, 0)) goto err;
- *p = '/';
-
- // /media/username/dirname <- owned by root
- if (!_mkdir(tmnt, 0, 0)) goto err;
- free(tmnt);
+ free(dirs[0]);
+ free(dirs[1]);
+ free(dirs[2]);
+ return EINA_FALSE;
}
+ // 2nd path must be username
+ if (!!strcmp(dirs[1], user_name)) goto err;
+
+ tmp[0] = 0;
+ strcat(tmp, "/");
+ strcat(tmp, dirs[0]);
+ if (!_mkdir(tmp)) goto err;
+
+ strcat(tmp, "/");
+ strcat(tmp, dirs[1]);
+ if (!_mkdir(tmp)) goto err;
+
+ strcat(tmp, "/");
+ strcat(tmp, dirs[2]);
+ if (!_mkdir(tmp)) goto err;
+
+ free(tmp);
+ free(dirs[0]);
+ free(dirs[1]);
+ free(dirs[2]);
return EINA_TRUE;
-malformed:
- ERR("Malformed mount point [%s]\n", mnt);
err:
- free(tmnt);
+ ERR("Malformed mount point or create error [%s]\n", mnt);
+ free(tmp);
+ free(dirs[0]);
+ free(dirs[1]);
+ free(dirs[2]);
return EINA_FALSE;
}
static Eina_Bool
_store_umount_verify(const char *mnt)
{
- char *tmnt, *p;
- const char *s;
+ char *dirs[3] = { NULL, NULL, NULL };
+ char *tmp = NULL;
struct stat st;
// XXX: we should use /run/media - possibly make this adapt
- if (!(!strncmp(mnt, "/media/", 7))) return EINA_FALSE;
- for (s = mnt; *s; s++)
+ if (!mnt) return EINA_FALSE;
+ if (!(!strncmp(mnt, "/media/", 7))) goto err;
+ if (!_store_is_triplet(mnt, dirs)) goto err;
+ tmp = malloc(strlen(mnt) + 1);
+ if (!tmp)
{
- if (*s == '\\') return EINA_FALSE;
- if ((*s <= '*') || (*s == '`') || (*s == ';') || (*s == '<') ||
- (*s == '>') || (*s == '?') || (*s >= '{') ||
- ((*s >= '[') && (*s <= '^')))
- return EINA_FALSE;
+ free(dirs[0]);
+ free(dirs[1]);
+ free(dirs[2]);
+ return EINA_FALSE;
}
- if (strstr(mnt, "/..")) return EINA_FALSE;
- if (strstr(mnt, "/./")) return EINA_FALSE;
- if (strstr(mnt, "//")) return EINA_FALSE;
- if (stat(mnt, &st) != 0) return EINA_FALSE;
- if (!S_ISDIR(st.st_mode)) return EINA_FALSE;
- tmnt = strdup(mnt);
- if (!tmnt) return EINA_FALSE;
- p = strchr(tmnt + 7, '/');
- if (!p) goto err;
- *p = '\0';
- if (stat(tmnt, &st) != 0) goto err;
+ // 2nd path must be username
+ if (!!strcmp(dirs[1], user_name)) goto err;
+ if (stat(mnt, &st) != 0) goto err;
+ if (!S_ISDIR(st.st_mode)) goto err;
if (st.st_uid != 0) goto err;
if (st.st_gid != 0) goto err;
- p = tmnt + 7; // after /media/ (so username)
- if (strcmp(p + 1, user_name)) goto err; // not user named dir
- free(tmnt);
+
+ free(tmp);
+ free(dirs[0]);
+ free(dirs[1]);
+ free(dirs[2]);
return EINA_TRUE;
err:
- free(tmnt);
+ ERR("Malformed umount point [%s]\n", mnt);
+ free(tmp);
+ free(dirs[0]);
+ free(dirs[1]);
+ free(dirs[2]);
return EINA_FALSE;
}