diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2020-09-09 13:05:58 +0200 |
---|---|---|
committer | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2020-10-12 12:53:34 +0200 |
commit | a207516776769404dfa8ae89003efba1004a55df (patch) | |
tree | 46c06918427badaab11d5326cbb70e1d7c99cdba /security/tomoyo | |
parent | Linux 5.9 (diff) | |
download | linux-a207516776769404dfa8ae89003efba1004a55df.tar.xz linux-a207516776769404dfa8ae89003efba1004a55df.zip |
tomoyo: Loosen pathname/domainname validation.
Since commit e2dc9bf3f5275ca3 ("umd: Transform fork_usermode_blob into
fork_usermode_driver") started calling execve() on a program written in
a local mount which is not connected to mount tree,
tomoyo_realpath_from_path() started returning a pathname in
"$fsname:/$pathname" format which violates TOMOYO's domainname rule that
it must start with "<$namespace>" followed by zero or more repetitions of
pathnames which start with '/'.
Since $fsname must not contain '.' since commit 79c0b2df79eb56fc ("add
filesystem subtype support"), tomoyo_correct_path() can recognize a token
which appears '/' before '.' appears (e.g. proc:/self/exe ) as a pathname
while rejecting a token which appears '.' before '/' appears (e.g.
exec.realpath="/bin/bash" ) as a condition parameter.
Therefore, accept domainnames which contain pathnames which do not start
with '/' but contain '/' before '.' (e.g. <kernel> tmpfs:/bpfilter_umh ).
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/util.c | 29 |
1 files changed, 23 insertions, 6 deletions
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index eba0b3395851..a40abb0b91ee 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -143,6 +143,8 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param) return pos; } +static bool tomoyo_correct_path2(const char *filename, const size_t len); + /** * tomoyo_get_domainname - Read a domainname from a line. * @@ -157,10 +159,10 @@ const struct tomoyo_path_info *tomoyo_get_domainname char *pos = start; while (*pos) { - if (*pos++ != ' ' || *pos++ == '/') + if (*pos++ != ' ' || + tomoyo_correct_path2(pos, strchrnul(pos, ' ') - pos)) continue; - pos -= 2; - *pos++ = '\0'; + *(pos - 1) = '\0'; break; } param->data = pos; @@ -514,6 +516,22 @@ bool tomoyo_correct_word(const char *string) } /** + * tomoyo_correct_path2 - Check whether the given pathname follows the naming rules. + * + * @filename: The pathname to check. + * @len: Length of @filename. + * + * Returns true if @filename follows the naming rules, false otherwise. + */ +static bool tomoyo_correct_path2(const char *filename, const size_t len) +{ + const char *cp1 = memchr(filename, '/', len); + const char *cp2 = memchr(filename, '.', len); + + return cp1 && (!cp2 || (cp1 < cp2)) && tomoyo_correct_word2(filename, len); +} + +/** * tomoyo_correct_path - Validate a pathname. * * @filename: The pathname to check. @@ -523,7 +541,7 @@ bool tomoyo_correct_word(const char *string) */ bool tomoyo_correct_path(const char *filename) { - return *filename == '/' && tomoyo_correct_word(filename); + return tomoyo_correct_path2(filename, strlen(filename)); } /** @@ -545,8 +563,7 @@ bool tomoyo_correct_domain(const unsigned char *domainname) if (!cp) break; - if (*domainname != '/' || - !tomoyo_correct_word2(domainname, cp - domainname)) + if (!tomoyo_correct_path2(domainname, cp - domainname)) return false; domainname = cp + 1; } |