I am managing an OAuth implementation for Puredata (Pd), which is written in C. OAuth can accept RSA keys, but Pd cannot send messages with newlines, so placing private keys will come as a list of strings with spaces acting as separators.
Basically this function looks into the different parts of the block and adds either a newline or a space at the end, such that -----BEGIN PRIVATE KEY-----
will end up in one line, while A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d 7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ
will end up in separate ones.
Some functions, types and constants, that are used here: MAXPDSTRING
: the maximum length of a string, t_atom
: message part, atom_string(*t_atom src, *char dest, size_t max_length)
: convert src to dest with a max_length.
static char *string_create(size_t *const newl, const size_t strl) {
char *gen;
/* newl is not the length of the string, but the memory size */
(*newl) = 1 + strl;
gen = getbytes((*newl) * sizeof(char));
if (gen == NULL) {
pd_error(0, "not enough memory.");
return gen;
}
return memset(gen, 0x00, (*newl));
}
static void oauth_set_rsa_key(t_oauth *const oauth, const int argc, t_atom *const argv) {
char temp[MAXPDSTRING];
size_t rsa_key_len = 1; /* Accomodate NULL terminator */
short use_newline = 0;
for (int i = 1; i < argc; i++) {
atom_string(argv + i, temp, MAXPDSTRING);
rsa_key_len += strlen(temp) + 1; /* Each section + 1 for space or newline */
}
oauth->oauth.rsa_key = string_create(&oauth->oauth.rsa_key_len, rsa_key_len);
for (int i = 1; i < argc; i++) {
atom_string(argv + i, temp, MAXPDSTRING);
if (strncmp(temp, "-----", 5) == 0 && strlen(oauth->oauth.rsa_key) > 1) {
/* Cutoff trailing space and add newline */
memset(oauth->oauth.rsa_key + strlen(oauth->oauth.rsa_key) - 1, 0x00, 1);
strcat(oauth->oauth.rsa_key, "\n");
use_newline = 0;
}
if (strlen(temp) >= 5 && strncmp(temp + strlen(temp) - 5, "-----", 5) == 0) {
use_newline = 1;
}
strcat(oauth->oauth.rsa_key, temp);
if (i < argc - 1) {
if (use_newline == 1) {
/* This gets flagged as possible buffer overflow */
strcat(oauth->oauth.rsa_key, "\n");
} else {
/* This also */
strcat(oauth->oauth.rsa_key, " ");
}
}
}
}
Static analysis in Coverity does flag strcat(oauth->oauth.rsa_key, "\n");
as possible buffer overflow, but I cannot see the possible overflow here. What am I missing?
I could not provoke a buffer overflow by arbitrary data containing any combinations of -
, spaces or anything.