Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: modified incorrect_password() function

...

Wiki Markup
This noncompliant code example shows the {{incorrect_password()}} function, which is called during identification and authentication if the specified user is not found, or the password is incorrect, to display an error message. The function accepts the name of the user as a null-terminated byte string referenced by {{user}}.  This is an excellent example of data that originates from an untrusted, unauthenticated user.  The function constructs an error message which is then output to {{stderr}} using the C99 standard {{fprintf()}} function  \[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\].

Code Block
bgColor#FFCCCC
#define MSG_FORMAT "%s cannot be authenticated.\n"

void incorrect_password(const char *user) { 
  int ret;
  /* user names are restricted to 256 characters or less */ 
  static const char *msg_formatMSG_FORMAT[] = MSG_FORMAT; "%s cannot be authenticated.\n"; 
  size_t len = strlen(user) + sizeof(MSG_FORMAT); 
  char *msg = (char *)malloc(len); 
  if (!msg == NULL) { 
    /* handleHandle error condition */ 
  } 
  int ret = snprintf(msg, len, msg_format, user); 
  if (ret < 0 || ) /* Handle error */ ;
  else if (ret >= len) {\
    /* Handle truncated erroroutput */ ;
  }
  fprintf(stderr, msg); 
  free(msg);
  msg = NULL;
} 

The incorrect_password() function calculates the size of the message, allocates dynamic storage, and then constructs the message in the allocated memory using the snprintf() function. The addition operations are not checked for integer overflow because the length of the string referenced by user is known to be have a length of 256 or less. Because the %s characters are replaced by the string referenced by user in the call to snprintf(), one less byte is required to store the resulting string and terminating NULL-byte character. This is a common idiom for displaying the same message in multiple locations or when the message is difficult to build. The resulting code contains a format-string vulnerability, however, because the msg includes untrusted user input and is passed as the format-string argument in the call to fprintf().

...

This compliant solution fixes the problem by replacing the fprintf() call with a call to fputs(), which does not treat msg like a format string, but outputs it to stderr as is.

Code Block
bgColor#ccccff
#define MSG_FORMAT "%s cannot be authenticated.\n"

void incorrect_password(const char *user) { 
  int ret;
  /* user names are restricted to 256 characters or less */ 
  static const char *msg_formatMSG_FORMAT[] = MSG_FORMAT; "%s cannot be authenticated.\n"; 
  size_t len = strlen(user) + sizeof(msgMSG_formatFORMAT); 
  char *msg = (char *)malloc(len); 
  if (!msg == NULL) { 
    /* Handle error condition */ 
  } 
  int ret = snprintf(msg, len, msg_format, user); 
  if (ret < 0 || ) /* Handle error */ ;
  else if (ret >= len) {\
    /* Handle errortruncated output */ ;
  }
  if (fputs(msg, stderr) == EOF) {
    /* Handle error */
  }
  free(msg);
  msg = NULL;
} 

Compliant Solution (fprintf())

...