mountd: fix is_subdirectory to understand '/'
Subsystems (2)
PATCH 1/1 mountd: fix is_subdirectory to understand '/'
The is_subdirectory() function checks if a given 'child' is a subdirectory of the given 'parent'.
However it always fails if 'parent' == "/" (because 'child' doesn't begin with 'parent' followed by "/").
So change is_subdirectory() to special-case "/".
subexport() also tests if one directory is a subdirectory of the other, and contains the same bug. So change it to use is_subdirectory().
Finally, move is_subdirectory() and related path_matches() and export_matches() earlier in the file to avoid a forward-reference.
This patch fixes a bug wherein if you export "/" with 'crossmnt', the crossmnt flag is ineffective and you can only access the root filesystem, not any descendants.
utils/mountd/cache.c +25 -23
@@ -343,6 +343,30 @@ static char *next_mnt(void **v, char *p)return me->mnt_dir; } +static int is_subdirectory (char *child,char *parent) +{ +size_t l =strlen (parent); + +if (strcmp (parent,"/" ) ==0 ) +return 1 ; + +return strcmp (child, parent) ==0 + || (strncmp (child, parent, l) ==0 && child[l] =='/' ); +} + +static int path_matches (nfs_export *exp,char *path) +{ +if (exp->m_export.e_flags &NFSEXP_CROSSMOUNT ) +return is_subdirectory (path, exp->m_export.e_path); +return strcmp (path, exp->m_export.e_path) ==0 ; +} + +static int +export_matches (nfs_export *exp,char *dom,char *path,struct addrinfo *ai) +{ +return path_matches (exp, path) &&client_matches (exp, dom, ai); +} +/* True iff e1 is a child of e2 and e2 has crossmnt set: */ static bool subexport (struct exportent *e1,struct exportent *e2) {
@@ -350,8 +374,7 @@ static bool subexport(struct exportent *e1, struct exportent *e2)size_t l2 =strlen (p2);return e2->e_flags &NFSEXP_CROSSMOUNT - &&strncmp (p1, p2, l2) ==0 - && p1[l2] =='/' ; + &&is_subdirectory (p1, p2); }struct parsed_fsid {
@@ -752,27 +775,6 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *exreturn qword_eol (f); } -static int is_subdirectory (char *child,char *parent) -{ -size_t l =strlen (parent); - -return strcmp (child, parent) ==0 - || (strncmp (child, parent, l) ==0 && child[l] =='/' ); -} - -static int path_matches (nfs_export *exp,char *path) -{ -if (exp->m_export.e_flags &NFSEXP_CROSSMOUNT ) -return is_subdirectory (path, exp->m_export.e_path); -return strcmp (path, exp->m_export.e_path) ==0 ; -} - -static int -export_matches (nfs_export *exp,char *dom,char *path,struct addrinfo *ai) -{ -return path_matches (exp, path) &&client_matches (exp, dom, ai); -} -static nfs_export *lookup_export (char *dom,char *path,struct addrinfo *ai) {
Quoted 7 lines · NeilBrown
The
is_subdirectory()function checks if a given 'child' is a subdirectory of the given 'parent'.
However it always fails if 'parent' == "/" (because 'child' doesn't begin with 'parent' followed by "/").So change
is_subdirectory()to special-case "/".
Might be slightly more elegant to deal with this as a case of a parent directory with a terminating "/" rather than as a special case, and that might make this a little more robust. E.g.:
size_t l = strlen(parent); while (l && parent[l-1] == '/') l--; return (l <= strlen(child)) && strncmp(parent, child, l) == 0 && (child[l] == '/' || child[l] == '\0');
?
--b.
Quoted 86 lines
subexport()also tests if one directory is a subdirectory of the other, and contains the same bug. So change it to useis_subdirectory().Finally, move
is_subdirectory()and relatedpath_matches()andexport_matches()earlier in the file to avoid a forward-reference.This patch fixes a bug wherein if you export "/" with 'crossmnt', the crossmnt flag is ineffective and you can only access the root filesystem, not any descendants.
Signed-off-by NeilBrown <[email protected]>utils/mountd/cache.c +25
-23@@ -343,6 +343,30 @@ static char *next_mnt(void **v, char *p)return me->mnt_dir; } +static int is_subdirectory (char *child,char *parent) +{ +size_t l =strlen (parent); + +if (strcmp (parent,"/" ) ==0 ) +return 1 ; + +return strcmp (child, parent) ==0 + || (strncmp (child, parent, l) ==0 && child[l] =='/' ); +} + +static int path_matches (nfs_export *exp,char *path) +{ +if (exp->m_export.e_flags &NFSEXP_CROSSMOUNT ) +return is_subdirectory (path, exp->m_export.e_path); +return strcmp (path, exp->m_export.e_path) ==0 ; +} + +static int +export_matches (nfs_export *exp,char *dom,char *path,struct addrinfo *ai) +{ +return path_matches (exp, path) &&client_matches (exp, dom, ai); +} +/* True iff e1 is a child of e2 and e2 has crossmnt set: */ static bool subexport (struct exportent *e1,struct exportent *e2) {@@ -350,8 +374,7 @@ static bool subexport(struct exportent *e1, struct exportent *e2)size_t l2 =strlen (p2);return e2->e_flags &NFSEXP_CROSSMOUNT - &&strncmp (p1, p2, l2) ==0 - && p1[l2] =='/' ; + &&is_subdirectory (p1, p2); }struct parsed_fsid {@@ -752,27 +775,6 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *exreturn qword_eol (f); } -static int is_subdirectory (char *child,char *parent) -{ -size_t l =strlen (parent); - -return strcmp (child, parent) ==0 - || (strncmp (child, parent, l) ==0 && child[l] =='/' ); -} - -static int path_matches (nfs_export *exp,char *path) -{ -if (exp->m_export.e_flags &NFSEXP_CROSSMOUNT ) -return is_subdirectory (path, exp->m_export.e_path); -return strcmp (path, exp->m_export.e_path) ==0 ; -} - -static int -export_matches (nfs_export *exp,char *dom,char *path,struct addrinfo *ai) -{ -return path_matches (exp, path) &&client_matches (exp, dom, ai); -} -static nfs_export *lookup_export (char *dom,char *path,struct addrinfo *ai) {
Quoted 11 lines · NeilBrown
The
is_subdirectory()function checks if a given 'child' is a subdirectory of the given 'parent'.
However it always fails if 'parent' == "/" (because 'child' doesn't begin with 'parent' followed by "/").So change
is_subdirectory()to special-case "/".
subexport()also tests if one directory is a subdirectory of the other, and contains the same bug. So change it to useis_subdirectory().
Quoted 8 lines
Finally, move
is_subdirectory()and relatedpath_matches()andexport_matches()earlier in the file to avoid a forward-reference.This patch fixes a bug wherein if you export "/" with 'crossmnt', the crossmnt flag is ineffective and you can only access the root filesystem, not any descendants.
Signed-off-by NeilBrown <[email protected]>
Committed...
steved.
Quoted 75 lines
utils/mountd/cache.c +25
-23@@ -343,6 +343,30 @@ static char *next_mnt(void **v, char *p)return me->mnt_dir; } +static int is_subdirectory (char *child,char *parent) +{ +size_t l =strlen (parent); + +if (strcmp (parent,"/" ) ==0 ) +return 1 ; + +return strcmp (child, parent) ==0 + || (strncmp (child, parent, l) ==0 && child[l] =='/' ); +} + +static int path_matches (nfs_export *exp,char *path) +{ +if (exp->m_export.e_flags &NFSEXP_CROSSMOUNT ) +return is_subdirectory (path, exp->m_export.e_path); +return strcmp (path, exp->m_export.e_path) ==0 ; +} + +static int +export_matches (nfs_export *exp,char *dom,char *path,struct addrinfo *ai) +{ +return path_matches (exp, path) &&client_matches (exp, dom, ai); +} +/* True iff e1 is a child of e2 and e2 has crossmnt set: */ static bool subexport (struct exportent *e1,struct exportent *e2) {@@ -350,8 +374,7 @@ static bool subexport(struct exportent *e1, struct exportent *e2)size_t l2 =strlen (p2);return e2->e_flags &NFSEXP_CROSSMOUNT - &&strncmp (p1, p2, l2) ==0 - && p1[l2] =='/' ; + &&is_subdirectory (p1, p2); }struct parsed_fsid {@@ -752,27 +775,6 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *exreturn qword_eol (f); } -static int is_subdirectory (char *child,char *parent) -{ -size_t l =strlen (parent); - -return strcmp (child, parent) ==0 - || (strncmp (child, parent, l) ==0 && child[l] =='/' ); -} - -static int path_matches (nfs_export *exp,char *path) -{ -if (exp->m_export.e_flags &NFSEXP_CROSSMOUNT ) -return is_subdirectory (path, exp->m_export.e_path); -return strcmp (path, exp->m_export.e_path) ==0 ; -} - -static int -export_matches (nfs_export *exp,char *dom,char *path,struct addrinfo *ai) -{ -return path_matches (exp, path) &&client_matches (exp, dom, ai); -} -static nfs_export *lookup_export (char *dom,char *path,struct addrinfo *ai) {