Re: [PATCH] Continued cleanup of open_cred_file and fixed a potential security risk. The parsing for values has been moved to its own function and is a bit cleaner. Temporary buffers are zeroed out before being freed to ensure passwords/credentials aren't left in released memory.
Jeff Layton <[email protected]> Sun, 25 Apr 2010 09:39:01 -0400
| Newsgroups | gmane.linux.file-systems.cifs |
|---|---|
| Message-ID | <[email protected]> |
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Sat, 24 Apr 2010 19:21:08 -0400 Scott Lovenberg <[email protected]> wrote: Maybe try not to put all of the description on the subject line. You can use multiple lines and it makes it a little tougher to import the patch. > Signed-off-by: Scott Lovenberg <[email protected]> > --- > mount.cifs.c | 141 ++++++++++++++++++++++++++++++++++------------------------ > 1 files changed, 83 insertions(+), 58 deletions(-) > > diff --git a/mount.cifs.c b/mount.cifs.c > index 97dae82..09d6351 100644 > --- a/mount.cifs.c > +++ b/mount.cifs.c > @@ -121,6 +121,14 @@ > */ > #define CIFS_SETUID_FLAGS (MS_NOSUID|MS_NODEV) > > +/* > + * Values for parsing a credentials file. > + */ > +#define CRED_UNPARSEABLE 0 > +#define CRED_USER 1 > +#define CRED_PASS 2 > +#define CRED_DOM 4 > + > /* struct for holding parsed mount info for use by privleged process */ > struct parsed_mount_info { > unsigned long flags; > @@ -511,20 +519,43 @@ toggle_dac_capability(int writable, int enable) > #endif /* HAVE_LIBCAP */ > #endif /* HAVE_LIBCAP_NG */ > > -/* > - * Null terminate string at first '\n' > - */ > -static void null_terminate_endl(char* source) > +static void null_terminate_endl(char *source) > { > - char* newline = strchr(source, '\n'); > + char *newline = strchr(source, '\n'); > if (newline) > *newline = '\0'; > } > > - > +/* > + * Parse a line from the credentials file. Changes target to first > + * character after '=' on 'line' and returns the value type of the line > + * Returns CRED_UNPARSEABLE on failure or if either parameter is NULL. > + */ > +static int parse_cred_line(char *line, char **target) > +{ > + if (line == NULL || target == NULL) > + goto parsing_err; > + > + /* position target at first char of value */ > + *target = strchr(line, '='); > + if (!target) ^^^^^^^^^^^^ Should be: if (!*target) ...right? > + goto parsing_err; > + *target += 1; > + > + /* tell the caller which value target points to */ > + if (strncasecmp("user", line, 4) == 0) > + return CRED_USER; > + if (strncasecmp("pass", line, 4) == 0) > + return CRED_PASS; > + if (strncasecmp("dom", line, 3) == 0) > + return CRED_DOM; > + > + parsing_err: > + return CRED_UNPARSEABLE; > +} > > static int open_cred_file(char *file_name, > - struct parsed_mount_info *parsed_info) > + struct parsed_mount_info *parsed_info) > { > char *line_buf; > char *temp_val; > @@ -535,30 +566,29 @@ static int open_cred_file(char *file_name, > > i = toggle_dac_capability(0, 1); > if (i) > - return i; > - > + goto return_i; > + > i = access(file_name, R_OK); > if (i) { > toggle_dac_capability(0, 0); > - return i; > + goto return_i; > } > > fs = fopen(file_name, "r"); > if (fs == NULL) { > toggle_dac_capability(0, 0); > - return errno; > + i = errno; > + goto return_i; > } > > i = toggle_dac_capability(0, 0); > - if (i) { > - fclose(fs); > - return i; > - } > - > - line_buf = (char *)malloc(line_buf_size); > + if(i) > + goto return_i; > + > + line_buf = (char*)malloc(line_buf_size); > if (line_buf == NULL) { > - fclose(fs); > - return EX_SYSERR; > + i = EX_SYSERR; > + goto return_i; > } > > /* parse line from credentials file */ > @@ -570,47 +600,42 @@ static int open_cred_file(char *file_name, > } > null_terminate_endl(line_buf); > > - /* parse user */ > - if (strncasecmp("user", line_buf + i, 4) == 0) { > - temp_val = strchr(line_buf + i, '='); > - if (temp_val) { > - /* go past equals sign */ > - temp_val++; > - parsed_info->got_user = 1; > - strlcpy(parsed_info->username, temp_val, > - sizeof(parsed_info->username)); > - } > - } > - > - /* parse password */ > - else if (strncasecmp("pass", line_buf + i, 4) == 0) { > - temp_val = strchr(line_buf + i, '='); > - if (!temp_val) > - continue; > - ++temp_val; > - i = set_password(parsed_info, temp_val); > - if (i) > - return i; > - } > - > - /* parse domain */ > - else if (strncasecmp("dom", line_buf + i, 3) == 0) { > - temp_val = strchr(line_buf + i, '='); > - if (temp_val) { > - /* go past equals sign */ > - temp_val++; > - if (parsed_info->verboseflag) > - fprintf(stderr, "\nDomain %s\n", > - temp_val); > - strlcpy(parsed_info->domain, temp_val, > - sizeof(parsed_info->domain)); > - } > + /* parse next token */ > + switch(parse_cred_line(line_buf + i, &temp_val)) { > + case CRED_USER: > + parse_username(temp_val, parsed_info); I think you should check the return value from parse_username here too. > + break; > + case CRED_PASS: > + if ((i = set_password(parsed_info, temp_val))) > + goto return_i; > + break; > + case CRED_DOM: > + if (parsed_info->verboseflag) > + fprintf(stderr, "\nDomain %s\n", > + temp_val); > + strlcpy(parsed_info->domain, temp_val, > + sizeof(parsed_info->domain)); > + break; > + case CRED_UNPARSEABLE: > + if (parsed_info->verboseflag) > + fprintf(stderr, > + "Credential formatted incorrectly: %s", > + temp_val); > + break; > } > - > } > - fclose(fs); > - SAFE_FREE(line_buf); > - return 0; > + > + i = 0; > + /* jump point for errors */ > + return_i: ^^^^^^^^ Minor nit: typically labels are flush to the left, and the code below shouldn't be indented as much. > + if (fs != NULL) > + fclose(fs); > + > + /* make sure passwords are scrubbed from memory */ > + if (line_buf != NULL) > + memset(line_buf, 0, line_buf_size); > + SAFE_FREE(line_buf); > + return i; > } > > static int There's also some trailing whitespace and other formatting errors that checkpatch complained about, and the patch didn't apply cleanly to the head git commit. I cleaned up most of these problems and will send a revised patch in a bit. - -- Jeff Layton <[email protected]> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iEYEARECAAYFAkvURfsACgkQyP0gxQMdzIAcNgCgkfVOVnYMIeLgxjnmDlFjURTV sCQAn2gmgmkJ80WDfc/UDwyY5uhqNbsJ =iFIZ -----END PGP SIGNATURE-----