Commit 18a245be authored by Demi Marie Obenour's avatar Demi Marie Obenour
Browse files

Add extended shared memory attach structure

This provides an extended version of `X_ShmAttachFd`, called
`X_ShmAttachFdExt`, which allows the client to specify two additional
parameters:

1. The size of the mapping, in bytes.
2. The offset that should be passed to `mmap`, in bytes.

The intended use-case for this extension is when one needs to map
a drawable from a character special device, but it can also be
used with regular files if one needs to map with a nonzero offset.
Qubes OS needs the X server to map the `/dev/xen/gntdev` character
device, which represents memory shared from a different virtual
machine.  This is currently accomplished with an `LD_PRELOAD`’d
shared library that overrides `shmat`, `shmctl`, and `shmdt`, and
I have written a version that instead overrides `fstat` and `mmap`.
With this extension, the preloaded shared library will not be required.
parent d83c84bd
Pipeline #371917 failed with stages
in 1 minute and 47 seconds
......@@ -1143,39 +1143,21 @@ ShmBusfaultNotify(void *context)
}
static int
ProcShmAttachFd(ClientPtr client)
ProcShmAttachFdCommon(ClientPtr client, off_t offset, size_t size, int fd)
{
int fd;
ShmDescPtr shmdesc;
REQUEST(xShmAttachFdReq);
struct stat statb;
SetReqFds(client, 1);
REQUEST_SIZE_MATCH(xShmAttachFdReq);
LEGAL_NEW_RESOURCE(stuff->shmseg, client);
if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
client->errorValue = stuff->readOnly;
return BadValue;
}
fd = ReadFdFromClient(client);
if (fd < 0)
return BadMatch;
if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
close(fd);
return BadMatch;
}
shmdesc = malloc(sizeof(ShmDescRec));
/* Parameters are validated already, so no need to check them */
ShmDescPtr shmdesc = malloc(sizeof(ShmDescRec));
if (!shmdesc) {
close(fd);
return BadAlloc;
}
shmdesc->is_fd = TRUE;
shmdesc->addr = mmap(NULL, statb.st_size,
shmdesc->addr = mmap(NULL, size,
stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
MAP_SHARED,
fd, 0);
fd, offset);
close(fd);
if (shmdesc->addr == ((char *) -1)) {
......@@ -1185,7 +1167,7 @@ ProcShmAttachFd(ClientPtr client)
shmdesc->refcnt = 1;
shmdesc->writable = !stuff->readOnly;
shmdesc->size = statb.st_size;
shmdesc->size = size;
shmdesc->resource = stuff->shmseg;
shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
......@@ -1203,6 +1185,84 @@ ProcShmAttachFd(ClientPtr client)
return Success;
}
static int
ProcShmAttachFd(ClientPtr client)
{
int fd;
struct stat statb;
size_t size;
REQUEST(xShmAttachFdReq);
SetReqFds(client, 1);
REQUEST_SIZE_MATCH(xShmAttachFdReq);
LEGAL_NEW_RESOURCE(stuff->shmseg, client);
if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
client->errorValue = stuff->readOnly;
return BadValue;
}
fd = ReadFdFromClient(client);
if (fd < 0)
return BadMatch;
if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
close(fd);
return BadMatch;
}
size = (size_t)statb.st_size;
if ((off_t)size != statb.st_size) {
close(fd);
return BadMatch;
}
return ProcShmAttachFdCommon(client, 0, size, fd);
}
static int
ProcShmAttachFdExt(ClientPtr client)
{
int fd;
size_t size;
off_t offset;
REQUEST(xShmAttachFdExtReq);
SetReqFds(client, 1);
REQUEST_SIZE_MATCH(xShmAttachFdExtReq);
LEGAL_NEW_RESOURCE(stuff->shmseg, client);
if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
client->errorValue = stuff->readOnly;
return BadValue;
}
fd = ReadFdFromClient(client);
if (fd < 0)
return BadMatch;
if (stuff->pad0) {
client->errorValue = stuff->pad0;
return BadValue;
}
if (stuff->pad1) {
client->errorValue = stuff->pad1;
return BadValue;
}
size = (size_t)stuff->size;
offset = (off_t)stuff->offset;
if (size == 0 || (uint32_t)size != stuff->size) {
client->errorValue = stuff->size;
return BadValue;
}
if ((uint64_t)offset != stuff->offset) {
client->errorValue = stuff->offset;
return BadValue;
}
return ProcShmAttachFdCommon(client, offset, size, fd);
}
static int
shm_tmpfile(void)
{
......@@ -1369,6 +1429,8 @@ ProcShmDispatch(ClientPtr client)
return ProcShmAttachFd(client);
case X_ShmCreateSegment:
return ProcShmCreateSegment(client);
case X_ShmAttachFdExt:
return ProcShmAttachFdExt(client);
#endif
default:
return BadRequest;
......@@ -1492,6 +1554,19 @@ SProcShmCreateSegment(ClientPtr client)
swapl(&stuff->size);
return ProcShmCreateSegment(client);
}
static int _X_COLD
SProcShmAttachFdExt(ClientPtr client)
{
REQUEST(xShmAttachFdExtReq);
SetReqFds(client, 1);
swaps(&stuff->length);
REQUEST_SIZE_MATCH(xShmAttachFdExtReq);
swapl(&stuff->shmseg);
swapl(&stuff->size);
swapll(&stuff->offset);
return ProcShmAttachFd(client);
}
#endif /* SHM_FD_PASSING */
static int _X_COLD
......@@ -1521,6 +1596,8 @@ SProcShmDispatch(ClientPtr client)
return SProcShmAttachFd(client);
case X_ShmCreateSegment:
return SProcShmCreateSegment(client);
case X_ShmAttachFdExt:
return SProcShmAttachFdExt(client);
#endif
default:
return BadRequest;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment