DTrace: how to print out memory buffers - dtrace

I need to trace all pwrite(2) calls done to some specific file and print all buffers that are to be written byte by byte. The data expected is not in ASCII string format so i can't use:
printf("%s\n", copyinstr(arg1))
I learned about copyin(arg1, arg2), but that gives me a void* and all examples i've found covert it to string again by calling stringof, e.g.:
printf("%s\n", stringof(copyin(arg1, arg2)))
What i need is to somehow display all bytes in copyin'ed buffer. Any suggestions?
Thank you,
Inso.

Ok, it's done with tracemem(buffer, size) call.

tracemem(address, size_t nbytes, size_t dbytes), where nbytes is a constant and dbytes can be dynamic and less than nbytes.
tracemem
void tracemem(address, size_t nbytes)
void tracemem(address, size_t nbytes, size_t dbytes)
The tracemem action takes a D expression as its first argument,
address, and a constant as its second argument, nbytes. tracemem
copies the memory from the address specified by addr into the directed
buffer for the length specified by nbytes.
If the third argument, dbytes is supplied, only up to dbytes will be
copied. dbytes is allowed to be a variable amount, but it must be less
than or equal to nbytes. This is useful when you are looking at
something that has a known upper bound, but the actual number of bytes
may vary. For example, consider the case where you are dumping an
Ethernet packet. The maximum size is based on the MTU, but the
amount of data in the given packet is variable.

Related

Determining size of vsprintf output

I am implementing a printf(const char * format, ...) like method for a class, where I need to determine the exact size of it's output given only the supplied format and the arguments given in va_list, before calling vsprintf() to perform the actual writing.
Is there a function that can take the format and va_list to generate the exact length of the output?
As from the example in the documentation, you can determine the necessary buffer size 1st (emphasis mine):
std::vector<char> buf(1+std::vsnprintf(NULL, 0, fmt, args1)); // <<<
va_end(args1);
std::vsnprintf(buf.data(), buf.size(), fmt, args2);
4) Writes the results to a character string buffer. At most buf_size-1 characters are written. The resulting character string will be terminated with a null character, unless buf_size is zero. If buf_size is zero, nothing is written and buffer may be a null pointer, however the return value (number of bytes that would be written not including the null terminator) is still calculated and returned.
Generally all variants of the <x>sprintf() functions family can be used to calculate the necessary buffer size if the target buffer parameter is passed as NULL or nullptr.

cast to pointer from integer of different size when converting uint64_t to bytes

[EDIT]I wanted write uint64_t to char* array in network byte order to send it as UDP datagram with sendto, uint64_t has 8 bytes so I convert them as follow:
void strcat_number(uint64_t v, char* datagram) {
uint64_t net_order = htobe64(v);
for (uint8_t i=0; i<8 ;++i) {
strcat(datagram, (const char*)((uint8_t*)&net_order)[i]);
}
}
wchich give me
warning: cast to pointer from integer of different size [-Wint-to-pointer-xast]
strcat(datagram, (const char*)((uint8_t*)&net_order)[i]);
how can I get rid of this warning or maybe do this number converting simpler or clearer?
((uint8_t*)&net_order)
this is a pointer to net_order casted to a uint8_t pointer
((uint8_t*)&net_order)[i]
this is the i-th byte of the underlying representation of net_order.
(const char*)((uint8_t*)&net_order)[i]
this is the same as above, but brutally casted to a const char *. This is an invalid pointer, and it is what the compiler is warning you about; even just creating this pointer is undefined behavior, and using it in any way will almost surely result in a crash.
Notice that, even if you somehow managed to make this kludge work, strcat is still the wrong function, as it deals with NUL-terminated strings, while here you are trying to put binary data inside your buffer, and binary data can naturally contain embedded NULs. strcat will append at the first NUL (and stop at the first NUL in the second parameter) instead of at the "real" end.
If you are building a buffer of binary data you have to use straight memcpy, and most importantly you cannot use string-related functions that rely on the final NUL to know where the string ends, but you have to keep track explicitly of how many bytes you used (i.e. the current position in the datagram).

Passing vector to enclave in Intel SGX

I have a vector<vector <string>> a; How could I pass it to the enclave? How I declare edl function.
A sample function declaration for the app, edl and enclave is much appreciated.
I am aware of this: C++ Arguments to SGX Enclave Edge Functions.
A sample to pass even a vector<string> is ok for me.
update1:
I came up with this:
App.cpp
const char *convert(const std::string & s)
{
return s.c_str();
}
vector<string> members_data;
member_data.push_back("apple");
member_data.push_back("orange"); //just for sample
std::vector<const char*> vc;
std::transform(members_data.begin(), members_data.end(), std::back_inserter(vc), convert);
edl:
trusted {
public void ecall_receive_vector([in, size=len] const char **arr, size_t len);
};
enclave
void ecall_receive_vector(const char *arr[], size_t len)
{
vector<string> v(arr, arr+len);
printf("%s\n", v[2].c_str());
}
But enclave does not receive any data, the program compiles perfectly with no error. Could anyone help? The printf is the sample ocall.
In the EDL use count instead of size.
trusted {
public void ecall_receive_vector([in, count=len] const char **arr, size_t len);
};
You are passing a double pointer, it is, a pointer to pointer to char (char **).
While marshaling/unmarshaling pointers, the EDL Processor processes (copies and validates input and output) only the first level of indirection, it's up to the developer to handle the additional levels of indirection. Hence, for an array of pointers it will only copy the first array of pointers, not the pointed values, copying them is the developer's responsibility.
If not specified count and size default to 1 and sizeof(<pointed-type>) respectively. In your case size = sizeof(<pointer>) which in most platforms is 4.
In your case, you provided only size. As you don't provide the caller code I assume you're passing the length of the string, and as count was not specified it defaults to 1. Then the total number of bytes, based on Total number of bytes = count * size will be 1 * len which is wrong.
Using only count will let size default to sizeof(<pointed-type>), then Total number of bytes = count * size will be count * sizeof(<pointed-type>), which is right because you're passing an array of pointers.
To close, once inside the Enclave you need to copy the pointers' data because those pointers reside out of the enclave, that may be done automatically by assigning them to a std::string.
From Intel SGX SDK Documentation:
Pointer Handling (the last paragraph)
You may use the direction attribute to trade protection for performance. Otherwise, you must use the user_check attribute described below and validate the data obtained from untrusted memory via pointers before using it, since the memory a pointer points to could change unexpectedly because it is stored in untrusted memory. However, the direction attribute does not help with structures that contain pointers. In this scenario, developers have to validate and copy the buffer contents, recursively if needed, themselves.
And,
Buffer Size Calculation
The generalized formula for calculating the buffer size using these attributes:
Total number of bytes = count * size
The above formula holds when both count and size/sizefunc are specified.
size can be specified by either size or sizefunc attribute.
If count is not specified for the pointer parameter, then it is assumed to be equal to 1, i.e., count=1. Then total number of bytes equals to size/sizefunc.
If size is not specified, then the buffer size is calculated using the above formula where size is sizeof (element pointed by the pointer).

Not sure why I am getting different lengths when using a string or a char

When I call gethostname using a char my length 25 but when I use a string my length is 64. Not really sure why. Both of them I am declaring the same size on HOST_NAME_MAX.
char hostname[HOST_NAME_MAX];
BOOL host = gethostname(hostname, sizeof hostname);
expectedComputerName = hostname;
int size2 = expectedComputerName.length();
std::string test(HOST_NAME_MAX, 0);
host = gethostname(&test[0], test.length());
int testSize = test.length();
An std::string object can contain NULs (i.e. '\0' characters). You are storing the name in the first bytes of a string object that was created with a size of HOST_NAME_MAX length.
Storing something in the beginning of the string data won't change the length of the string that remains therefore HOST_NAME_MAX.
When creating a string from a char pointer instead the std::string object created will contain up to, but excluding, the first NUL character (0x00). The reason is that a C string cannot contain NULs because the first NUL is used to mark the end of the string.
Consider what you're doing in each case. In the former code snippet, you're declaring a character array capable of holding HOST_NAME_MAX-1 characters (1 for the null terminator). You then load some string data into that buffer via the call to gethostname and then print out the length of buffer by assigning it to a std::string object using std::string::operator= that takes a const char *. One of the effects of this is that it will change an internal size variable of std::string to be strlen of the buffer, which is not necessarily the same as HOST_NAME_MAX. A call to std::string::length simply returns that variable.
In the latter case, you're using the std::string constructor that takes a size and initial character to construct test. This constructor sets the internal size variable to whatever size you passed in, which is HOST_NAME_MAX. The fact that you then copy in some data to std::strings internal buffer has no bearing on its size variable. As with the other case, a call to the length() member function simply returns the size - which is HOST_NAME_MAX - regardless of whether or not the actual length of the underlying buffer is smaller than HOST_NAME_MAX.
As #MattMcNabb mentioned in the comments, you could fix this by:
test.resize( strlen(test.c_str()) );
Why might you want to do this? Consistency with the char buffer approach might be a reason, but another reason may be performance oriented. In the latter case you're not only outright setting the length of the string to HOST_NAME_MAX, but also its capacity (omitting the SSO for brevity), which you can find starting on line 242 of libstdc++'s std::string implementation. What this means in terms of performance is that even though only, say, 25 characters are actually in your test string, the next time you append to that string (via +=,std::string::append,etc), it's more than likely to have to reallocate and grow the string, as shown here, because the internal size and internal capacity are equal. Following #MattMcNabb's suggestion, however, the string's internal size is reduced down to the length of the actual payload, while keeping the capacity the same as before, and you avoid the almost immediate re-growth and re-copy of the string, as shown here.

RegKeyValue returning nonsense data

char value[255];
DWORD BufferSize = 8192;
RegGetValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"ProductName", RRF_RT_ANY, NULL, &value, &BufferSize);
cout << value;
After RegKeyValue() runs, it appears that value is
value 0x0034f50c "ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ... char[255]
What's going on here?
Note: RegKeyValue() returns 0
There are two issues here.
Make sure the return value of RegGetValue is ERROR_SUCCESS. If it is not, the routine failed. Also, you can check to see what was written into BufferSize, as RegGetValue specifies the number of bytes written.
You're passing in a buffer defined as char value[255];, then specifying it's length as 8192. This can cause a buffer overrun.
You didn't check the return value of RegGetValue. Most likely the call failed and the buffer value was never assigned anything. Always check return values.
From the code we can see, I note that you are lying about the buffer size. You say that it is 8192 bytes. But you only allocated 255 bytes. You are also calling the Unicode version of the API, but passing in a char buffer. If you are expecting string data then you need to supply a buffer of wide characters. The Unicode version of this API will return string data as UTF-16 encoded text.
Once you get all that sorted you next need to check what type is stored in that value. You are passing NULL for the type parameter. Pass a pointer to a variable and find out whether or not a string really is stored
there. You will also need to read how many bytes are read and set the null-terminator in your buffer accordingly.