I'm stumped. I'm working on a small data server for a school assignment, that's supposed to be communicating over sockets for this iteration. Most of it's working but I can't quite figure out what valgrind is complaining about, but here's what it all says.
valgrind says;
Conditional jump or move depends on uninitialised value(s)
at 0x4C2ABD9: strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x510F0EF: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.17)
by 0x4078C9: netreq::cread() (netreq.c:120)
by 0x402585: event(void*) (simpleclient.C:166)
gdb is receiving a SIGPIPE seemingly at the same point in the process.
Here's the function that it is complaining about;
string netreq::cread()
{
char buf[255];
if(read(fd,buf, 255) < 0)
cout << "I cants read dat right, sorry"<<endl;
return (string)buf; //this is line 120 in netreq.c
}
thoughts? anyone fixed something similar? i've tried quite a few things but no luck yet.
read() does not terminate the array by \0 to indicate the end. You should do it by yourself.
int len;
if ((len = read(fd, buf, 255)) < 0) {
/* ... */
} else {
buf[len] = '\0';
}
return string(buf);
Related
I use Crypto++ (libcrypto++ 1.11) to embed JWT in my application. I made methods to sign and verify messages with CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256> algorithm (with secp256r1 curve). Tokens for verification can come from the outer world, so I need to verify token contents (textual data) signature knowing the public key.
The problem is that Crypto++ can cause SegFault on invalid signatures, which gives me a lot of pain in my web server.
I hoped that signatures in BER format (default serialization format in the library) have fixed length, so all I need is to compare the length of signature with some constant. However, I found out larger contents enables larger signatures, so a deeper approach is needed.
bool ES256Verifier::Verify(const std::string& data,
const std::string& signature) {
bool result = false;
try {
CryptoPP::StringSource ss(
signature + data, true,
new CryptoPP::SignatureVerificationFilter(
verifier_,
new CryptoPP::ArraySink((byte*)&result, sizeof(result))));
} catch (const CryptoPP::BERDecodeErr& err) {
LOG_WARNING() << "Signature `" << signature << "` has invalid (non-BER) format";
} catch (const CryptoPP::Exception& ex) {
LOG_WARNING() << "Signature verification has failed: " << ex.what();
}
return result;
}
Verifier verifier_ is initialized correctly (and verifies tokens successfully apart from SegFaults), but given data = "" and signature = "", for example, I always get SegFault:
__memmove_avx_unaligned_erms 0x00007fb4b9da6b38
CryptoPP::ArraySink::Put2(unsigned char const*, unsigned long, int, bool) 0x00007fb4ba414fb2
CryptoPP::BufferedTransformation::ChannelPut2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned char const*, unsigned long, int, bool) 0x00007fb4ba3acedc
CryptoPP::StringStore::CopyRangeTo2(CryptoPP::BufferedTransformation&, unsigned long long&, unsigned long long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) const 0x00007fb4ba414e02
CryptoPP::BufferedTransformation::Peek(unsigned char*, unsigned long) const 0x00007fb4ba3ad74a
CryptoPP::Integer::Decode(CryptoPP::BufferedTransformation&, unsigned long, CryptoPP::Integer::Signedness) 0x00007fb4ba45885c
CryptoPP::Integer::Decode(unsigned char const*, unsigned long, CryptoPP::Integer::Signedness) 0x00007fb4ba458c16
CryptoPP::DL_VerifierBase<CryptoPP::ECPPoint>::InputSignature pubkey.h:1560
CryptoPP::SignatureVerificationFilter::LastPut(unsigned char const*, unsigned long) 0x00007fb4ba4159a0
CryptoPP::FilterWithBufferedInput::PutMaybeModifiable(unsigned char*, unsigned long, int, bool, bool) 0x00007fb4ba418107
CryptoPP::BufferedTransformation::ChannelPut2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned char const*, unsigned long, int, bool) 0x00007fb4ba3acedc
CryptoPP::BufferedTransformation::TransferMessagesTo2(CryptoPP::BufferedTransformation&, unsigned int&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) 0x00007fb4ba3ad8fa
CryptoPP::BufferedTransformation::TransferAllTo2(CryptoPP::BufferedTransformation&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) 0x00007fb4ba3adb21
CryptoPP::SourceTemplate<CryptoPP::StringStore>::PumpAll2 filters.h:1238
CryptoPP::Source::PumpAll filters.h:1182
CryptoPP::Source::SourceInitialize filters.h:1215
CryptoPP::StringSource::StringSource filters.h:1271
jwt::signature::algorithm::ES256Verifier::Verify es256_verifier.cpp:40
ES256_SignatureTest_Test::TestBody es256_test.cpp:29
...
So, is there a way to look at the data and signature and decide if this particular combination is going to cause SegFault due to invalid signature length?
Here's some sample code to determine the signature length using the Field Element, Signer and Verifier. The first output prints the element length and r||s length because r||s is the signature in P1363 format.
The second and third output just print the result of SignatureLength(). Your program should reject a signature shorter than SignatureLength(). There is no sense in even trying to verify a short signature since it is no good.
Note well: this only work for the DL_* signature schemes (based on discrete logs). It does not apply to TF_* signature schemes (based on trapdoor functions).
#include "cryptlib.h"
#include "eccrypto.h"
#include "osrng.h"
#include "oids.h"
#include <iostream>
int main(int argc, char* argv[])
{
using namespace CryptoPP;
AutoSeededRandomPool prng;
///// Element
DL_GroupParameters_EC<ECP> params(ASN1::secp256r1());
unsigned int elemLength = params.GetCurve().GetField().MaxElementByteLength();
std::cout << "Element length: " << elemLength << std::endl;
std::cout << "r||s length: " << 2*elemLength << std::endl;
///// Signer
ECDSA<ECP, SHA256>::Signer signer;
signer.AccessKey().Initialize(prng, params);
unsigned int signerLength = signer.SignatureLength();
std::cout << "Signer signature length: " << signerLength << std::endl;
///// Verifier
ECDSA<ECP, SHA256>::Verifier verifier(signer);
unsigned int verifierLength = verifier.SignatureLength();
std::cout << "Verifier signature length: " << verifierLength << std::endl;
return 0;
}
Running the program results in the following.
$ ./test.exe
Element length: 32
r||s length: 64
Signer signature length: 64
Verifier signature length: 64
And if you switch curves to ASN1::secp521r1(), then running the program results in the following.
$ ./test.exe
Element length: 66
r||s length: 132
Signer signature length: 132
Verifier signature length: 132
For some reason Valgrind seems to give an invalid write at a line where the ifstream.read is called (in the searchInFile function). gdb seems to segfault at the same line but I can't figure out the problem. If a read function is being called, how is there a write operation taking place?
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
#define FILENAME "./test.dat"
using namespace std;
struct record
{
long long int phoneNumber;
char name[10];
char address[75];
};
int searchInFile(long long int phoneNo)
{
/*
Search if a record with the given phone no.
exists in the file. Returns the number of
records before the required record. Returns
-1 if no such record exists.
*/
int ctr = 0;
record * buffer = NULL;
ifstream file(FILENAME, ios::binary);
while(file.read( reinterpret_cast<char*>(buffer), sizeof(record)))
{
if(buffer->phoneNumber == phoneNo)
{
file.close();
return(ctr);
}
ctr++;
}
file.close();
if(buffer->phoneNumber == phoneNo)
return(ctr);
return(-1);
}
void displayRecord(long long int phoneNo)
{
/*
Displays the record with given phone no.
*/
int location = searchInFile(phoneNo);
record * buffer = NULL;
if(location == -1)
cout << "Invalid Number! No such record exists!" << endl;
else
{
ifstream file(FILENAME, ios::binary);
cout << "Reading Error Code: " << file.read(reinterpret_cast<char*>(buffer), sizeof(record));
cout << "Phone Number: " << buffer->phoneNumber << endl;
cout << "Name: " << buffer->name << endl;
cout << "Address: " << buffer->address << endl;
file.close();
}
}
void saveRecord(record toSave)
{
/*
Saves a new record to file
*/
ofstream ofile(FILENAME, ios::app | ios::binary);
//ofile.seekp(0, ios::end);
ofile.write( reinterpret_cast<char*>(&toSave), sizeof(record));
ofile.close();
}
int main()
{
record test = {(long long int)9988776655, "Debug", "Address of Debugger"};
saveRecord(test);
displayRecord((long long int) 9988776655);
return(0);
}
Here is the Valgrind and gdb output for it:
Syscall param write(buf) points to uninitialised byte(s)
at 0x543B870: __write_nocancel (syscall-template.S:81)
by 0x4EB18D5: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE9A77: std::basic_filebuf<char, std::char_traits<char> >::_M_convert_to_external(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EEA4D2: std::basic_filebuf<char, std::char_traits<char> >::overflow(int) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE9CA2: std::basic_filebuf<char, std::char_traits<char> >::_M_terminate_output() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE9D4A: std::basic_filebuf<char, std::char_traits<char> >::close() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EEBB4C: std::basic_ofstream<char, std::char_traits<char> >::close() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4011A5: saveRecord(record) (test.cpp:84)
by 0x4012F1: main (test.cpp:91)
Address 0x5a1b31d is 93 bytes inside a block of size 8,192 alloc'd
at 0x4C2B8A8: operator new[](unsigned long) (vg_replace_malloc.c:423)
by 0x4EE98AB: std::basic_filebuf<char, std::char_traits<char> >::_M_allocate_internal_buffer() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE9EC1: std::basic_filebuf<char, std::char_traits<char> >::open(char const*, std::_Ios_Openmode) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EEB747: std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(char const*, std::_Ios_Openmode) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x40117E: saveRecord(record) (test.cpp:81)
by 0x4012F1: main (test.cpp:91)
Invalid write of size 1
at 0x4ED338E: std::basic_streambuf<char, std::char_traits<char> >::xsgetn(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE8D0D: std::basic_filebuf<char, std::char_traits<char> >::xsgetn(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EB4CAA: std::istream::read(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x400EDD: searchInFile(long long) (test.cpp:30)
by 0x400FAA: displayRecord(long long) (test.cpp:55)
by 0x401300: main (test.cpp:92)
Address 0x0 is not stack'd, malloc'd or (recently) free'd
Process terminating with default action of signal 11 (SIGSEGV)
Access not within mapped region at address 0x0
at 0x4ED338E: std::basic_streambuf<char, std::char_traits<char> >::xsgetn(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE8D0D: std::basic_filebuf<char, std::char_traits<char> >::xsgetn(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EB4CAA: std::istream::read(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x400EDD: searchInFile(long long) (test.cpp:30)
by 0x400FAA: displayRecord(long long) (test.cpp:55)
by 0x401300: main (test.cpp:92)
If you believe this happened as a result of a stack
overflow in your program's main thread (unlikely but
possible), you can try to increase the size of the
main thread stack using the --main-stacksize= flag.
The main thread stack size used in this run was 8388608.
HEAP SUMMARY:
in use at exit: 8,760 bytes in 2 blocks
total heap usage: 4 allocs, 2 frees, 17,520 bytes allocated
LEAK SUMMARY:
definitely lost: 0 bytes in 0 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 8,760 bytes in 2 blocks
suppressed: 0 bytes in 0 blocks
ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
Note that the test.dat file was deleted before each run.
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b7338e in std::basic_streambuf<char, std::char_traits<char> >::xsgetn(char*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt
#0 0x00007ffff7b7338e in std::basic_streambuf<char, std::char_traits<char> >::xsgetn(char*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00007ffff7b88d0e in std::basic_filebuf<char, std::char_traits<char> >::xsgetn(char*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2 0x00007ffff7b54cab in std::istream::read(char*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x0000000000400ede in searchInFile (phoneNo=9988776655) at test.cpp:30
#4 0x0000000000400fab in displayRecord (phoneNo=9988776655) at test.cpp:55
#5 0x0000000000401301 in main () at test.cpp:92
The only thing I can think of is that buffer is being written into over here, but that doesn't get me anywhere.
The read() method is writing the information it has read into your buffer,
and I suspect valgrind thinks this write is invalid,
so start looking at how your buffer is allocated.
In this case valgrind is clearly correct. You need to allocate memory to buffer for it to put the file contents into.
eg
record * buffer = new record;
buffer is null. you do not allocate any storage to read into it, passing wrong size (it should be 0, not sizeof(record)) and dereference it later causing Undefined Behavior. write and read in valgrind refer to memory access, not to file read or write.
I am having a bizarre error in assigning values in an array of strings. It assigns two or three intermittently and then crashes.
I am trying to implement a simple unsorted dictionary like structure using two parallel arrays(one of strings and one of integers)
Here is where in the code I think the fault is occurring.
std::ifstream infile1("out1.tmp");
std::string word;
while (getline(infile1,word)){
std::istringstream iss(word);
printf("stream created\n");
if (!(iss >> bookone.keys[i]))
break;
i++;
}
bookone is a dictionary object that has the public fields:keys and index. Even if I move the variable assignment into the class it errors in the same way.
The part that confuses me the most is that it appears to work the first few iterations.
strace provides this:
open("out1.tmp", O_RDONLY) = 5
read(5, "This\nEtext\nfile\nis\npresented\nby\n"..., 8191) = 8191
write(1, "stream created\n", 15stream created
) = 15
write(1, "stream created\n", 15stream created
) = 15
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xd36ff8} ---
+++ killed by SIGSEGV +++
[1] 16430 segmentation fault strace ./book macbeth.txt othello.txt
and valgrind gives me a bunch of these:
==16499== Invalid read of size 8
==16499== at 0x4EAB634: std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==16499== by 0x401673: main (in /home/luna/sauce/books/book)
==16499== Address 0x5a00ca8 is 24 bytes before a block of size 568 alloc'd
==16499== at 0x4C28C20: malloc (vg_replace_malloc.c:296)
==16499== by 0x56C106C: __fopen_internal (iofopen.c:73)
==16499== by 0x401555: main (in /home/luna/sauce/books/book)
I keep getting unusual segmentation faults inside libc.so.6 on a CentOS 6.4 64bit machine. This is the backtrace that gdb most often reports:
0x00007ffff60d9b3f in memcpy () from /lib64/libc.so.6
(gdb) backtrace
#0 0x00007ffff60d9b3f in memcpy () from /lib64/libc.so.6
#1 0x00000000004b6a6b in std::string::_S_construct<__gnu_cxx::__normal_iterator<char*, std::string> > ()
#2 0x00000000004b719b in NewsMAIL::SMTPClient::receiveLine(std::basic_string<char, std::char_traits<char>, std::allocator<char> >*) ()
#3 0x00000000004b776f in NewsMAIL::SMTPClient::handleResponse() ()
And this is the code in question that seems to trigger the segfault:
bool SMTPClient::receiveLine(std::string* Line)
{
static std::string Buffer;
std::string::iterator iter;
while((iter = std::find(Buffer.begin(), Buffer.end(), '\n')) == Buffer.end()) {
char Bucket[MAX_BUCKET_SIZE + 1] = {};
int BytesRecv = read(m_Socket, Bucket, MAX_BUCKET_SIZE);
//Did we get a socket error?
if(BytesRecv == -1) {
//This is generally considered a bad thing..
*Line = Buffer;
Buffer = std::string("");
return false;
}
Bucket[BytesRecv] = 0;
Buffer += Bucket;
}
*Line = std::string(Buffer.begin(), iter);
Buffer = std::string(iter + 1, Buffer.end());
return true;
}
Sometimes it works 100% without any failures so it is not everytime unfortunately.
The above code is a slightly modified version of this: https://stackoverflow.com/a/1584620/3133245
Does anyone have any thoughts on why this might be happening? I am compiling with g++ 4.7.2
Thanks!
Nate
Using a static variable (Buffer) is not thread safe. Could cause a crash.
You should add a check that Line is not NULL.
BTW, the line Buffer = std::string(""); could be Buffer.clear();
In addition to the static variable issue, are you sure that the data that is received contains no embedded NULL characters?
If the resulting Buffer contains embedded NULL bytes, this line will not do the correct concatenation using the += operator:
Buffer += Bucket;
The += overload assumes that Bucket is a c-style string, thus the first NULL byte encountered will be used as the terminator when the concatenation occurs.
Taking a glance at the code, it would seem to be the case that if the Bucket does indeed contain embedded NULL chracters, doing the above concatenation could result in your "iter" iterator pointing passed the end() of Buffer (in those lines after the while() loop).
Instead, you can do this:
Buffer.append(Bucket, BytesRecv)
This guarantees that all characters that Bucket is addressing will be concatenated onto the existing string.
But before making any changes, make sure you know exactly what the issue is, especially since you stated the error doesn't happen very often. Changing around code without first knowing the true cause of the error may just mask the error, thus making it harder to diagnose the real issue.
I'm getting a memory leak from the following function:
int ReadWrite(int socket, char *readfile) {
FILE *rf = NULL;
rf = fopen(readfile, "rb");
fseek(rf, 0, SEEK_END);
int len = ftell(rf);
rewind(rf);
char readbuf[len + 1];
int res = fread(readbuf, len, 1, rf);
readbuf[len + 1] = '\0';
fclose(rf);
while (1) {
int wres = write(socket, readbuf, res);
if (wres == 0) {
cerr << "socket closed prematurely" << endl;
close(socket);
return EXIT_FAILURE;
}
if (res == -1) {
if (errno == EINTR)
continue;
cerr << "socket write failure: " << strerror(errno) << endl;
close(socket);
return EXIT_FAILURE;
}
break;
}
return EXIT_SUCCESS;
}
Valgrind tells me I leak the number of bytes that are in readfile (the actual file, not the name of readfile) through this operation:
Address 0x4c3b67e is 0 bytes after a block of size 14 alloc'd
at 0x4A07C84: operator new[](unsigned long) (vg_replace_malloc.c:363)
What's confusing me is I don't ever use new[] in my code. I checked fopen, ftell, and fread to see if they have hidden "gotcha's" where they call new[] somewhere but didn't find anything in the documentation on cplusplus.com. I've tried all different combinations of new char[]/delete[], malloc/free, and stack-allocated variables (above) but I get the same valgrind message every time. Any ideas? Thanks.
you call
char readbuf[len + 1];
and then later
readbuf[len + 1] = '\0';
wouldn't that overflow the array?
Well, you are declaring your readbuf array with non-constant size (i.e with run-time size). This is formally illegal in C++. Such feature exists in C99, but not in C++. Your code will not even compile in a pedantic C++ compiler. And your question is tagged [C++].
But it is quite possible that your compiler implements this feature as a non-standard extension, and that it creates such arrays through an implicit call to new[]. This is why you get the error message that refers to new[], even though you are not using new[] explicitly.
Of course, it is the compiler's responsibility to deallocate such arrays when they end their lifetime. I suspect that the compiler does all it has to do, but the valgrind is confused by something in compiler's actions, which makes it conclude that it is a memory leak.
Moreover, as others already noted, you are making out of bounds access to your array, which can also lead to absolutely any problems at run-time, including the strange report from valgrind.
I found out the problem actually had to do with the Makefile I was using. Thanks for the insight on my slip-up with the char[] bounds though!