[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Add check for maximum xenstore key lengths



Hi,

On 19/08/2025 12:52, Owen Smith wrote:
> Fail any xenstore call that exceeds the maximum lengths, as defined
> in xs_wire.h
> 
> Signed-off-by: Owen Smith <owen.smith@xxxxxxxxx>
> ---
>   src/xenbus/store.c | 159 ++++++++++++++++++++++++++++++++-------------
>   1 file changed, 114 insertions(+), 45 deletions(-)
> 
> diff --git a/src/xenbus/store.c b/src/xenbus/store.c
> index afb1954..1ce77ed 100644
> --- a/src/xenbus/store.c
> +++ b/src/xenbus/store.c
> @@ -1099,6 +1099,34 @@ RtlCaptureStackBackTrace(
>       __out_opt   PULONG  BackTraceHash
>       );
>   
> +static NTSTATUS
> +StoreCheckPathLength(
> +    __in_opt PSTR           Prefix,
> +    __in     PSTR           Node
> +    )

Could you replace the annotations with SAL2 ones (_In_, _In_opt_)?

> +{
> +    ULONG                   Length;
> +    ULONG                   MaximumLength;
> +
> +    if (Prefix != NULL) {
> +        MaximumLength = Prefix[0] == '/' ?

If Prefix is an empty string, the resulting path will be of the form 
"/Node". This check should take this case into account and use 
XENSTORE_ABS_PATH_MAX instead.

> +                        XENSTORE_ABS_PATH_MAX :
> +                        XENSTORE_REL_PATH_MAX;
> +        Length = (ULONG)strlen(Prefix) + 1;
> +    } else {
> +        MaximumLength = Node[0] == '/' ?
> +                        XENSTORE_ABS_PATH_MAX :
> +                        XENSTORE_REL_PATH_MAX;
> +        Length = 0;
> +    }
> +
> +    Length += (ULONG)strlen(Node) + 1;

I think you should check for overflow of Length, both due to the 
downcast to ULONG and the addition.

Also, is the +1 necessary here? I don't know if XENSTORE_*_PATH_MAX 
counts the null terminator.

> +
> +    return Length > MaximumLength ?
> +            STATUS_INVALID_BUFFER_SIZE :
> +            STATUS_SUCCESS;
> +}
> +
>   static NTSTATUS
>   StoreRead(
>       _In_ PINTERFACE                     Interface,
> @@ -1116,6 +1144,10 @@ StoreRead(
>       PXENBUS_STORE_BUFFER                Buffer;
>       NTSTATUS                            status;
>   
> +    status = StoreCheckPathLength(Prefix, Node);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
>       (VOID) RtlCaptureStackBackTrace(1, 1, &Caller, NULL);
>   
>       RtlZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST));
> @@ -1145,23 +1177,23 @@ StoreRead(
>       KeReleaseSpinLock(&Context->Lock, Irql);
>   
>       if (!NT_SUCCESS(status))
> -        goto fail1;
> +        goto fail2;
>   
>       Response = StoreSubmitRequest(Context, &Request);
>   
>       status = STATUS_NO_MEMORY;
>       if (Response == NULL)
> -        goto fail2;
> +        goto fail3;
>   
>       status = StoreCheckResponse(Response);
>       if (!NT_SUCCESS(status))
> -        goto fail3;
> +        goto fail4;
>   
>       Buffer = StoreCopyPayload(Context, Response, Caller);
>   
>       status = STATUS_NO_MEMORY;
>       if (Buffer == NULL)
> -        goto fail4;
> +        goto fail5;
>   
>       StoreFreeResponse(Response);
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
> @@ -1170,14 +1202,15 @@ StoreRead(
>   
>       return STATUS_SUCCESS;
>   
> +fail5:
>   fail4:
> -fail3:
>       StoreFreeResponse(Response);
>   
> +fail3:
>   fail2:
> -fail1:
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
>   
> +fail1:
>       return status;
>   }
>   
> @@ -1195,6 +1228,10 @@ StoreWrite(
>       PXENBUS_STORE_RESPONSE              Response;
>       NTSTATUS                            status;
>   
> +    status = StoreCheckPathLength(Prefix, Node);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +

StoreWrite is indirectly called by StoreVPrintf, and eventually 
StorePrintf which already checks for this, so another check here 
shouldn't be necessary. I think checking at the interface boundaries 
should be enough unless the path is further transformed.

>       RtlZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST));
>   
>       KeAcquireSpinLock(&Context->Lock, &Irql);
> @@ -1224,30 +1261,31 @@ StoreWrite(
>       KeReleaseSpinLock(&Context->Lock, Irql);
>   
>       if (!NT_SUCCESS(status))
> -        goto fail1;
> +        goto fail2;
>   
>       Response = StoreSubmitRequest(Context, &Request);
>   
>       status = STATUS_NO_MEMORY;
>       if (Response == NULL)
> -        goto fail2;
> +        goto fail3;
>   
>       status = StoreCheckResponse(Response);
>       if (!NT_SUCCESS(status))
> -        goto fail3;
> +        goto fail4;
>   
>       StoreFreeResponse(Response);
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
>   
>       return STATUS_SUCCESS;
>   
> -fail3:
> +fail4:
>       StoreFreeResponse(Response);
>   
> +fail3:
>   fail2:
> -fail1:
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
>   
> +fail1:
>       return status;
>   }
>   
> @@ -1326,6 +1364,10 @@ StorePrintf(
>       va_list                             Arguments;
>       NTSTATUS                            status;
>   
> +    status = StoreCheckPathLength(Prefix, Node);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
>       va_start(Arguments, Format);
>       status = StoreVPrintf(Interface,
>                               Transaction,
> @@ -1336,6 +1378,9 @@ StorePrintf(
>       va_end(Arguments);
>   
>       return status;
> +
> +fail1:
> +    return status;
>   }
>   
>   static NTSTATUS
> @@ -1352,6 +1397,10 @@ StoreRemove(
>       PXENBUS_STORE_RESPONSE              Response;
>       NTSTATUS                            status;
>   
> +    status = StoreCheckPathLength(Prefix, Node);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
>       RtlZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST));
>   
>       KeAcquireSpinLock(&Context->Lock, &Irql);
> @@ -1379,30 +1428,31 @@ StoreRemove(
>       KeReleaseSpinLock(&Context->Lock, Irql);
>   
>       if (!NT_SUCCESS(status))
> -        goto fail1;
> +        goto fail2;
>   
>       Response = StoreSubmitRequest(Context, &Request);
>   
>       status = STATUS_NO_MEMORY;
>       if (Response == NULL)
> -        goto fail2;
> +        goto fail3;
>   
>       status = StoreCheckResponse(Response);
>       if (!NT_SUCCESS(status))
> -        goto fail3;
> +        goto fail4;
>   
>       StoreFreeResponse(Response);
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
>   
>       return STATUS_SUCCESS;
>   
> -fail3:
> +fail4:
>       StoreFreeResponse(Response);
>   
> +fail3:
>   fail2:
> -fail1:
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
>   
> +fail1:
>       return status;
>   }
>   
> @@ -1423,6 +1473,10 @@ StoreDirectory(
>       PXENBUS_STORE_BUFFER                Buffer;
>       NTSTATUS                            status;
>   
> +    status = StoreCheckPathLength(Prefix, Node);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
>       (VOID) RtlCaptureStackBackTrace(1, 1, &Caller, NULL);
>   
>       RtlZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST));
> @@ -1452,27 +1506,27 @@ StoreDirectory(
>       KeReleaseSpinLock(&Context->Lock, Irql);
>   
>       if (!NT_SUCCESS(status))
> -        goto fail1;
> +        goto fail2;
>   
>       Response = StoreSubmitRequest(Context, &Request);
>   
>       status = STATUS_NO_MEMORY;
>       if (Response == NULL)
> -        goto fail2;
> +        goto fail3;
>   
>       status = StoreCheckResponse(Response);
>       if (!NT_SUCCESS(status))
> -        goto fail3;
> +        goto fail4;
>   
>       Buffer = StoreCopyPayload(Context, Response, Caller);
>   
>       status = STATUS_NO_MEMORY;
>       if (Buffer == NULL)
> -        goto fail4;
> +        goto fail5;
>   
>       status = STATUS_OBJECT_PATH_NOT_FOUND;
>       if (Buffer->Length == 0)
> -        goto fail5;
> +        goto fail6;
>   
>       StoreFreeResponse(Response);
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
> @@ -1481,17 +1535,18 @@ StoreDirectory(
>   
>       return STATUS_SUCCESS;
>   
> -fail5:
> +fail6:
>       StoreFreePayload(Context, Buffer);
>   
> +fail5:
>   fail4:
> -fail3:
>       StoreFreeResponse(Response);
>   
> +fail3:
>   fail2:
> -fail1:
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
>   
> +fail1:
>       return status;
>   }
>   
> @@ -1672,11 +1727,15 @@ StoreWatchAdd(
>       KIRQL                           Irql;
>       NTSTATUS                        status;
>   
> +    status = StoreCheckPathLength(Prefix, Node);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
>       *Watch = __StoreAllocate(sizeof (XENBUS_STORE_WATCH));
>   
>       status = STATUS_NO_MEMORY;
>       if (*Watch == NULL)
> -        goto fail1;
> +        goto fail2;
>   
>       (*Watch)->Magic = STORE_WATCH_MAGIC;
>       (VOID) RtlCaptureStackBackTrace(1, 1, &(*Watch)->Caller, NULL);
> @@ -1690,7 +1749,7 @@ StoreWatchAdd(
>   
>       status = STATUS_NO_MEMORY;
>       if (Path == NULL)
> -        goto fail2;
> +        goto fail3;
>   
>       status = (Prefix == NULL) ?
>                RtlStringCbPrintfA(Path, Length, "%s", Node) :
> @@ -1736,24 +1795,24 @@ StoreWatchAdd(
>   
>       status = STATUS_NO_MEMORY;
>       if (Response == NULL)
> -        goto fail3;
> +        goto fail4;
>   
>       status = StoreCheckResponse(Response);
>       if (!NT_SUCCESS(status))
> -        goto fail4;
> +        goto fail5;
>   
>       StoreFreeResponse(Response);
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
>   
>       return STATUS_SUCCESS;
>   
> -fail4:
> -    Error("fail4\n");
> +fail5:
> +    Error("fail5\n");
>   
>       StoreFreeResponse(Response);
>   
> -fail3:
> -    Error("fail3\n");
> +fail4:
> +    Error("fail4\n");
>   
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
>   
> @@ -1770,8 +1829,8 @@ fail3:
>   
>       __StoreFree(Path);
>   
> -fail2:
> -    Error("fail2\n");
> +fail3:
> +    Error("fail3\n");
>   
>       (*Watch)->Caller = NULL;
>       (*Watch)->Magic = 0;
> @@ -1779,6 +1838,9 @@ fail2:
>       ASSERT(IsZeroMemory(*Watch, sizeof (XENBUS_STORE_WATCH)));
>       __StoreFree(*Watch);
>   
> +fail2:
> +    Error("fail2\n");
> +
>   fail1:
>       Error("fail1 (%08x)\n", status);
>   
> @@ -2057,11 +2119,15 @@ StorePermissionsSet(
>       PSTR                                PermissionString;
>       PSTR                                Segment;
>   
> +    status = StoreCheckPathLength(Prefix, Node);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
>       PermissionString = __StoreAllocate(XENSTORE_PAYLOAD_MAX);
>   
>       status = STATUS_NO_MEMORY;
>       if (PermissionString == NULL)
> -        goto fail1;
> +        goto fail2;
>   
>       if (Prefix == NULL)
>           Length = (ULONG)strlen(Node) + sizeof (CHAR);
> @@ -2071,7 +2137,7 @@ StorePermissionsSet(
>       Path = __StoreAllocate(Length);
>   
>       if (Path == NULL)
> -        goto fail2;
> +        goto fail3;
>   
>       status = (Prefix == NULL) ?
>                RtlStringCbPrintfA(Path, Length, "%s", Node) :
> @@ -2088,7 +2154,7 @@ StorePermissionsSet(
>                                            Length,
>                                            &Used);
>           if (!NT_SUCCESS(status))
> -            goto fail3;
> +            goto fail4;
>   
>           Segment += Used;
>           Length -= Used;
> @@ -2108,17 +2174,17 @@ StorePermissionsSet(
>       KeReleaseSpinLock(&Context->Lock, Irql);
>   
>       if (!NT_SUCCESS(status))
> -        goto fail4;
> +        goto fail5;
>   
>       Response = StoreSubmitRequest(Context, &Request);
>   
>       status = STATUS_NO_MEMORY;
>       if (Response == NULL)
> -        goto fail5;
> +        goto fail6;
>   
>       status = StoreCheckResponse(Response);
>       if (!NT_SUCCESS(status))
> -        goto fail6;
> +        goto fail7;
>   
>       StoreFreeResponse(Response);
>       ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
> @@ -2128,9 +2194,12 @@ StorePermissionsSet(
>   
>       return STATUS_SUCCESS;
>   
> +fail7:
> +    Error("fail7\n");
> +    StoreFreeResponse(Response);
> +
>   fail6:
>       Error("fail6\n");
> -    StoreFreeResponse(Response);
>   
>   fail5:
>       Error("fail5\n");
> @@ -2138,17 +2207,17 @@ fail5:
>   fail4:
>       Error("fail4\n");
>   
> +    __StoreFree(Path);
> +    ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
> +
>   fail3:
>       Error("fail3\n");
>   
> -    __StoreFree(Path);
> -    ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
> +    __StoreFree(PermissionString);
>   
>   fail2:
>       Error("fail2\n");
>   
> -    __StoreFree(PermissionString);
> -
>   fail1:
>       Error("fail1 (%08x)\n", status);
>   



Ngoc Tu Dinh | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.