Read file content in SGX enclave - c++

I'm trying to read the content of a file from an enclave using OCalls.
enclave.edl:
untrusted {
void ocall_print_string([in, string] const char *str);
void ocall_read_IMA_file([in, string] const char *filename, [out] char *buf, [out] int *size);
};
enclave.cpp:
void printf(const char *fmt, ...) {
ocall_print_string(fmt);
}
void read_IMA_file(const char *filename, char *buf, int *size) {
ocall_read_IMA_file(filename, buf, size);
printf(buf);
}
//whereas the read_IMA_file function is called with
char *buf;
int size;
read_IMA_file("test.txt", buf, &size);
implementation of ocall functions in the application:
void ocall_print_string(const char *str) {
printf("%s\n", str);
}
void ocall_read_IMA_file(const char *filename, char *content, int *size) {
content = (char*) malloc(sizeof(char) * 10);
memset(content, '\0', sizeof(char) *10);
char tmp[] = "1234567890";
copy(&tmp[0], &tmp[9], content);
cout << content << endl;
}
But the result I receive is the following:
123456789 (null)
I'm not sure what I'm doing wrong?

In the above program, the "read_IMA_file" trusted function is called with pointer variable(OUT pointer) of type character.Here we are passing the pointer variable without any memory allocation.
"read_IMA_file" initiate a OCall that allocate memory and do "Copy" operation.Now the allocated memory is valid within the untrusted region. So we are getting expected result for the "cout<
Since there is no trusted memory allocated for "content"(before calling Ocall), no copy back operation happens in "OUT" pointer during Ocall returns.
So "buf" doesn't contain any valid data while doing "print(buf)" after Ocall returns in trusted region.
Please try with valid OUT pointer to character buffer(with some memory allocation) or IN and OUT pointer to String buffer.

If you expect it to output 1234567890, then you may need to malloc(11) instead of malloc(10), plus the way you are using copy may contain a bug too.
copy(&tmp[0], &tmp[9], content);
is copying 123456789 to the content, it exclude the the last iterator &tmp[9] as I understand. For more detail, you may want to look at: http://www.cplusplus.com/reference/algorithm/copy/
Also, I think you are not reading in any content from file "test.txt" either.

Related

Passing const char* variables to a function

I'm having a weird and unexpected result in my code and I'd like your support to explain me what happens here.
I have a structure of a confiration :
struct sConfig {
const char* ssid;
const char* password;
}
I'm loading this configuration using LittleFS from a deserialized json :
config.ssid = json["ssid"]; // so this is coming from the FS in a json file
config.password = json["password"]; // so this is coming from the FS in a json file
So far, all is fine, I can print out the value using
Serial.println(config.ssid);
I'm then calling an internal void function
startWiFi(config.ssid, config.password);
void startWiFi(const char* ssid, const char* psswd) {
Serial.println(ssid);
Serial.println(psswd);
}
As a result, the console returns :
⸮
and
?:⸮?#⸮8⸮?<9⸮?⸮8⸮?:⸮?#⸮8⸮?<9⸮?⸮8⸮?:⸮?#⸮8⸮?<9⸮?⸮8⸮?.:⸮?#⸮
What can be wrong in my variables ?
Please help me as I'm stuck.
Thanks a lot.
To fix the issue I'd avoid copying a pointer and copy the actual data.
So, instead of config.password = json["password"];
I'd declare ssid and password as char arrays and copy the values from the json with strncpy()
struct sConfig {
char ssid[32];
char password[64];
}
or I'd allocate them on the spot with a custom copy function
char * myCopy (char *destination, const char *source)
{
// I'm using 64 because is the max length of WPA2-PSK passwords
size_t len = strnlen(destination, 64);
destination = malloc((num + 1) * sizeof(char));
strncpy(destination, source, num);
return destination;
}
....
myCopy(config.ssid, json["ssid"]);
myCopy(config.password, json["password"]);
What's probably happening here is a use-after-free bug.
At config.ssid = json["ssid"] you copy a pointer to the internal memory of the json object. It's probably valid at the time of that copy (so the print succeeds), but when the json changes its state or gets deallocated, you get garbage at that memory address.
The solution is - as suggested in the other answer - copy the whole string and not just its address.

the strcpy function keeps crashing

#include <iostream>
using namespace std;
defining class
class fancyString {
private:
char *content;
bool flag_bold;
bool flag_italics;
public:
fancyString(){
content="";
flag_bold= false;
flag_italics=false;
}
in both functions I'm asked to use the old fashioned calloc
fancyString(char* cntnt){
content=(char *) calloc(strlen(cntnt)+1, sizeof(char*));
Usually the strcpy is the main reason of the crash
strcpy(cntnt,content);
}
fancyString(fancyString & f1){
content=(char *) calloc(strlen(f1.content)+1, sizeof(char*));
Usually the strcpy is the main reason of the crash
strcpy(f1.content,content);
flag_bold=f1.flag_bold;
flag_italics=f1.flag_italics;
}
friend ostream& operator<<(ostream& os, const fancyString& FS){
os<<"string is "<<FS.content<<endl<<"bold status is "<<FS.flag_bold<<endl<<"italics status is "<<FS.flag_italics<<endl;
return os;
}
~fancyString(){
cout << "Destroying the string\n";
if ( content != NULL )
free (content);
}
};
main function
int main(int argc, const char * argv[]) {
fancyString fs1 ("First Example");
fancyString fs2(fs1);
cout<<fs2;
return 0;
}
You have the arguments to the strcpy calls the wrong way round! See the definition on cppreference:
char * strcpy ( char * destination, const char * source );
So, in your your first constructor, the call:
strcpy(cntnt,content);
is attempting to copy the newly-allocated buffer into the passed argument, which is actually a (constant) string literal:
int main(int argc, const char * argv[]) {
fancyString fs1 ("First Example");
//...
NOTES based on suggestions made in the comments:
(1) Note that, in your calloc call - which is allocating an 'array' of char, the elements' size is sizeof(char) not sizeof(char*) (which would be appropriate for an 'array' of pointers). Use:
content = (char *) calloc(strlen(cntnt)+1, sizeof(char));
and similarly in the copy constructor.
(2) Assuming that your first constructor is never intended to modify the string given as its argument, you should really specify it as const:
fancyString(const char* cntnt){
//...
(This would have flagged the error of having the strcpy arguments wrong!)
Please feel free to ask for further clarification and/or explanation.

SSLeay reading a PEM file

I am trying to use the PEM_read_bio function to get data from a file.
The version of SSLeay we are using is from 1997, so documentation is a bit thin on the ground. Thankfully in this case it seems there is a matching function documented here: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio.html
I originally tried this:
char ** names;
char ** headers;
unsigned char ** data;
long len;
BIO *in = BIO_new_file("C:\\filename.txt", "r");
if (!in)
{
// error
}
else
{
int result = PEM_read_bio(in, names, headers, data, &len);
}
BIO_free(in);
OPENSSL_free(names);
OPENSSL_free(headers);
OPENSSL_free(data);
However this results in a run-time check failure: The variable 'names' is being used without being initialized.
The documentation mentions OPENSSL_malloc( num ) is used to initialize memory, but it fails to mention whether it does this behind the scenes, or the user does it.
OPENSSL_malloc is similar in usage to C's malloc, but how are we supposed to know how much memory to allocate in advance, before reading the file?
I have tried the following at the beginning:
char ** names = reinterpret_cast<char **>(OPENSSL_malloc(2));
char ** headers = reinterpret_cast<char **>(OPENSSL_malloc(2));
unsigned char ** data = reinterpret_cast<unsigned char **>(OPENSSL_malloc(2));
long len;
This results in apparently random data.
The documentation you linked to says:
The name, header and data pointers are allocated via OPENSSL_malloc() and should be freed by the caller via OPENSSL_free() when no longer needed.
That means PEM_read_bio() calls OPENSSL_malloc() for you, and then you call OPENSSL_free() on the allocated memory it returns when you are doing with it.
You are passing uninitialized pointers to PEM_read_bio(), that is why it is failing. The name, header and data parameters are all output parameters. You need to pass in the addresses of your own pointer variables to receive the memory that PEM_read_bio() allocates for you, eg:
char *name;
char *headers;
unsigned char *data;
long len;
BIO *in = BIO_new_file("C:\\filename.txt", "r");
if (!in)
{
// error
}
else
{
int result = PEM_read_bio(in, &name, &headers, &data, &len);
if (!result)
{
// error
}
else
{
...
OPENSSL_free(name);
OPENSSL_free(headers);
OPENSSL_free(data);
}
BIO_free(in);
}

deal with void pointers and char in c++

i am working on a piece of code right now and got a problem with void pointer and char. basically, within the serialize function, we would have a new char. we would need to store that char in buffer. and here is the signature of serialize function.
void serialize(void *buffer,
//some other inputs here
){
std::string str = "";
/*some code here, store the final output in str first*/
char* charStr = new char[str.size()];
strcpy(charStr,str.c_str());
buffer = static_cast<void*>(charStr);
}
using the function like this,
char buffer[256];
serialize(buffer,
//some other inputs here
);
However, the data stored in buffer would be something real strange. I changed the void pointer in the signature to char pointer as a temporary solution. However, i know there must be a better one.
If you want to fill a buffer, you cannot assign to it (that will just overwrite the pointer, leaving the original buffer contents intact). You also do not need a temporary buffer in serialize (charStr). You can directly strcpy to the output buffer, like this:
void serialize(void *buffer
){
std::string str = "foo bar baz";
strcpy((char *)buffer, str.c_str());
}
define it as
void serialize(void *& buffer,
//some other inputs here
){
use pointer as parameter, remember to delete the buffer
char* buffer;
serialize(buffer,
//some other inputs here
);

variable len string

i have a packet struct which have a variable len for a string example:
BYTE StringLen;
String MyString; //String is not a real type, just trying to represent an string of unknown size
My question is how i can make the implementation of this packet inside an struct without knowing the size of members (in this case strings). Here is an example of how i want it to "look like"
void ProcessPacket (PacketStruct* packet)
{
pointer = &packet.MyString;
}
I think its not possible to make since the compiler doesn't know the size of the string until run time. So how can make it look high level and comprehensible?.
The reason i need structs its for document every packet without the user actually have to look any of the functions that analyze the packet.
So i can resume the question to: is there a way to declare an struct of undefined size members or something close as a struct?
I would recommend a shell class that just interprets the packet data.
struct StringPacket {
char *data_;
StringPacket (char *data) : data_(data) {}
unsigned char len () const { return *data_; }
std::string str () const { return std::string(data_+1, len());
};
As mentioned in comments, you wanted a way to treat a variable-sized packet like a struct. The old C way to do that was to create a struct that looked like this:
struct StringPacketC {
unsigned char len_;
char str_[1]; /* Modern C allows char str_[]; but C++ doesn't */
};
And then, cast the data (remember, this is C code):
struct StringPacketC *strpack = (struct StringPacketC *)packet;
But, you are entering undefined behavior, since to access the full range of data in strpack, you would have to read beyond the 1 byte array boundary defined in the struct. But, this is a commonly used technique in C.
But, in C++, you don't have to resort to such a hack, because you can define accessor methods to treat the variable length data appropriately.
you can copy the string into a high-level std::string (at least, if my guess that String is a typedef for const char* is correct):
void ProcessPacket( const PacketStruct& packet )
{
std::string highLevelString( packet.MyString,
static_cast< size_t >( packet.StringLen ) );
...
}
A simple variant according to your posting would be:
struct PacketStruct {
std::string MyString;
size_t length () const { return MyString.length(); }
const char* operator & () const { return MyString.c_str(); }
};
This can be used (almost) as you desired above:
void ProcessPacket (const PacketStruct& packet)
{
const char * pointer = &packet;
size_t length = packet.length();
std::cout << pointer << '\t' << length << std::endl;
}
and should be invoked like:
int main()
{
PacketStruct p;
p.MyString ="Hello";
ProcessPacket(p);
}