Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,8 @@ Server::Server(const std::string &serviceName, const std::string &advertisingNam
.onReadValue(CHARACTERISTIC_METHOD_CALLBACK_LAMBDA
{
const char *pTextString = self.getDataPointer<const char *>("text/string", "");
// for longer data, the reading device may ask to read starting at an offset (i.e, iOS devices read in 184 byte chunks)
pTextString += ServerUtils::getOffsetFromParameters(pParameters, strlen(pTextString));
self.methodReturnValue(pInvocation, pTextString, true);
})

Expand Down
28 changes: 27 additions & 1 deletion src/ServerUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,32 @@ void ServerUtils::getManagedObjects(GDBusMethodInvocation *pInvocation)
g_dbus_method_invocation_return_value(pInvocation, pParams);
}

// Sometimes you get an additional parameter back that the previous read was only partial and
// needs a subsequent chunk starting at "offset". If "offset" exists in the pParameters
// we need to move the char * that many bytes forward. As an example, this happens on iOS
// devices attempting a read of over 184 bytes.
//
// It is important that the maximum value not exceed the current data that this offset will
// be applied to. An attacker can easily ask for an offset that is well beyond the data they
// are supposed to have access to.
uint16_t ServerUtils::getOffsetFromParameters(GVariant *pParameters, uint16_t dataLength)
{
GVariant *params;
g_variant_get(pParameters, "(@a{sv})", &params);
uint16_t offset = 0;
GVariant *value = g_variant_lookup_value(params, "offset", NULL);
if (value)
{
g_variant_get(value, "q", &offset);
}
if (offset > dataLength)
{
Logger::error(SSTR << "Attempt to get read offset beyond scope of data. Offset: " << offset << " vs. maximum length: " << dataLength);
offset = dataLength;
}
return offset;
}

// WARNING: Hacky code - don't count on this working properly on all systems
//
// This routine will attempt to parse /proc/cpuinfo to return the CPU count/model. Results are cached on the first call, with
Expand Down Expand Up @@ -305,4 +331,4 @@ GVariant *ServerUtils::gvariantLocalTime()
return pVariant;
}

}; // namespace ggk
}; // namespace ggk
5 changes: 4 additions & 1 deletion src/ServerUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ struct ServerUtils
// Builds the response to the method call `GetManagedObjects` from the D-Bus interface `org.freedesktop.DBus.ObjectManager`
static void getManagedObjects(GDBusMethodInvocation *pInvocation);

// Devices will sometimes perform reads on long buffers in multiple chunks, this returns an offset if that occurs.
static uint16_t getOffsetFromParameters(GVariant *params, uint16_t dataLength);

// WARNING: Hacky code - don't count on this working properly on all systems
//
// This routine will attempt to parse /proc/cpuinfo to return the CPU count/model. Results are cached on the first call, with
Expand All @@ -53,4 +56,4 @@ struct ServerUtils
static GVariant *gvariantLocalTime();
};

}; // namespace ggk
}; // namespace ggk