summaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus/loopback.c
diff options
context:
space:
mode:
authorBryan O'Donoghue2015-07-13 21:20:50 +0200
committerGreg Kroah-Hartman2015-07-14 00:42:01 +0200
commitc3bba87a7ab57e636a8c96ddd36fdedfefe4848c (patch)
tree1e2abf94991aba12ee3ee4a3d603b4ce4043e530 /drivers/staging/greybus/loopback.c
parentgreybus: loopback: add sink to loopback protocol (diff)
downloadkernel-qcow2-linux-c3bba87a7ab57e636a8c96ddd36fdedfefe4848c.tar.gz
kernel-qcow2-linux-c3bba87a7ab57e636a8c96ddd36fdedfefe4848c.tar.xz
kernel-qcow2-linux-c3bba87a7ab57e636a8c96ddd36fdedfefe4848c.zip
greybus: loopback: truncate maximum loop data to link size
Get maximum payload by way of gb_operation_get_payload_size_max() and truncate any requested loopback size greater than this value. RX of data from firmware over the specified size will not be accepted. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/loopback.c')
-rw-r--r--drivers/staging/greybus/loopback.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c
index 678690fbbc93..f490648648ce 100644
--- a/drivers/staging/greybus/loopback.c
+++ b/drivers/staging/greybus/loopback.c
@@ -34,6 +34,7 @@ struct gb_loopback {
int type;
u32 size;
+ u32 size_max;
int ms_wait;
struct gb_loopback_stats latency;
@@ -46,7 +47,6 @@ struct gb_loopback {
};
#define GB_LOOPBACK_MS_WAIT_MAX 1000
-#define GB_LOOPBACK_SIZE_MAX SZ_4K
/* Define get_version() routine */
define_get_version(gb_loopback, LOOPBACK);
@@ -122,8 +122,8 @@ static void gb_loopback_check_attr(struct gb_loopback *gb)
}
if (gb->ms_wait > GB_LOOPBACK_MS_WAIT_MAX)
gb->ms_wait = GB_LOOPBACK_MS_WAIT_MAX;
- if (gb->size > GB_LOOPBACK_SIZE_MAX)
- gb->size = GB_LOOPBACK_SIZE_MAX;
+ if (gb->size > gb->size_max)
+ gb->size = gb->size_max;
gb->error = 0;
gb_loopback_reset_stats(gb);
}
@@ -182,6 +182,7 @@ static int gb_loopback_sink(struct gb_loopback *gb,
do_gettimeofday(&ts);
retval = gb_operation_sync(gb->connection, GB_LOOPBACK_TYPE_SINK,
request, len + sizeof(*request), NULL, 0);
+
do_gettimeofday(&te);
elapsed_nsecs = timeval_to_ns(&te) - timeval_to_ns(&ts);
*tping = ns_to_timeval(elapsed_nsecs);
@@ -250,6 +251,7 @@ static int gb_loopback_ping(struct gb_loopback *gb, struct timeval *tping)
static int gb_loopback_request_recv(u8 type, struct gb_operation *operation)
{
struct gb_connection *connection = operation->connection;
+ struct gb_loopback *gb = connection->private;
struct gb_loopback_transfer_request *request;
struct gb_loopback_transfer_response *response;
u32 len;
@@ -273,6 +275,13 @@ static int gb_loopback_request_recv(u8 type, struct gb_operation *operation)
}
request = operation->request->payload;
len = le32_to_cpu(request->len);
+ if (len > gb->size_max) {
+ dev_err(&connection->dev,
+ "transfer request too large (%zu > %zu)\n",
+ len, gb->size_max);
+ return -EINVAL;
+ }
+
if (len) {
if (!gb_operation_response_alloc(operation, len)) {
dev_err(&connection->dev,
@@ -416,6 +425,14 @@ static int gb_loopback_connection_init(struct gb_connection *connection)
if (retval)
goto out_get_ver;
+ /* Calculate maximum payload */
+ gb->size_max = gb_operation_get_payload_size_max(connection);
+ if (gb->size_max <= sizeof(struct gb_loopback_transfer_request)) {
+ retval = -EINVAL;
+ goto out_get_ver;
+ }
+ gb->size_max -= sizeof(struct gb_loopback_transfer_request);
+
gb_loopback_reset_stats(gb);
gb->task = kthread_run(gb_loopback_fn, gb, "gb_loopback");
if (IS_ERR(gb->task)) {