security: validate <delay> 'from' per XEP-0203 §4
Some checks failed
CI Code / Check spelling (pull_request) Successful in 19s
CI Code / Check coding style (pull_request) Successful in 34s
CI Code / Code Coverage (pull_request) Failing after 9m56s
CI Code / Linux (arch) (pull_request) Failing after 13m41s
CI Code / Linux (debian) (pull_request) Failing after 15m0s
CI Code / Linux (ubuntu) (pull_request) Failing after 15m9s
Some checks failed
CI Code / Check spelling (pull_request) Successful in 19s
CI Code / Check coding style (pull_request) Successful in 34s
CI Code / Code Coverage (pull_request) Failing after 9m56s
CI Code / Linux (arch) (pull_request) Failing after 13m41s
CI Code / Linux (debian) (pull_request) Failing after 15m0s
CI Code / Linux (ubuntu) (pull_request) Failing after 15m9s
Reject client-forged <delay> timestamps in the incoming message handlers. The displayed timestamp was taken from an unfiltered delay scan, so a remote peer could place a message anywhere in history by injecting <delay from='...' stamp='...'>. - _handle_groupchat: oldest delay from room bare JID -> room domain -> our server domain, else now. - _handle_muc_private_message / _handle_chat: delay from our server domain -> sender domain, else now. Add stanza_get_oldest_delay_from(); stanza_get_oldest_delay() delegates with from=NULL. The MAM <forwarded> path stays unfiltered (trusted by construction). The original PR's XEP-0359 <stanza-id> 'by' edits are dropped: master already validates 'by'.
This commit is contained in:
@@ -1132,12 +1132,17 @@ _handle_groupchat(xmpp_stanza_t* const stanza)
|
|||||||
message->timestamp = NULL;
|
message->timestamp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we want to display the oldest delay
|
// XEP-0203 §4: trust <delay> only from the room or our server, not a client-forged stamp
|
||||||
message->timestamp = stanza_get_oldest_delay(stanza);
|
message->timestamp = stanza_get_oldest_delay_from(stanza, from_jid->barejid);
|
||||||
|
if (!message->timestamp && from_jid->domainpart) {
|
||||||
// now this has nothing to do with MUC history
|
message->timestamp = stanza_get_oldest_delay_from(stanza, from_jid->domainpart);
|
||||||
// it's just setting the time to the received time so upon displaying we can use this time
|
}
|
||||||
// for example in win_println_incoming_muc_msg()
|
if (!message->timestamp) {
|
||||||
|
const char* my_domain = connection_get_domain();
|
||||||
|
if (my_domain) {
|
||||||
|
message->timestamp = stanza_get_oldest_delay_from(stanza, my_domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!message->timestamp) {
|
if (!message->timestamp) {
|
||||||
message->timestamp = g_date_time_new_now_local();
|
message->timestamp = g_date_time_new_now_local();
|
||||||
}
|
}
|
||||||
@@ -1268,7 +1273,15 @@ _handle_muc_private_message(xmpp_stanza_t* const stanza)
|
|||||||
_receive_omemo(stanza, message);
|
_receive_omemo(stanza, message);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
message->timestamp = stanza_get_delay(stanza);
|
// XEP-0203 §4: trust <delay> only from a server domain, not a client-forged stamp
|
||||||
|
const char* my_domain = connection_get_domain();
|
||||||
|
message->timestamp = stanza_get_delay_from(stanza, my_domain);
|
||||||
|
if (!message->timestamp && message->from_jid->domainpart) {
|
||||||
|
message->timestamp = stanza_get_delay_from(stanza, message->from_jid->domainpart);
|
||||||
|
}
|
||||||
|
if (!message->timestamp) {
|
||||||
|
message->timestamp = g_date_time_new_now_local();
|
||||||
|
}
|
||||||
message->body = xmpp_message_get_body(stanza);
|
message->body = xmpp_message_get_body(stanza);
|
||||||
|
|
||||||
if (!message->plain && !message->body) {
|
if (!message->plain && !message->body) {
|
||||||
@@ -1419,8 +1432,12 @@ _handle_chat(xmpp_stanza_t* const stanza, gboolean is_mam, gboolean is_carbon, c
|
|||||||
// timestamp provided outside like in a <forwarded> by MAM
|
// timestamp provided outside like in a <forwarded> by MAM
|
||||||
message->timestamp = timestamp;
|
message->timestamp = timestamp;
|
||||||
} else {
|
} else {
|
||||||
// timestamp in the message stanza or use time of receival (now)
|
// XEP-0203 §4: trust <delay> only from a server domain, not a client-forged stamp
|
||||||
message->timestamp = stanza_get_delay(stanza);
|
const char* my_domain = connection_get_domain();
|
||||||
|
message->timestamp = stanza_get_delay_from(stanza, my_domain);
|
||||||
|
if (!message->timestamp && jid->domainpart) {
|
||||||
|
message->timestamp = stanza_get_delay_from(stanza, jid->domainpart);
|
||||||
|
}
|
||||||
if (!message->timestamp) {
|
if (!message->timestamp) {
|
||||||
message->timestamp = g_date_time_new_now_local();
|
message->timestamp = g_date_time_new_now_local();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1163,7 +1163,7 @@ _stanza_get_delay_timestamp_xep0091(xmpp_stanza_t* const x_stanza)
|
|||||||
}
|
}
|
||||||
|
|
||||||
GDateTime*
|
GDateTime*
|
||||||
stanza_get_delay_from(xmpp_stanza_t* const stanza, gchar* from)
|
stanza_get_delay_from(xmpp_stanza_t* const stanza, const char* const from)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t* delay = NULL;
|
xmpp_stanza_t* delay = NULL;
|
||||||
|
|
||||||
@@ -1195,6 +1195,12 @@ stanza_get_delay_from(xmpp_stanza_t* const stanza, gchar* from)
|
|||||||
|
|
||||||
GDateTime*
|
GDateTime*
|
||||||
stanza_get_oldest_delay(xmpp_stanza_t* const stanza)
|
stanza_get_oldest_delay(xmpp_stanza_t* const stanza)
|
||||||
|
{
|
||||||
|
return stanza_get_oldest_delay_from(stanza, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDateTime*
|
||||||
|
stanza_get_oldest_delay_from(xmpp_stanza_t* const stanza, const char* const from)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t* child;
|
xmpp_stanza_t* child;
|
||||||
const char* child_name;
|
const char* child_name;
|
||||||
@@ -1205,27 +1211,37 @@ stanza_get_oldest_delay(xmpp_stanza_t* const stanza)
|
|||||||
child_name = xmpp_stanza_get_name(child);
|
child_name = xmpp_stanza_get_name(child);
|
||||||
|
|
||||||
if (child_name && g_strcmp0(child_name, STANZA_NAME_DELAY) == 0) {
|
if (child_name && g_strcmp0(child_name, STANZA_NAME_DELAY) == 0) {
|
||||||
|
if (from) {
|
||||||
|
const char* child_from = xmpp_stanza_get_attribute(child, STANZA_ATTR_FROM);
|
||||||
|
if (!child_from || g_strcmp0(child_from, from) != 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
GDateTime* tmp = _stanza_get_delay_timestamp_xep0203(child);
|
GDateTime* tmp = _stanza_get_delay_timestamp_xep0203(child);
|
||||||
|
|
||||||
if (oldest == NULL) {
|
if (oldest == NULL) {
|
||||||
oldest = tmp;
|
oldest = tmp;
|
||||||
} else if (g_date_time_compare(oldest, tmp) == 1) {
|
} else if (tmp && g_date_time_compare(oldest, tmp) == 1) {
|
||||||
g_date_time_unref(oldest);
|
g_date_time_unref(oldest);
|
||||||
oldest = tmp;
|
oldest = tmp;
|
||||||
} else {
|
} else if (tmp) {
|
||||||
g_date_time_unref(tmp);
|
g_date_time_unref(tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child_name && g_strcmp0(child_name, STANZA_NAME_X) == 0) {
|
if (child_name && g_strcmp0(child_name, STANZA_NAME_X) == 0) {
|
||||||
|
if (from) {
|
||||||
|
const char* child_from = xmpp_stanza_get_attribute(child, STANZA_ATTR_FROM);
|
||||||
|
if (!child_from || g_strcmp0(child_from, from) != 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
GDateTime* tmp = _stanza_get_delay_timestamp_xep0091(child);
|
GDateTime* tmp = _stanza_get_delay_timestamp_xep0091(child);
|
||||||
|
|
||||||
if (oldest == NULL) {
|
if (oldest == NULL) {
|
||||||
oldest = tmp;
|
oldest = tmp;
|
||||||
} else if (g_date_time_compare(oldest, tmp) == 1) {
|
} else if (tmp && g_date_time_compare(oldest, tmp) == 1) {
|
||||||
g_date_time_unref(oldest);
|
g_date_time_unref(oldest);
|
||||||
oldest = tmp;
|
oldest = tmp;
|
||||||
} else {
|
} else if (tmp) {
|
||||||
g_date_time_unref(tmp);
|
g_date_time_unref(tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -305,8 +305,9 @@ xmpp_stanza_t* stanza_create_mediated_invite(xmpp_ctx_t* ctx, const char* const
|
|||||||
gboolean stanza_contains_chat_state(xmpp_stanza_t* stanza);
|
gboolean stanza_contains_chat_state(xmpp_stanza_t* stanza);
|
||||||
|
|
||||||
GDateTime* stanza_get_delay(xmpp_stanza_t* const stanza);
|
GDateTime* stanza_get_delay(xmpp_stanza_t* const stanza);
|
||||||
GDateTime* stanza_get_delay_from(xmpp_stanza_t* const stanza, gchar* from);
|
GDateTime* stanza_get_delay_from(xmpp_stanza_t* const stanza, const char* const from);
|
||||||
GDateTime* stanza_get_oldest_delay(xmpp_stanza_t* const stanza);
|
GDateTime* stanza_get_oldest_delay(xmpp_stanza_t* const stanza);
|
||||||
|
GDateTime* stanza_get_oldest_delay_from(xmpp_stanza_t* const stanza, const char* const from);
|
||||||
|
|
||||||
gboolean stanza_is_muc_presence(xmpp_stanza_t* const stanza);
|
gboolean stanza_is_muc_presence(xmpp_stanza_t* const stanza);
|
||||||
gboolean stanza_is_muc_self_presence(xmpp_stanza_t* const stanza,
|
gboolean stanza_is_muc_self_presence(xmpp_stanza_t* const stanza,
|
||||||
|
|||||||
Reference in New Issue
Block a user