|
Message-Id: <20230331105206.2267169-1-matthias.goergens@gmail.com> Date: Fri, 31 Mar 2023 18:52:06 +0800 From: Matthias Goergens <matthias.goergens@...il.com> To: musl@...ts.openwall.com Cc: Matthias Goergens <matthias.goergens@...il.com> Subject: [PATCH v3] mntent: deal with escaped whitespace in mtab and fstab >From glibc's documentation: > Since fields in the mtab and fstab files are separated by whitespace, > octal escapes are used to represent the characters space (\040), > tab (\011), newline (\012), and backslash (\\) in those files when they > occur in one of the four strings in a mntent structure. The > routines addmntent() and getmntent() will convert from string > representation to escaped representation and back. When converting > from escaped representation, the sequence \134 is also converted to a > backslash. This fixes the issue reported in https://www.openwall.com/lists/musl/2021/12/14/1 --- Notes: This is yet another version that incorporates more suggestions by Szabolcs Nagy and rofl0r I also adapted and ran the glibc tests, which you can find at https://github.com/bminor/glibc/tree/master/misc as `tst-mntent*.c` src/misc/mntent.c | 79 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 7 deletions(-) diff --git a/src/misc/mntent.c b/src/misc/mntent.c index d404fbe3..266d23be 100644 --- a/src/misc/mntent.c +++ b/src/misc/mntent.c @@ -3,6 +3,7 @@ #include <mntent.h> #include <errno.h> #include <limits.h> +#include "stdio_impl.h" static char *internal_buf; static size_t internal_bufsize; @@ -20,6 +21,44 @@ int endmntent(FILE *f) return 1; } +static char* decode(char* buf) { + char* src = buf; + char* dest = buf; + while (1) { + char* next_src = __strchrnul(src, '\\'); + int offset = next_src - src; + memmove(dest, src, offset); + src = next_src; + dest += offset; + + if(*src == '\0') { + *dest = *src; + return buf; + } + src++; + + const char *replacements = + "\040" "040" "\0" // space + "\011" "011" "\0" // tab + "\012" "012" "\0" // newline + "\134" "134" "\0" // backslash + "\\" "\\" "\0" + // Fallback for unrecognized escape sequence, + // copy literally: + "\\" ""; + while(1) { + char c = *replacements++; + size_t n = strlen(replacements); + if (strncmp(src, replacements, n) == 0) { + *dest++ = c; + src += n; + break; + } + replacements += n+1; + } + } +} + struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) { int n[8], use_internal = (linebuf == SENTINEL); @@ -55,10 +94,10 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle linebuf[n[5]] = 0; linebuf[n[7]] = 0; - mnt->mnt_fsname = linebuf+n[0]; - mnt->mnt_dir = linebuf+n[2]; - mnt->mnt_type = linebuf+n[4]; - mnt->mnt_opts = linebuf+n[6]; + mnt->mnt_fsname = decode(linebuf+n[0]); + mnt->mnt_dir = decode(linebuf+n[2]); + mnt->mnt_type = decode(linebuf+n[4]); + mnt->mnt_opts = decode(linebuf+n[6]); return mnt; } @@ -69,12 +108,38 @@ struct mntent *getmntent(FILE *f) return getmntent_r(f, &mnt, SENTINEL, 0); } +static int escape_and_write_string(FILE *f, const char* str) +{ + const char* replace_me = "\040\011\012\\"; + char c; + int error_occured = 0; + while(str && !error_occured && (c = *str++) != 0) { + if (NULL == strchr(replace_me, c)) { + error_occured = putc_unlocked(c, f) < 0; + } else { + error_occured = + (0 > putc_unlocked('\\', f)) + || (0 > putc_unlocked('0' + (3 & (c >> 6)), f)) + || (0 > putc_unlocked('0' + (7 & (c >> 3)), f)) + || (0 > putc_unlocked('0' + (7 & (c >> 0)), f)); + } + } + return error_occured || (0 > putc_unlocked('\t', f)); +} + int addmntent(FILE *f, const struct mntent *mnt) { if (fseek(f, 0, SEEK_END)) return 1; - return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", - mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, - mnt->mnt_freq, mnt->mnt_passno) < 0; + FLOCK(f); + int error_occured = + escape_and_write_string(f, mnt->mnt_fsname) + || escape_and_write_string(f, mnt->mnt_dir) + || escape_and_write_string(f, mnt->mnt_type) + || escape_and_write_string(f, mnt->mnt_opts) + || (0 > fprintf(f, "%d\t%d\n", + mnt->mnt_freq, mnt->mnt_passno)); + FUNLOCK(f); + return error_occured; } char *hasmntopt(const struct mntent *mnt, const char *opt) -- 2.40.0
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.