eBPF: insert a new inner map to `BPF_MAP_TYPE_HASH_OF_MAPS`? - bpf

I am trying to implement LSM BPF programs and I want to use BPF_MAP_TYPE_HASH_OF_MAPS to store information for each super block as the sb_alloc_security LSM hook is triggered. For example, I want to define the map as:
struct bpf_map_def SEC("SBMap") outer_map = {
.type = BPF_MAP_TYPE_HASH_OF_MAPS,
.key_size = sizeof(uuid_t), // super block unique identifier
.value_size = sizeof(__u32), // must be u32 because it is inner map id
.max_entries = 1024, // for now, let's assume we care about only 1024 super blocks
};
I want to use the super block's UUID as the key to the outer_map and every time a new super block is allocated, I would like to create a new inner map, something like:
SEC("lsm/sb_alloc_security")
int BPF_PROG(sb_alloc_security, struct super_block *sb) {
uuid_t key = sb->s_uuid; // use super block UUID as key to the outer_map
// If key does not exist in outer_map,
// create a new inner map and insert it
// into the outer_map with the key
}
But it seems like maps can be created only in user space. Is there any workaround?

That is correct, BPF maps can only be created from userspace, including inner maps of maps-in-maps structures. If you could create maps from the BPF programs, it would essentially enable dynamic memory allocation.

Related

Get the actual structure size before alignment

So it turns out that both dt struct and ?? sizeof struct return the total size the struct occupies in memory after alignment.
Is there a way to get the actual size of the struct before alignment?
I need this functionality for a function that returns the actual size of a field within a struct. For example:
__declspec(align(64)) struct ALIGNED_STRUCT {
char field;
}
running ?? sizeof(ALIGNED_STRUCT) one should get 0x40 which makes it hard to deduce the actual size of the internal field.
edit:
command outputs:
2:001> dt -v ALIGNED_STRUCT
test!ALIGNED_STRUCT
struct ALIGNED_STRUCT, 1 elements, 0x40 bytes
+0x000 field : Char
3:001> ?? sizeof(ALIGNED_STRUCT)
0x40
No -- there isn't a way to return the structure size "before alignment". That's not really meaningful in any case. The compiler is always using the aligned size. The symbols have the aligned size. That's the size of the type.
If you are looking for things like the "size of an internal field", there are numerous ways to accomplish this. As mentioned in comments, you can do the quick dirty EE sizeof thing:
dx sizeof(((ALIGNED_STRUCT *)0)->field)
You can also get full access to the underlying type system via the data model APIs (in either a C/C++ extension or in JavaScript) which will allow you to find out pretty much whatever you want about the types: their fields, sizes, offsets, function parameter types, template arguments, etc...
From C/C++, you can:
QI for IDebugHostSymbols (https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/dbgmodel/nn-dbgmodel-idebughostsymbols)
Get an IDebugHostModule (https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/dbgmodel/nn-dbgmodel-idebughostmodule) for the module containing your structure by calling the FindModuleByName method.
Get an IDebugHostType (https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/dbgmodel/nn-dbgmodel-idebughosttype) for the type you want to inquire about (e.g.: ALIGNED_STRUCT) by calling FindTypeByName
Enumerate its fields with EnumerateChildren, getting an IDebugHostField (https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/dbgmodel/nn-dbgmodel-idebughostfield) for each
Get the offset of such field by calling GetOffset
Get the type of each field by calling GetType, getting you back to another IDebugHostType
Get the size of the field by calling GetSize
That might look something like this:
ComPtr<IDebugHostSymbols> spHostSymbols; /* QI this off IDebugClient, etc... */
ComPtr<IDebugHostModule> spMyModule;
if (FAILED(spHostSymbols->FindModuleByName(USE_CURRENT_HOST_CONTEXT, L"myModule", &spMyModule)))
{
return ...;
}
ComPtr<IDebugHostType> spType;
if (FAILED(spMyModule->FindTypeByName(L"ALIGNED_STRUCT", &spType)))
{
return ...;
}
ComPtr<IDebugHostType> spType; /* get the type of an object */
//
// Enumerate every field of this type. Note thiat this *WILL NOT* enumerate
// fields of base classes!
//
ComPtr<IDebugHostSymbolEnumerator> spEnum;
if (SUCCEEDED(spType->EnumerateChildren(SymbolField, nullptr, &spEnum)))
{
ComPtr<IDebugHostSymbol> spFieldSymbol;
HRESULT hr = S_OK;
while (SUCCEEDED(hr))
{
hr = spEnum->GetNext(&spFieldSymbol);
if (SUCCEEDED(hr))
{
ComPtr<IDebugHostField> spField;
if (SUCCEEDED(spFieldSymbol.As(&spField))) /* should always succeed */
{
// spField is each field of the type in turn
}
ULONG64 fieldOffset;
if (SUCCEEDED(spField->GetOffset(&fieldOffset)) /* won't succeed on static fields */
{
// fieldOffset is the offset of the field within the type
}
ComPtr<IDebugHostType> spFieldType;
if (SUCCEEDED(spField->GetType(&spFieldType))
{
ULONG64 fieldSize;
if (SUCCEEDED(spFieldType->GetSize(&fieldSize)))
{
// fieldSize contains the size (aligned) of the field's type
}
}
}
}
// hr == E_BOUNDS : we hit the end of the enumerator
// hr == E_ABORT : user requested interruption, propagate upwards immediately
}
For C++, this can be made significantly easier by using the C++17 helper library on GitHub (https://github.com/microsoft/WinDbg-Libraries/blob/master/DbgModelCppLib/DbgModelClientEx.h)
That might look something like:
Module myModule(HostContext::DeferredCurrent(), L"myModule");
Type alignedStruct(myModule, L"ALIGNED_STRUCT");
//
// The below will *NOT* enumerate fields of base classes. You must explicitly
// recurse if you want such.
//
for(Field f : alignedStruct.Fields())
{
//
// Get the offset and size of each field.
//
ULONG64 fieldOffset = f.GetOffset();
ULONG64 fieldSize = f.Type().Size();
}
In JavaScript (see https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/native-objects-in-javascript-extensions-type-objects), this would look like:
Call host.getModuleType to get a type object for the structure (e.g.: ALIGNED_STRUCT)
Get access to the field in question by accessing the named property of fields on the type (e.g.: myType.fields.field_name)
Get the offset of of such field by accessing the offset property
Get the type of each field by accessing the type property
Get the size of the field by accessing the size property of its type
That might look something like:
var myType = host.getModuleType("myModule", "ALIGNED_STRUCT");
var fields = myType.fields;
//
// In JavaScript, fields has properties named according to each field. If
// you want to enumerate, get the property names and access those keys.
//
var fieldNames = Object.getOwnPropertyNames(fields);
for (var fieldName of fieldNames)
{
var field = fields[fieldName];
//
// Get the offset and size of each field...
//
var fieldOffset = field.offset;
var fieldSize = field.type.size;
}
In either of these cases, you would need to manually recurse base classes if you're looking at C++ objects where fields are contained in base classes.
Hope that helps...
William has provided a comprehensive answer this answer is just a practical example of that
0:000> dx #$stru
#$stru : Pcb _KPROCESS (+ 0x0)
name : Pcb
type : _KPROCESS
locationKind : member
offset : 0x0
0:000> dx #$stru.type.fields.Header.type.size
#$stru.type.fields.Header.type.size : 0x18
0:000>

Are only types with trivial destructor suited for storage for placement new?

The examples for placement new often use unsigned char arrays as the underlying storage. The steps can be:
create the unsigned char array with new
create an object in this storage with placement new
use object
destroy object
call delte for the unsigned char array to free the array
Point 5. seems only to work if we use a type for the underlying storage with a trivial destructor. Otherwise, we would call the destructor of the underlying storage type but with no object existing there. Technically, we are destructing a bunch of unsigned chars which are not present and we are lucky that the desturctor of the unsigned char type is trivial and so no-op.
What about the following code:
struct A{ /* some members... */ };
struct B{ /* some members... B shall be same size as A */ };
int main()
{
auto ptr_to_a = new A; // A object lives # ptr_to_a
ptr_to_a->~A(); // A object destroyed. no object living # ptr_to_a, but storage is preserved
new (ptr_to_a) B; // B object living # ptr_to_a.
std::launder(reinterpret_cast<b*>(ptr_to_a))->/*...*/; // use B. for this purpose we need std::launder in C++17 or we would store the pointer returned by the placement new and use it without std::launder
std::launder(reinterpret_cast<b*>(ptr_to_a))->~B(); // B object destroyed. no object living # ptr_to_a, but storage is preserved
// at this point there is no object living # ptr_to_a, but we need to hand back the occupied storage.
// a)
delete ptr_to_a; // undefined behavior because no object is sitting # ptr_to_a
// b)
new (ptr_to_a) A; // create an object again to make behavior defined. but this seems odd.
delete ptr_to_a;
// c)
// some method to just free the memory somehow without invoking destructors?
return 0;
}
On https://en.cppreference.com/w/cpp/language/lifetime is written:
As a special case, objects can be created in arrays of unsigned char or std::byte (in which case it is said that the array provides storage for the object) if... .
Does this imply, that its only allowed to use placement new on unsigned char and byte arrays and because they have a trivial destructor my code sample is obsolete?
Otherwise, how about my codesample? Is option b) the only valid solution?
Edit: second examlpe:
struct A{ /* some members... */ };
struct alignas(alignof(A)) B{ /* some members... */ };
int main()
{
static_assert(sizeof(A) == sizeof(B));
A a;
a.~A();
auto b_ptr = new (&a) B;
b_ptr->~B();
return 0;
// undefined behavior because a's destructor gets called but no A object is "alive" (assuming non trivial destructor)
// to make it work, we need to placement new a new A into a?
}
Generally, you wouldn't use the storage returned by an allocation of an unrelated class A to put your B in. You don't even have to have an allocation at all
int main ()
{
char storage[sizeof(B)];
std::aligned_storage<sizeof(B), alignof(B)>::type aligned_storage;
auto b_ptr1 = new (&storage) B; // potentially unaligned
auto b_ptr2 = new (&aligned_storage) B; // guaranteed safe
// use b_ptr1, b_ptr2
b_ptr1->~B();
b_ptr2->~B();
// storage ceases to exist when main returns
}
If you do need to dynamically allocate, I would suggest wrapping the storage in a holder struct, so that you don't end the lifetime of the thing you newed.
struct B_holder
{
std::aligned_storage<sizeof(B), alignof(B)>::type storage;
B * make_B() { return new(&storage) B; }
}
int main()
{
auto holder = std::make_unique<B_holder>();
auto * B_ptr = B_holder->make_B();
// use B_ptr
B_ptr->~B();
// holder ceases to exist when main returns
}
For the most part yes.
You can however do something like this.
struct placed {
char stuff[100];
};
struct stupid {
std::aligned_storage_t<sizeof(placed), alignof(placed)> data;
~stupid() {
std::cout << "stupid gone\n";
}
};
int main() {
auto* pstupid = new stupid;
auto* pplaced = ::new( (void*)&pstupid->data ) placed;
pplaced->~placed();
auto* pstupid2 = ::new( (void*)pstupid ) stupid;
delete pstupid2;
}
but that is, as implied by the type name, pretty stupid. And exceedingly hard to make exception safe without a lot of noexcept guarantees I didn't include above.
I am also not completely certain if delete pstupid2 is legal, as it was created via placement new and not via a simple new expression.

Constructing variable based on 2 random variables in seq_item

In my sequence Item I have a bus which should contain the address and data together. Now I want to randomize the address and data, after which concatenate their randomized value in the bus.
Please help understand how to do this, in the seqItem class.
class seqItem extends uvm_sequence_item;
`uvm_object_param_utils(seqItem)
rand logic [541-1:515] wfifo_addr;
rand logic [512-1:0] wfifo_data;
logic [541-1:0] wfifo_dout; // = {this.wfifo_addr, 3'b000, this.wfifo_data};
constraint wfifo_addr_ctrl { ... }
constraint wfifo_data_ctrl { ... }
…
endclass
So how to make wfifo_dout to contain the randomized values of wfifo_addr and wfifo_data.
I have to keep separate wfifo_addr and wfifo_data signals to create randomization constraints for them.
Now I am assigning value to wfifo_dout from the sequence, which randomizes the seqItem transaction. However it would be nice if I could create the value of wfifo_dout right in seqItem.
There are two things you can do:
Create a post_randomize() method that makes an assignment to wfifo_dout
function post_randomize(); // called automatically after a call to randomize();
wfifo_dout = {this.wfifo_addr, 3'b000, this.wfifo_data};
endfunction
Use the let statement to declare the address and data instead of making them separate variables
rand logic [541-1:0] wfifo_dout;
let wfifo_addr = wfifo_dout[541-1:515];
let wfifo_data = wfifo_dout[512-1:0];

Purpose of GValue, GTypeValueTable, GTypeInfo and GParamSpec

GObject library is really awfully documented. It's damn hard to figure the purposes of entities created. Namely, I don't get the roles of GValue, GTypeValueTable, GTypeInfo, GParamSpec and TypeData.
In brief, the process of type registration is as follows. Each type is represented by a TypeNode structure. There are 2 storages of TypeNode structures: static_fundamental_type_nodes array for storing TypeNodes of static fundamental types and static_type_nodes_ht hash table for static non-fundamental types. Each GType is just the memory address of the corresponding TypeNode in case of non-fundamental types or index of TypeNode in static_fundamental_type_nodes in case of fundamental types. What happens to dynamic types - I don't know, please explain me if you can. The corresponding code resides in gtype_init function, responsible for initialization of the type system: http://git.gnome.org/browse/glib/tree/gobject/gtype.c#n4323.
GValue, GParamSpec and GObject are GTypes themselves, so they are registered as types.
GValue is meant used to register new type values through it, but how?.
GParameters and GParamSpec seem to be required for registering GObject type (not sure). How exactly it is done? What are the roles of each?
MOST IMPORTANTLY: What are the roles of GTypeValueTable, GTypeInfo and TypeData? TypeData is referrenced by TypeNode and contains GTypeValueTable as well as substructures BoxedData, ClassData, IFaceData, InstanceData (why Instance, aren't we registering type?). Moreover, they seems to duplicate each other, cause ALL of them contain references to base_init/finalize, class_init/finalize has a reference to GTypeValueTable.
So, GObject papas, if you're reading this, please, explain yourselves! Describe the purpose of those structures you use.
The only two of these that you really need to care about unless you're attempting to work on some very low level code are GValue and GParamType
I'll start with GParamType
GParamType is for used for registering a property with a GObject. Say, for example, I have a GObject subclass called Person, and I wanted it to have two properties: Name and Age. In the class_init function I would register these like so
{
GParamSpec *pspec;
. . .
pspec = g_param_spec_string ("name", "Name", "The name of the person", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_NAME, pspec);
pspec = g_param_spec_int ("age", "Age", "The age of the person", 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_AGE, spec);
. . .
}
Now you can call g_object_get or g_object_set on those properties and the system will know how to handle it
char *name;
int age;
g_object_set (G_OBJECT (person), "name", "Steve", "age", 37, NULL);
g_object_get (G_OBJECT (person), "name", &name, "age", &age, NULL);
g_print ("%s is %d years old\n", name, age);
// And because the type system knows when a property is a string, it knows how to give
// you a copy of the string, so you need to free it once you've finished with it
g_free (name);
The various parameters are explained here: GParamSpec There are GValue types for all the standard types: strings, bools, ints etc, and some other libraries such as GStreamer will register their own custom ones.
Outside of installing properties on GObjectClass you very rarely need to deal with GParamSpec. The two main occasions where they appear is in the GObjectClass set/get_property methods and the GObject notify signal. It is useful in the last case to detect which property has received the notify signal, by calling g_param_spec_get_name, but really it's better to use a more specific notify signal like so:
g_signal_connect (person, "notify::name", G_CALLBACK (name_changed_cb), NULL);
g_signal_connect (person, "notify::age", G_CALLBACK (age_changed_cb), NULL);
rather than
g_signal_connect (person, "notify", G_CALLBACK (something_changed_cb), NULL);
Sometimes you may want to create your own structures and use those for the properties. For example if I had
struct _PersonDetails {
char *name;
int age;
}
and instead of having two properties on the Person object, I wanted one called "details". The GLib type system does not know how to deal with my custom struct _PersonDetails so I would need to create a boxed type for it, so that it knew how to correctly copy/free the structure as it is passed around the Glib internals. And that is where GValue comes in.
GValue is for wrapping values of different types so they can be copied and freed correctly (if they need to be), and so that generic functions can be used.
For example, the GObjectClass method set_property has the prototype of
void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
This means that any type which can be represented by a GValue can be passed in and specific functions such as set_int_property, set_string_property, set_bool_property are not required.
It also means that the functions g_object_set and g_object_get know how to deal with the parameters that are passed in because it knows that the property "name" is registered to be a string type, and it has the functions necessary to copy/free that string.
More about GValue can be found here - Generic values
To register our custom struct _PersonDetails with the GLib type system we would create a custom Boxed type which told the system how to copy and free it. The details are here: Boxed Types
G_DEFINE_BOXED_TYPE (PersonDetails, person_details,
person_details_copy,
person_details_free)
. . .
static gpointer
person_details_copy (gpointer data)
{
struct _PersonDetails *details = (struct _PersonDetails *)data;
struct _PersonDetails *copy = g_new (struct _PersonDetails, 1);
// We need to copy the string
copy->name = g_strdup (details->name);
copy->age = details->age;
return (gpointer) copy;
}
static void
person_details_free (gpointer data)
{
struct _PersonDetails *details = (struct _PersonDetails *)data;
// name was allocated so it needs freed as well
g_free (details->name);
g_free (details);
}
Now we can register our type using
pspec = g_param_spec_boxed ("details", "Details", "The person's details", person_details_get_type (), G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_DETAILS, pspec);

Mirth Traverse through a GlobalMap

In my mirth implementation (Mirth Connect Server 2.2.1) I have a GlobalMap that contains keys and properties comes from external property file. How do I get the key set from the Globalmap and iterate it to get the values?
You can iterate through the global map like so:
for each (key in globalMap.getVariables().keySet().toArray())
logger.info(key+': '+$g('key'));
I'm not sure exactly how you're initializing your key/value set, but here's a basic rundown of what I do.
To stick a key/value set in the GlobalMap:
//I will assume that you have your own routine for initializing the
//kv set from your property file
var kvPairs = {'key1':'value1',
'key2':'value2',
'key3':'value3'};
globalMap.put('keyValuePairs',kvPairs);
To extract the set from the GlobalMap:
// Method 1
// Grab directly from GlobalMap object.
var kvPairs = globalMap.get('keyValuePairs');
// Method 2
// Use the Mirth shorthand to search all map objects until the
// desired variable is located.
var kvPairs = $('keyValuePairs');
To iterate through the set:
// Method 1
// If you need to access both the keys and the associated values, then
// use a for in loop
for (var key in kvPairs)
{
var value = kvPairs[key];
// you now have key and value, and can use them as you see fit
}
// Method 2
// If you only need the values, and don't need the keys, then you can use
// the more familiar for each in loop
for each (var value in kvPairs)
{
// you now have value, and can use it as you see fit;
}