basic_streambuf does not set eof bit when using setp - c++

I'm trying to use a std::ostream backed by a buffer that I own.
When using setp to have the std::basic_streambuf to us my buffer, everything works fine expect that I would have expected the eof to be set when writing more bytes that were allocated for my buffer. The fail and bad bits are being set while the eof bit is not.
Is this the expected behavior?
If not, how can I get the eof bit to be set?
#include <iostream>
#include <streambuf>
template <typename char_type>
struct OStreamBufWrapper : public std::basic_streambuf<char_type, std::char_traits<char_type> >
{
OStreamBufWrapper(char_type* buffer, std::streamsize bufferLength)
{
// set the "put" pointer the start of the buffer and record its length.
this->setp(buffer, buffer + bufferLength);
}
};
int main(int argc, const char * argv[])
{
int bufsize = 10;
char *buf = new char[bufsize];
OStreamBufWrapper<char> ost(buf, bufsize);
std::ostream sb(&ost);
char i = 0;
while ( 1 )
{
sb.write(&i, 1);
if (!sb.good())
{
if (sb.fail())
std::cout << "fail\n";
if (sb.bad())
std::cout << "bad\n";
if (sb.eof())
std::cout << "eof\n";
break;
}
i++;
}
delete [] buf;
return 0;
}

Related

bsoncxx - is there a way to iterate through documents in .bson dump file?

Similarly to how we construct bsoncxx::document::view objects from a buffer with a single binary document, is there a way to extract single documents from a collection in a .bson dump in this framework without having to load them into a DB?
i.e. what works for single document objects
uint8 *buffer; // single bson document
size_t length; // size of buffer
bsoncxx::document::view view(buffer, length);
for (auto elem : view) {
doSomethingWithElem()
}
I'd like to be able to construct a cursor for the whole dump, but without loading it into a collection. Is something like this possible?
Found the solution and it was pretty simple in the end - I utilized the libbson library.
An example of what I used below:
#include <bson.h>
// and other includes
void read_bson() {
bson_reader_t *reader;
const bson_t *doc;
bson_error_t error;
bool eof;
char *path;
reader = bson_reader_new_from_file(path, &error);
if (reader)
{
while ((doc = bson_reader_read(reader, &eof)))
{
const uint8_t *buffer = bson_get_data(doc);
auto view = bsoncxx::document::view(buffer, doc->len);
}
}
}
If you are using mongo-cxx-driver, here is a example for reading bson file dumped by mongodump tool.
#include <iostream>
#include <vector>
#include <fstream>
#include <mongocxx/client.hpp>
#include <mongocxx/uri.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/builder/stream/document.hpp>
#include <sstream>
void parse_one_doc(const char *data, const size_t &length) {
// TODO fill your code
bsoncxx::document::view view((std::uint8_t *) data, length);
std::cout << bsoncxx::to_json(view) << std::endl;
}
int unpack_size(const char *data, size_t position) {
return *(int *) (data + position);
}
bool parse_mongo_dumper(const std::string &data) {
size_t position = 0u, end = data.length() - 1u, data_len = data.size();
size_t obj_size, obj_end;
const char *dc = data.c_str();
while (position < end) {
obj_size = unpack_size(dc, position);
if (position + obj_size > data_len) {
return false;
}
obj_end = position + obj_size;
if (*(dc + obj_end - 1) != '\0') {
return false;
}
parse_one_doc(dc + position, obj_size);
position = obj_end;
}
return true;
}
int main() {
std::string f = "/path/to/data.bson";
// read all data into string
std::ifstream t(f);
std::stringstream buffer;
buffer << t.rdbuf();
std::string s = buffer.str();
// parse bson
parse_mongo_dumper(s);
return 0;
}

Bypassing stack guard- Buffer overflow

I am taking a secure computer system course and I am very new to the subject. I am having a problem with an assignment where I need to get a shell by overflowing the buffer in a target program (target.cc). I cannot make any changes in target.cc but I can send the parameters to the target file.
here is the code.
#include <cstdio>
#include <cstring>
#include <cstdlib>
class SubStringReference
{
const char *start;
size_t len;
public:
SubStringReference(const char *s, size_t l) : start(s), len(l) { }
virtual ~SubStringReference() { }
virtual const char *getStart() const { return start; }
virtual int getLen() const { return len; }
};
void print_sub_string(const SubStringReference& str)
{
char buf[252];
if (str.getLen() >= sizeof buf)
{
// Only copy sizeof(buf) - 1 bytes plus a null
memcpy(buf, str.getStart(), sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0'; // null-terminate
}
else
{
printf("by passed mem check\n");
// The length is less than the size of buf so just string copy.
strcpy(buf, str.getStart());
buf[str.getLen()] = '\0'; // null-terminate to get just the substring
}
puts(buf);
}
int main(int argc, char **argv)
{
if (argc != 4)
{
fprintf(stderr, "Usage: %s STRING START LENGTH\n", argv[0]);
return 1;
}
const char *s = argv[1];
int total_len = strlen(s);
int start = atoi(argv[2]);
int len = atoi(argv[3]);
if (start < 0 || start >= total_len)
{
fputs("start is out of range!\n", stderr);
return 1;
}
if (len < 0 || start + len > total_len)
{
fputs("length is out of range!\n", stderr);
return 1;
}
SubStringReference str(s + start, len);
print_sub_string(str);
return 0;
}
Since this program is stackguard protected the program gets aborted before returning. Is there any other way that i can overflow the buffer and get a shell??
Thanks.
Edit - I am running this on a Qemu arm emulator with g++ compiler
The vulnerability can be exploited by overflowing the buffer and overwriting the address of str.getLen() function so as to point to the shell code. Since the canary check is done at the end of the function, shell is got before the canary is checked.

Reading stdin in c ++ without using getline

I'm trying to convert a program (it's a bridge between vscode and a debug)
This program is written in C#.
It was based on the o vscode-mono-debug
(https://github.com/Microsoft/vscode-mono-debug/blob/master/src/Protocol.cs)
Well,
In C # I can read the standard input as a stream:
byte[] buffer = new byte[BUFFER_SIZE];
Stream inputStream = Console.OpenStandardInput();
_rawData = new ByteBuffer();
while (!_stopRequested) {
var read = await inputStream.ReadAsync(buffer, 0, buffer.Length);
if (read == 0) {
// end of stream
break;
}
if (read > 0) {
_rawData.Append(buffer, read);
ProcessData();
}
}
I try this :
#define _WIN32_WINNT 0x05017
#define BUFFER_SIZE 4096
#include<iostream>
#include<thread>
#include <sstream>
using namespace std;
class ProtocolServer
{
private:
bool _stopRequested;
ostringstream _rawData;
public:
void Start()
{
char buffer[BUFFER_SIZE];
while (!cin.eof())
{
cin.getline(buffer,BUFFER_SIZE);
if (cin.fail())
{
//error
break;
}
else
{
_rawData << buffer;
}
}
}
};
int main()
{
ProtocolServer *server = new ProtocolServer();
server->Start();
return 0;
}
Input:
Content-Length: 261\r\n\r\n{\"command\":\"initialize\",\"arguments\":{\"clientID\":\"vscode\",\"adapterID\":\"advpl\",\"pathFormat\":\"path\",\"linesStartAt1\":true,\"columnsStartAt1\":true,\"supportsVariableType\":true,\"supportsVariablePaging\":true,\"supportsRunInTerminalRequest\":true},\"type\":\"request\",\"seq\":1}
This reads the first 2 lines correctly. Since the protocol does not put \n at the end, it gets stuck in cin.getline in the 3 interaction.
Switching to read() causes it to stay stopped at cin.read (), and does not read anything at all.
I found some similar questions:
StackOverFlow Question
And examples:
Posix_chat_client
But I do not need it to be necessarily asynchronous, but it works on windows and linux.
I'm sorry for my English
Thanks!
What you want is known as unformatted input operations.
Here's a 1:1 translation using just std::iostream. The only "trick" is using and honouring gcount():
std::vector<char> buffer(BUFFER_SIZE);
auto& inputStream = std::cin;
_rawData = std::string {}; // or _rawData.clear(), e.g.
while (!_stopRequested) {
inputStream.read(buffer.data(), buffer.size());
auto read = inputStream.gcount();
if (read == 0) {
// end of stream
break;
}
if (read > 0) {
_rawData.append(buffer.begin(), buffer.begin() + read);
ProcessData();
}
}
I'd personally suggest dropping that read == 0 check in favour of the more accurate:
if (inputStream.eof()) { break; } // end of stream
if (!inputStream.good()) { break; } // failure
Note that !good() also catches eof(), so you can
if (!inputStream.good()) { break; } // failure or end of stream
Live Demo
Live On Coliru
#include <iostream>
#include <vector>
#include <atomic>
struct Foo {
void bar() {
std::vector<char> buffer(BUFFER_SIZE);
auto& inputStream = std::cin;
_rawData = std::string {};
while (!_stopRequested) {
inputStream.read(buffer.data(), buffer.size());
auto read = inputStream.gcount();
if (read > 0) {
_rawData.append(buffer.begin(), buffer.begin() + read);
ProcessData();
}
if (!inputStream.good()) { break; } // failure or end of stream
}
}
protected:
void ProcessData() {
//std::cout << "got " << _rawData.size() << " bytes: \n-----\n" << _rawData << "\n-----\n";
std::cout << "got " << _rawData.size() << " bytes\n";
_rawData.clear();
}
static constexpr size_t BUFFER_SIZE = 128;
std::atomic_bool _stopRequested { false };
std::string _rawData;
};
int main() {
Foo foo;
foo.bar();
}
Prints (e.g. when reading its own source file):
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 92 bytes

C++ / Gcc - Stack smashing when a func returns a struct

I'm actually having troubles with a simple program which is supposed to pass a struct through named pipes.
Here is my main.cpp:
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <string>
#include "NamedPipe.hh"
int main()
{
pid_t pid;
std::string str("test_namedPipe");
NamedPipe pipe(str);
message *msg;
//Initialisation of my struct
msg = (message *)malloc(sizeof(message) + sizeof(char) * 12);
msg->type = 1;
sprintf(msg->str, "Hello World");
//Forking
pid = fork();
if (pid != 0) {
pipe.send(msg);
} else {
message msg_receive = pipe.receive(); //Here is the overflow
std::cout << "type: " << msg_receive.type << " file: " << msg_receive.str << std::endl;
}
return (0);
}
My NamedPipe.cpp:
#include "NamedPipe.hh"
#include <stdio.h>
NamedPipe::NamedPipe(std::string const &_name) : name("/tmp/" + _name) {
mkfifo(name.c_str(), 0666);
// std::cout << "create fifo " << name << std::endl;
}
NamedPipe::~NamedPipe() {
unlink(name.c_str());
}
void NamedPipe::send(message *msg) {
int fd;
int size = sizeof(char) * 12 + sizeof(message);
fd = open(name.c_str(), O_WRONLY);
write(fd, &size, sizeof(int));
write(fd, msg, (size_t)size);
close(fd);
}
message NamedPipe::receive() {
int fd;
int size;
message msg;
fd = open(name.c_str(), O_RDONLY);
read(fd, &size, sizeof(int));
read(fd, &msg, (size_t)size);
close(fd);
return (msg); //I debugged with printf. This actually reach this point before overflow
}
And my struct is defined like:
struct message {
int type;
char str[0];
};
I actually think that may be a problem of memory allocation, but I have really no idea of what I should do to fix this.
Thanks for reading/helping !
This is the root of your problem, your struct message:
char str[0];
This is not kosher in C++ (nor is the way you're using it kosher in C). When you allocate a message on the stack, you're allocating room for one int and 0 chars. Then in this line
read(fd, &msg, (size_t)size);
you write beyond your stack allocation into neverland. Then you return your message object which would be just one int in size.
Change your struct to this, and it should "work"
struct message
{
int type;
char str[ 16 ];
};

C++: Store read binary file into buffer

I'm trying to read a binary file and store it in a buffer. The problem is, that in the binary file are multiple null-terminated characters, but they are not at the end, instead they are before other binary text, so if I store the text after the '\0' it just deletes it in the buffer.
Example:
char * a = "this is a\0 test";
cout << a;
This will just output: this is a
here's my real code:
this function reads one character
bool CStream::Read (int * _OutChar)
{
if (!bInitialized)
return false;
int iReturn = 0;
*_OutChar = fgetc (pFile);
if (*_OutChar == EOF)
return false;
return true;
}
And this is how I use it:
char * SendData = new char[4096 + 1];
for (i = 0; i < 4096; i++)
{
if (Stream.Read (&iChar))
SendData[i] = iChar;
else
break;
}
I just want to mention that there is a standard way to read from a binary file into a buffer.
Using <cstdio>:
char buffer[BUFFERSIZE];
FILE * filp = fopen("filename.bin", "rb");
int bytes_read = fread(buffer, sizeof(char), BUFFERSIZE, filp);
Using <fstream>:
std::ifstream fin("filename.bin", ios::in | ios::binary );
fin.read(buffer, BUFFERSIZE);
What you do with the buffer afterwards is all up to you of course.
Edit: Full example using <cstdio>
#include <cstdio>
const int BUFFERSIZE = 4096;
int main() {
const char * fname = "filename.bin";
FILE* filp = fopen(fname, "rb" );
if (!filp) { printf("Error: could not open file %s\n", fname); return -1; }
char * buffer = new char[BUFFERSIZE];
while ( (int bytes = fread(buffer, sizeof(char), BUFFERSIZE, filp)) > 0 ) {
// Do something with the bytes, first elements of buffer.
// For example, reversing the data and forget about it afterwards!
for (char *beg = buffer, *end=buffer + bytes; beg < end; beg++, end-- ) {
swap(*beg, *end);
}
}
// Done and close.
fclose(filp);
return 0;
}
static std::vector<unsigned char> read_binary_file (const std::string filename)
{
// binary mode is only for switching off newline translation
std::ifstream file(filename, std::ios::binary);
file.unsetf(std::ios::skipws);
std::streampos file_size;
file.seekg(0, std::ios::end);
file_size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<unsigned char> vec;
vec.reserve(file_size);
vec.insert(vec.begin(),
std::istream_iterator<unsigned char>(file),
std::istream_iterator<unsigned char>());
return (vec);
}
and then
auto vec = read_binary_file(filename);
auto src = (char*) new char[vec.size()];
std::copy(vec.begin(), vec.end(), src);
The problem is definitievely the writing of your buffer, because you read a byte at a time.
If you know the length of the data in your buffer, you could force cout to go on:
char *bf = "Hello\0 world";
cout << bf << endl;
cout << string(bf, 12) << endl;
This should give the following output:
Hello
Hello world
However this is a workaround, as cout is foreseent to output printable data. Be aware that the output of non printable chars such as '\0' is system dependent.
Alternative solutions:
But if you manipulate binary data, you should define ad-hoc data structures and printing. Here some hints, with a quick draft for the general principles:
struct Mybuff { // special strtucture to manage buffers of binary data
static const int maxsz = 512;
int size;
char buffer[maxsz];
void set(char *src, int sz) // binary copy of data of a given length
{ size = sz; memcpy(buffer, src, max(sz, maxsz)); }
} ;
Then you could overload the output operator function:
ostream& operator<< (ostream& os, Mybuff &b)
{
for (int i = 0; i < b.size; i++)
os.put(isprint(b.buffer[i]) ? b.buffer[i]:'*'); // non printables replaced with *
return os;
}
ANd you could use it like this:
char *bf = "Hello\0 world";
Mybuff my;
my.set(bf, 13); // physical copy of memory
cout << my << endl; // special output
I believe your problem is not in reading the data, but rather in how you try to print it.
char * a = "this is a\0 test";
cout << a;
This example you show us prints a C-string. Since C-string is a sequence of chars ended by '\0', the printing function stops at the first null char.
This is because you need to know where the string ends either by using special terminating character (like '\0' here) or knowing its length.
So, to print whole data, you must know the length of it and use a loop similar to the one you use for reading it.
Are you on Windows? If so you need to execute _setmode(_fileno(stdout), _O_BINARY);
Include <fcntl.h> and <io.h>