]> xenbits.xensource.com Git - people/pauldu/xenbus.git/commitdiff
Add support for changing key permissions to the STORE interface
authorRafal Wojdyla <omeg@invisiblethingslab.com>
Fri, 11 Sep 2015 12:30:44 +0000 (14:30 +0200)
committerPaul Durrant <paul.durrant@citrix.com>
Fri, 11 Sep 2015 15:43:31 +0000 (16:43 +0100)
STORE interface now includes a function to change key permissions. This
allows granting key access to other, non-privileged domains.

Signed-off-by: Rafal Wojdyla <omeg@invisiblethingslab.com>
Cosmetic tweaking

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
include/store_interface.h
src/xenbus/store.c

index 5bcbba3d1a2aa8052bc629c7a5ed417c2d001cf1..52f1a1dde59228a3cbd794228ede031b4d57fb3b 100644 (file)
@@ -50,6 +50,23 @@ typedef struct _XENBUS_STORE_TRANSACTION    XENBUS_STORE_TRANSACTION, *PXENBUS_S
 */
 typedef struct _XENBUS_STORE_WATCH          XENBUS_STORE_WATCH, *PXENBUS_STORE_WATCH;
 
+/*! \typedef XENBUS_STORE_PERMISSION_MASK
+    \brief Bitmask of XenStore key permissions
+*/
+typedef enum _XENBUS_STORE_PERMISSION_MASK {
+    XENBUS_STORE_PERM_NONE = 0,
+    XENBUS_STORE_PERM_READ = 1,
+    XENBUS_STORE_PERM_WRITE = 2,
+} XENBUS_STORE_PERMISSION_MASK;
+
+/*! \typedef XENBUS_STORE_PERMISSION
+    \brief XenStore key permissions entry for a single domain
+*/
+typedef struct _XENBUS_STORE_PERMISSION {
+    USHORT                          Domain;
+    XENBUS_STORE_PERMISSION_MASK    Mask;
+} XENBUS_STORE_PERMISSION, *PXENBUS_STORE_PERMISSION;
+
 /*! \typedef XENBUS_STORE_ACQUIRE
     \brief Acquire a reference to the STORE interface
 
@@ -247,10 +264,36 @@ typedef VOID
     IN  PINTERFACE  Interface
     );
 
+/*! \typedef XENBUS_STORE_PERMISSIONS_SET
+    \brief Set permissions for a XenStore key
+
+    \param Interface The interface header
+    \param Transaction The transaction handle (NULL if this is not
+    part of a transaction)
+    \param Prefix An optional prefix for the \a Node
+    \param Node The concatenation of the \a Prefix and this value specifies
+    the XenStore key to set permissions of
+    \param Permissions An array of permissions to set
+    \param NumberPermissions Number of elements in the \a Permissions array
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_PERMISSIONS_SET)(
+    IN  PINTERFACE                  Interface,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction OPTIONAL,
+    IN  PCHAR                       Prefix OPTIONAL,
+    IN  PCHAR                       Node,
+    IN  PXENBUS_STORE_PERMISSION    Permissions,
+    IN  ULONG                       NumberPermissions
+    );
+
 // {86824C3B-D34E-4753-B281-2F1E3AD214D7}
 DEFINE_GUID(GUID_XENBUS_STORE_INTERFACE, 
 0x86824c3b, 0xd34e, 0x4753, 0xb2, 0x81, 0x2f, 0x1e, 0x3a, 0xd2, 0x14, 0xd7);
 
+/*! \struct _XENBUS_STORE_INTERFACE_V1
+    \brief STORE interface version 1
+    \ingroup interfaces
+*/
 struct _XENBUS_STORE_INTERFACE_V1 {
     INTERFACE                       Interface;
     XENBUS_STORE_ACQUIRE            StoreAcquire;
@@ -267,11 +310,28 @@ struct _XENBUS_STORE_INTERFACE_V1 {
     XENBUS_STORE_POLL               StorePoll;
 };
 
-/*! \struct _XENBUS_STORE_INTERFACE_V1
-    \brief STORE interface version 1
+/*! \struct _XENBUS_STORE_INTERFACE_V2
+    \brief STORE interface version 2
     \ingroup interfaces
 */
-typedef struct _XENBUS_STORE_INTERFACE_V1 XENBUS_STORE_INTERFACE, *PXENBUS_STORE_INTERFACE;
+struct _XENBUS_STORE_INTERFACE_V2 {
+    INTERFACE                       Interface;
+    XENBUS_STORE_ACQUIRE            StoreAcquire;
+    XENBUS_STORE_RELEASE            StoreRelease;
+    XENBUS_STORE_FREE               StoreFree;
+    XENBUS_STORE_READ               StoreRead;
+    XENBUS_STORE_PRINTF             StorePrintf;
+    XENBUS_STORE_PERMISSIONS_SET    StorePermissionsSet;
+    XENBUS_STORE_REMOVE             StoreRemove;
+    XENBUS_STORE_DIRECTORY          StoreDirectory;
+    XENBUS_STORE_TRANSACTION_START  StoreTransactionStart;
+    XENBUS_STORE_TRANSACTION_END    StoreTransactionEnd;
+    XENBUS_STORE_WATCH_ADD          StoreWatchAdd;
+    XENBUS_STORE_WATCH_REMOVE       StoreWatchRemove;
+    XENBUS_STORE_POLL               StorePoll;
+};
+
+typedef struct _XENBUS_STORE_INTERFACE_V2 XENBUS_STORE_INTERFACE, *PXENBUS_STORE_INTERFACE;
 
 /*! \def XENBUS_STORE
     \brief Macro at assist in method invocation
@@ -282,7 +342,7 @@ typedef struct _XENBUS_STORE_INTERFACE_V1 XENBUS_STORE_INTERFACE, *PXENBUS_STORE
 #endif  // _WINDLL
 
 #define XENBUS_STORE_INTERFACE_VERSION_MIN  1
-#define XENBUS_STORE_INTERFACE_VERSION_MAX  1
+#define XENBUS_STORE_INTERFACE_VERSION_MAX  2
 
 #endif  // _XENBUS_STORE_INTERFACE_H
 
index c54b0f005b08f7d9c8f134311d175eed55fa6091..127bb986f4a74f1394860a0bf849c1d9a9fba70d 100644 (file)
@@ -442,7 +442,6 @@ StoreIgnoreHeaderType(
     case XS_RELEASE:
     case XS_GET_DOMAIN_PATH:
     case XS_MKDIR:
-    case XS_SET_PERMS:
     case XS_IS_DOMAIN_INTRODUCED:
     case XS_RESUME:
     case XS_SET_TARGET:
@@ -470,6 +469,7 @@ StoreVerifyHeader(
         Header->type != XS_TRANSACTION_END &&
         Header->type != XS_WRITE &&
         Header->type != XS_RM &&
+        Header->type != XS_SET_PERMS &&
         Header->type != XS_WATCH_EVENT &&
         Header->type != XS_ERROR &&
         !StoreIgnoreHeaderType(Header->type)) {
@@ -936,7 +936,7 @@ StoreSubmitRequest(
            Response->Header.type == XS_ERROR ||
            Response->Header.type == Request->Header.type);
 
-    RtlZeroMemory(Request, sizeof(XENBUS_STORE_REQUEST));
+    RtlZeroMemory(Request, sizeof (XENBUS_STORE_REQUEST));
 
     KeLowerIrql(Irql);
 
@@ -1816,6 +1816,178 @@ StorePoll(
     KeReleaseSpinLockFromDpcLevel(&Context->Lock);
 }
 
+static NTSTATUS
+StorePermissionToString(
+    IN  PXENBUS_STORE_PERMISSION    Permission,
+    OUT PCHAR                       Buffer,
+    IN  ULONG                       BufferSize,
+    OUT PULONG                      UsedSize
+    )
+{
+    size_t                          Remaining;
+    NTSTATUS                        status;
+
+    ASSERT(BufferSize > 1);
+
+    switch (Permission->Mask) {
+    case XENBUS_STORE_PERM_NONE:
+        *Buffer = 'n';
+        break;
+
+    case XENBUS_STORE_PERM_READ:
+        *Buffer = 'r';
+        break;
+
+    case XENBUS_STORE_PERM_WRITE:
+        *Buffer = 'w';
+        break;
+
+    case XENBUS_STORE_PERM_READ | XENBUS_STORE_PERM_WRITE:
+        *Buffer = 'b';
+        break;
+
+    default:
+        status = STATUS_INVALID_PARAMETER;
+        goto fail1;
+    }
+
+    status = RtlStringCbPrintfExA(Buffer + 1,
+                                  BufferSize - 1,
+                                  NULL,
+                                  &Remaining,
+                                  0,
+                                  "%u",
+                                  Permission->Domain);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    *UsedSize = BufferSize - (ULONG)Remaining + 1;
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static NTSTATUS
+StorePermissionsSet(
+    IN  PINTERFACE                  Interface,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction OPTIONAL,
+    IN  PCHAR                       Prefix OPTIONAL,
+    IN  PCHAR                       Node,
+    IN  PXENBUS_STORE_PERMISSION    Permissions,
+    IN  ULONG                       NumberPermissions
+    )
+{
+    PXENBUS_STORE_CONTEXT           Context = Interface->Context;
+    XENBUS_STORE_REQUEST            Request;
+    PXENBUS_STORE_RESPONSE          Response;
+    NTSTATUS                        status;
+    ULONG                           Index;
+    ULONG                           Length;
+    ULONG                           Used;
+    PCHAR                           Path;
+    PCHAR                           PermissionString;
+    PCHAR                           Segment;
+
+    PermissionString = __StoreAllocate(XENSTORE_PAYLOAD_MAX);
+
+    status = STATUS_NO_MEMORY;
+    if (PermissionString == NULL)
+        goto fail1;
+
+    if (Prefix == NULL)
+        Length = (ULONG)strlen(Node) + sizeof (CHAR);
+    else
+        Length = (ULONG)strlen(Prefix) + 1 + (ULONG)strlen(Node) + sizeof (CHAR);
+
+    Path = __StoreAllocate(Length);
+
+    if (Path == NULL)
+        goto fail2;
+
+    status = (Prefix == NULL) ?
+             RtlStringCbPrintfA(Path, Length, "%s", Node) :
+             RtlStringCbPrintfA(Path, Length, "%s/%s", Prefix, Node);
+    ASSERT(NT_SUCCESS(status));
+
+    RtlZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST));
+
+    for (Index = 0, Segment = PermissionString, Length = XENSTORE_PAYLOAD_MAX;
+         Index < NumberPermissions;
+         Index++) {
+        status = StorePermissionToString(&Permissions[Index],
+                                         Segment,
+                                         Length,
+                                         &Used);
+        if (!NT_SUCCESS(status))
+            goto fail3;
+
+        Segment += Used;
+        Length -= Used;
+    }
+
+    status = StorePrepareRequest(Context,
+                                 &Request,
+                                 Transaction,
+                                 XS_SET_PERMS,
+                                 Path, strlen(Path),
+                                 "", 1,
+                                 PermissionString, XENSTORE_PAYLOAD_MAX - Length,
+                                 NULL, 0);
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
+    Response = StoreSubmitRequest(Context, &Request);
+
+    status = STATUS_NO_MEMORY;
+    if (Response == NULL)
+        goto fail5;
+
+    status = StoreCheckResponse(Response);
+    if (!NT_SUCCESS(status))
+        goto fail6;
+
+    StoreFreeResponse(Response);
+    ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
+
+    __StoreFree(Path);
+    __StoreFree(PermissionString);
+
+    return STATUS_SUCCESS;
+
+fail6:
+    Error("fail6\n");
+    StoreFreeResponse(Response);
+
+fail5:
+    Error("fail5\n");
+
+fail4:
+    Error("fail4\n");
+
+fail3:
+    Error("fail3\n");
+
+    __StoreFree(Path);
+    ASSERT(IsZeroMemory(&Request, sizeof (XENBUS_STORE_REQUEST)));
+
+fail2:
+    Error("fail2\n");
+
+    __StoreFree(PermissionString);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
 static
 _Function_class_(KSERVICE_ROUTINE)
 _IRQL_requires_(HIGH_LEVEL)
@@ -2327,6 +2499,23 @@ static struct _XENBUS_STORE_INTERFACE_V1 StoreInterfaceVersion1 = {
     StorePoll
 };
                      
+static struct _XENBUS_STORE_INTERFACE_V2 StoreInterfaceVersion2 = {
+    { sizeof (struct _XENBUS_STORE_INTERFACE_V2), 2, NULL, NULL, NULL },
+    StoreAcquire,
+    StoreRelease,
+    StoreFree,
+    StoreRead,
+    StorePrintf,
+    StorePermissionsSet,
+    StoreRemove,
+    StoreDirectory,
+    StoreTransactionStart,
+    StoreTransactionEnd,
+    StoreWatchAdd,
+    StoreWatchRemove,
+    StorePoll
+};
+
 NTSTATUS
 StoreInitialize(
     IN  PXENBUS_FDO             Fdo,
@@ -2426,6 +2615,23 @@ StoreGetInterface(
         status = STATUS_SUCCESS;
         break;
     }
+    case 2: {
+        struct _XENBUS_STORE_INTERFACE_V2  *StoreInterface;
+
+        StoreInterface = (struct _XENBUS_STORE_INTERFACE_V2 *)Interface;
+
+        status = STATUS_BUFFER_OVERFLOW;
+        if (Size < sizeof (struct _XENBUS_STORE_INTERFACE_V2))
+            break;
+
+        *StoreInterface = StoreInterfaceVersion2;
+
+        ASSERT3U(Interface->Version, == , Version);
+        Interface->Context = Context;
+
+        status = STATUS_SUCCESS;
+        break;
+    }
     default:
         status = STATUS_NOT_SUPPORTED;
         break;