if (DecisionResult::ALLOW != decision)
return decisionToRetCode(decision);
- KdbusConnectionInfo senderInfo(kconn->conn);
- /* check can recv */
- /* get sender information from kdbus */
+ /* We checked if we can send the message, but we also need to check if it will be able
+ * to be received on the other side. This looks like a duplicate check (since receiving
+ * also performs both checks) but it is done for security reasons.
+ *
+ * Consider this example ruleset. It implements a rule that the system overseer,
+ * and only it, can order hibernation from the freezer service.
+ *
+ * deny send member='hibernate'
+ * allow send member='hibernate' destination='freezer'
+ * deny recv member='hibernate'
+ * allow recv member='hibernate' sender='overseer'
+ *
+ * ┌──────────┐ ┌─────────┐
+ * │ overseer ├──OK──>│ freezer │
+ * └─┬────────┘ └─────────┘
+ * │ ^
+ * │ │
+ * │ ┌──────bad────┘
+ * └─bad─┼────────────┐
+ * │ │
+ * │ v
+ * ┌─┴─┐ ┌───┐
+ * │ X │ │ Y │
+ * └───┘ └───┘
+ *
+ * Now:
+ * - if receiver didn't check sender, freezer could end up taking orders from some X instead of only overseer.
+ * - if sender didn't check receiver, overseer could end up talking to some Y instead of only freezer.
+ *
+ * So unfortunately it has to be done redundantly. */
+
+ KdbusConnectionInfo senderInfo(kconn->conn); // get sender info from kdbus
+
r = prepareNames(sender, senderInfo, KdbusConnection::POLICY_CONN_INFO_NAME);
if (r < 0)
return r;
if (DecisionResult::ALLOW != decision)
return decisionToRetCode(decision);
+ // Check for a 'send' match as well, see the send function above for rationale
+
if (!sender)
sender = ":";