Dear Fiasco.OC developers,
while working with Genode on top of Fiasco.OC, I've encountered the following problem. When I transfer ipc-gates via ipc between tasks, it comes to the point where a task receives a gate it already owns. These duplicates are detected due to an additional identifier that is transfered together with the gate. To detect fraud (whether somebody has send an invalid gate/id combination) the received gate gets compared with the locally available one via "l4_task_cap_equal". Now, the problem is "l4_task_cap_equal" often fails even when both capabilities point to the same ipc-gate. The following code-snippet demonstrates this issue:
... tag = l4_task_cap_equal(L4_BASE_TASK_CAP, i->kcap(), rcv_cap); if (!l4_msgtag_label(tag)) { unsigned long id1 = l4_debugger_global_id(i->kcap()), id2 = l4_debugger_global_id(rcv_cap); printf("my_cap=%lx (id=%lx) rcv_cap=%lx (id=%lx)", i->kcap(), id1, rcv_cap, id2); if (id1 == id2) enter_kdebug("FAIL"); } ...
This snippet is executed after a thread in the roottask received from another thread of the same task a capability via IPC. Thereby rcv_cap is the cap that was received via ipc and i->kcap() is the cap that was retrieved via the additional transfered identifier. When executed I get the following output:
... my_cap=20f000 (id=12) rcv_cap=205000 (id=12) --------------------------------------------------------------------- CPU 0 [00145e81]: FAIL [ entrypoint] jdb:
The debugger's global id (here: 12) indicates that both capabilities reference the same object. Nevertheless, the equality test fails. Can you confirm that this is undesired syscall's behaviour, or do I miss something important?
The attached kernel patch fixes the problem for me, but may introduce other problems (e.g.: not sure whether obj() returns always valid pointers).
Regards Stefan
On Wed, 2012-04-18 at 15:01 +0200, Stefan kalkowski wrote:
Dear Fiasco.OC developers,
while working with Genode on top of Fiasco.OC, I've encountered the following problem. When I transfer ipc-gates via ipc between tasks, it comes to the point where a task receives a gate it already owns. These duplicates are detected due to an additional identifier that is transfered together with the gate. To detect fraud (whether somebody has send an invalid gate/id combination) the received gate gets compared with the locally available one via "l4_task_cap_equal". Now, the problem is "l4_task_cap_equal" often fails even when both capabilities point to the same ipc-gate. The following code-snippet demonstrates this issue:
... tag = l4_task_cap_equal(L4_BASE_TASK_CAP, i->kcap(), rcv_cap); if (!l4_msgtag_label(tag)) { unsigned long id1 = l4_debugger_global_id(i->kcap()), id2 = l4_debugger_global_id(rcv_cap); printf("my_cap=%lx (id=%lx) rcv_cap=%lx (id=%lx)", i->kcap(), id1, rcv_cap, id2); if (id1 == id2) enter_kdebug("FAIL"); } ...
This snippet is executed after a thread in the roottask received from another thread of the same task a capability via IPC. Thereby rcv_cap is the cap that was received via ipc and i->kcap() is the cap that was retrieved via the additional transfered identifier. When executed I get the following output:
... my_cap=20f000 (id=12) rcv_cap=205000 (id=12)
CPU 0 [00145e81]: FAIL
[ entrypoint] jdb:
The debugger's global id (here: 12) indicates that both capabilities reference the same object. Nevertheless, the equality test fails. Can you confirm that this is undesired syscall's behaviour, or do I miss something important?
Yes, you missed the rights assigned to the capabilities. Two capabilities are equal if they are exactly equal. This means they must point to the same object and have exactly the same rights.
The attached kernel patch fixes the problem for me, but may introduce other problems (e.g.: not sure whether obj() returns always valid pointers).
The patch uses a debugging feature of the Kobject class and additionally removes the rights check. Note, the object pointers in two capabilities may also differ if they point to the same kernel object but have different rights!
Hi Alexander,
thanks for your explanations.
On 19.04.2012 17:36, Alexander Warg wrote:
Yes, you missed the rights assigned to the capabilities. Two capabilities are equal if they are exactly equal. This means they must point to the same object and have exactly the same rights.
Ok, in that case I think the documentation is misleading, citation:
"Test if two capabilities point to the same object."
Nevertheless, I already recognized the rights being encountered in the comparison when looking at the kernel-source. From my understanding the two least significant bits of the kobject_iface pointer are used for that. But they're equal in my situation, as well as the kernel-object the capabilities point to. Nevertheless, the kobject_iface pointer differs between both. When using the original source and adding the following prints to Task::sys_caps_equal:
printf("cap a: kobject=%lx rights=%x obj()=%lx\n", c_a.obj()->kobject_start_addr(), c_a.rights(), c_a.obj()); printf("cap b: kobject=%lx rights=%x obj()=%lx\n", c_b.obj()->kobject_start_addr(), c_b.rights(), c_b.obj()); printf("a == b ? %x\n", (c_a == c_b));
I get for instance the following output:
cap a: kobject=fd9b4ec0 rights=3 obj()=fd9b4efc cap b: kobject=fd9b4ec0 rights=3 obj()=fd9b4ec0 a == b ? 0
Can you please shed light on this behaviour? In what situation do I have differing kobject_iface objects (with the same rights) that represent actually the same kobject?
The patch uses a debugging feature of the Kobject class and additionally removes the rights check. Note, the object pointers in two capabilities may also differ if they point to the same kernel object but have different rights!
Sorry, I didn't recognized "kobject_start_addr()" being a debugging feature. The patch just circumnavigated my actual problem. I didn't wanted you to apply it mainline ;-).
Regards Stefan
l4-hackers@os.inf.tu-dresden.de