2002-03-04 Robert Collins <rbtcollins@hotmail.com>

* cygserver_shm.cc: Run indent.
        (deleted_head): New global for storing shm id's pending deletion.
        (client_request_shm::serve): Return ENOSYS for invalid request types.
        Implement SHM_DEL - delete a shm id.
        * cygserver_shm.h (SHM_DEL): New type value.
        * shm.cc (delete_inprocess_shmds): New function, does what it's name implies.
        (shmctl): Implement shm_rmid control type.
This commit is contained in:
Robert Collins 2002-03-04 07:22:08 +00:00
parent 74c3173ade
commit 67be0adb71
6 changed files with 686 additions and 532 deletions

View File

@ -70,7 +70,8 @@ getsystemallocgranularity ()
} }
client_request_shm::client_request_shm ():client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters)) client_request_shm::client_request_shm ():client_request (CYGSERVER_REQUEST_SHM_GET,
sizeof (parameters))
{ {
buffer = (char *) &parameters; buffer = (char *) &parameters;
} }
@ -80,10 +81,13 @@ client_request_shm::client_request_shm ():client_request (CYGSERVER_REQUEST_SHM_
*/ */
#if 0 #if 0
extern "C" void * extern
"C" void *
shmat (int shmid, const void *shmaddr, int parameters.in.shmflg) shmat (int shmid, const void *shmaddr, int parameters.in.shmflg)
{ {
class shmid_ds *shm = (class shmid_ds *) shmid; //FIXME: verifyable object test class shmid_ds *
shm = (class shmid_ds *)
shmid; //FIXME: verifyable object test
if (shmaddr) if (shmaddr)
{ {
@ -92,12 +96,14 @@ shmat (int shmid, const void *shmaddr, int parameters.in.shmflg)
return (void *) -1; return (void *) -1;
} }
void *rv = MapViewOfFile (shm->attachmap, void *
rv =
MapViewOfFile (shm->attachmap,
(parameters.in.shmflg & SHM_RDONLY) ? (parameters.in.shmflg & SHM_RDONLY) ?
FILE_MAP_READ : FILE_MAP_WRITE, 0, FILE_MAP_READ : FILE_MAP_WRITE, 0,
0, 0); 0, 0);
if (!rv) if (!rv)
{ {
@ -111,7 +117,10 @@ shmat (int shmid, const void *shmaddr, int parameters.in.shmflg)
*/ */
InterlockedIncrement (&shm->shm_nattch); InterlockedIncrement (&shm->shm_nattch);
_shmattach *attachnode = new _shmattach; _shmattach *
attachnode =
new
_shmattach;
attachnode->data = rv; attachnode->data = rv;
attachnode->next = attachnode->next =
@ -136,7 +145,8 @@ shmat (int shmid, const void *shmaddr, int parameters.in.shmflg)
/* FIXME: on NT we should check everything against the SD. On 95 we just emulate. /* FIXME: on NT we should check everything against the SD. On 95 we just emulate.
*/ */
extern GENERIC_MAPPING access_mapping; extern GENERIC_MAPPING
access_mapping;
extern int extern int
check_and_dup_handle (HANDLE from_process, HANDLE to_process, check_and_dup_handle (HANDLE from_process, HANDLE to_process,
@ -146,14 +156,22 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
HANDLE * to_handle_ptr, BOOL bInheritHandle); HANDLE * to_handle_ptr, BOOL bInheritHandle);
//FIXME: where should this live //FIXME: where should this live
static shmnode *shm_head = NULL; static shmnode *
shm_head =
NULL;
//FIXME: ditto.
static shmnode *
deleted_head = NULL;
/* must be long for InterlockedIncrement */ /* must be long for InterlockedIncrement */
static long new_id = 0; static long
static long new_private_key = 0; new_id =
0;
static long
new_private_key =
0;
void void
client_request_shm::serve (transport_layer_base * conn, client_request_shm::serve (transport_layer_base * conn, process_cache * cache)
process_cache * cache)
{ {
// DWORD sd_size = 4096; // DWORD sd_size = 4096;
// char sd_buf[4096]; // char sd_buf[4096];
@ -257,296 +275,335 @@ client_request_shm::serve (transport_layer_base * conn,
{ {
shmnode *tempnode = shm_head; shmnode *tempnode = shm_head;
while (tempnode) while (tempnode)
{ {
if (tempnode->shm_id == parameters.in.shm_id) if (tempnode->shm_id == parameters.in.shm_id)
{ {
InterlockedIncrement (&tempnode->shmds->shm_nattch); InterlockedIncrement (&tempnode->shmds->shm_nattch);
header.error_code = 0; header.error_code = 0;
CloseHandle (token_handle); CloseHandle (token_handle);
return; return;
} }
tempnode = tempnode->next; tempnode = tempnode->next;
} }
header.error_code = EINVAL; header.error_code = EINVAL;
CloseHandle (token_handle); CloseHandle (token_handle);
return; return;
} }
/* it's a original request from the users */ /* Someone wants the ID removed. */
if (parameters.in.type == SHM_DEL)
/* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide
* to prevent races on shmget.
*/
if (parameters.in.key == IPC_PRIVATE)
{ {
/* create the mapping name (CYGWINSHMKPRIVATE_0x01234567 */ shmnode **tempnode = &shm_head;
/* The K refers to Key, the actual mapped area has D */ while (*tempnode)
long private_key = (int) InterlockedIncrement (&new_private_key); {
snprintf (stringbuf, 29, "CYGWINSHMKPRIVATE_0x%0x", private_key); if ((*tempnode)->shm_id == parameters.in.shm_id)
shmname = stringbuf; {
snprintf (stringbuf1, 29, "CYGWINSHMDPRIVATE_0x%0x", private_key); // unlink from the accessible node list
shmaname = stringbuf1; shmnode *temp2 = *tempnode;
} *tempnode = temp2->next;
else // link into the deleted list
{ temp2->next = deleted_head;
/* create the mapping name (CYGWINSHMK0x0123456789abcdef */ deleted_head = temp2;
/* The K refers to Key, the actual mapped area has D */
snprintf (stringbuf, 29, "CYGWINSHMK0x%0qx", parameters.in.key); // FIXME: when/where do we delete the handles?
shmname = stringbuf;
snprintf (stringbuf1, 29, "CYGWINSHMD0x%0qx", parameters.in.key); header.error_code = 0;
shmaname = stringbuf1; CloseHandle (token_handle);
debug_printf ("system id strings are \n%s\n%s\n", shmname, shmaname); return;
debug_printf ("key input value is 0x%0qx\n", parameters.in.key); }
tempnode = &(*tempnode)->next;
}
header.error_code = EINVAL;
CloseHandle (token_handle);
return;
} }
/* attempt to open the key */
/* get an existing key */ if (parameters.in.type == SHM_CREATE)
/* On unix the same shmid identifier is returned on multiple calls to shm_get
* with the same key and size. Different modes is a ?.
*/
/* walk the list of known keys and return the id if found. remember, we are
* authoritative...
*/
shmnode *tempnode = shm_head;
while (tempnode)
{ {
if (tempnode->key == parameters.in.key /* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide
&& parameters.in.key != IPC_PRIVATE) * to prevent races on shmget.
*/
if (parameters.in.key == IPC_PRIVATE)
{ {
// FIXME: free the mutex /* create the mapping name (CYGWINSHMKPRIVATE_0x01234567 */
if (parameters.in.size /* The K refers to Key, the actual mapped area has D */
&& tempnode->shmds->shm_segsz < parameters.in.size) long private_key = (int) InterlockedIncrement (&new_private_key);
snprintf (stringbuf, 29, "CYGWINSHMKPRIVATE_0x%0x", private_key);
shmname = stringbuf;
snprintf (stringbuf1, 29, "CYGWINSHMDPRIVATE_0x%0x", private_key);
shmaname = stringbuf1;
}
else
{
/* create the mapping name (CYGWINSHMK0x0123456789abcdef */
/* The K refers to Key, the actual mapped area has D */
snprintf (stringbuf, 29, "CYGWINSHMK0x%0qx", parameters.in.key);
shmname = stringbuf;
snprintf (stringbuf1, 29, "CYGWINSHMD0x%0qx", parameters.in.key);
shmaname = stringbuf1;
debug_printf ("system id strings are \n%s\n%s\n", shmname,
shmaname);
debug_printf ("key input value is 0x%0qx\n", parameters.in.key);
}
/* attempt to open the key */
/* get an existing key */
/* On unix the same shmid identifier is returned on multiple calls to shm_get
* with the same key and size. Different modes is a ?.
*/
/* walk the list of known keys and return the id if found. remember, we are
* authoritative...
*/
shmnode *tempnode = shm_head;
while (tempnode)
{
if (tempnode->key == parameters.in.key
&& parameters.in.key != IPC_PRIVATE)
{ {
header.error_code = EINVAL; // FIXME: free the mutex
if (parameters.in.size
&& tempnode->shmds->shm_segsz < parameters.in.size)
{
header.error_code = EINVAL;
CloseHandle (token_handle);
return;
}
/* FIXME: can the same process call this twice without error ? test
* on unix
*/
if ((parameters.in.shmflg & IPC_CREAT)
&& (parameters.in.shmflg & IPC_EXCL))
{
header.error_code = EEXIST;
debug_printf
("attempt to exclusively create already created shm_area with key 0x%0qx\n",
parameters.in.key);
// FIXME: free the mutex
CloseHandle (token_handle);
return;
}
// FIXME: do we need to other tests of the requested mode with the
// tempnode->shm_id mode ? testcase on unix needed.
// FIXME how do we do the security test? or
// do we wait for shmat to bother with that?
/* One possibly solution: impersonate the client, and then test we can
* reopen the area. In fact we'll probably have to do that to get
* handles back to them, alternatively just tell them the id, and then
* let them attempt the open.
*/
parameters.out.shm_id = tempnode->shm_id;
if (check_and_dup_handle
(GetCurrentProcess (), from_process_handle, token_handle,
DUPLICATE_SAME_ACCESS, tempnode->filemap,
&parameters.out.filemap, TRUE) != 0)
{
printf ("error duplicating filemap handle (%lu)\n",
GetLastError ());
header.error_code = EACCES;
/*mutex*/
CloseHandle (token_handle);
return;
}
if (check_and_dup_handle
(GetCurrentProcess (), from_process_handle, token_handle,
DUPLICATE_SAME_ACCESS, tempnode->attachmap,
&parameters.out.attachmap, TRUE) != 0)
{
printf ("error duplicating attachmap handle (%lu)\n",
GetLastError ());
header.error_code = EACCES;
/*mutex*/
CloseHandle (token_handle);
return;
}
CloseHandle (token_handle); CloseHandle (token_handle);
return; return;
} }
/* FIXME: can the same process call this twice without error ? test tempnode = tempnode->next;
* on unix }
*/ /* couldn't find a currently open shm area. */
/* create one */
/* do this as the client */
conn->impersonate_client ();
/* This may need sh_none... it's only a control structure */
HANDLE filemap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile.
&sa,
PAGE_READWRITE, // protection
0x00000000,
getsystemallocgranularity (),
shmname // object name
);
int lasterr = GetLastError ();
conn->revert_to_self ();
if (filemap == NULL)
{
/* We failed to open the filemapping ? */
system_printf ("failed to open file mapping: %lu\n",
GetLastError ());
// free the mutex
// we can assume that it exists, and that it was an access problem.
header.error_code = EACCES;
CloseHandle (token_handle);
return;
}
/* successfully opened the control region mapping */
/* did we create it ? */
int oldmapping = lasterr == ERROR_ALREADY_EXISTS;
if (oldmapping)
{
/* should never happen - we are the global daemon! */
#if 0
if ((parameters.in.shmflg & IPC_CREAT) if ((parameters.in.shmflg & IPC_CREAT)
&& (parameters.in.shmflg & IPC_EXCL)) && (parameters.in.shmflg & IPC_EXCL))
{
header.error_code = EEXIST;
debug_printf
("attempt to exclusively create already created shm_area with key 0x%0qx\n",
parameters.in.key);
// FIXME: free the mutex
CloseHandle (token_handle);
return;
}
// FIXME: do we need to other tests of the requested mode with the
// tempnode->shm_id mode ? testcase on unix needed.
// FIXME how do we do the security test? or
// do we wait for shmat to bother with that?
/* One possibly solution: impersonate the client, and then test we can
* reopen the area. In fact we'll probably have to do that to get
* handles back to them, alternatively just tell them the id, and then
* let them attempt the open.
*/
parameters.out.shm_id = tempnode->shm_id;
if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
token_handle,
DUPLICATE_SAME_ACCESS,
tempnode->filemap,
&parameters.out.filemap, TRUE) != 0)
{
printf ("error duplicating filemap handle (%lu)\n",
GetLastError ());
header.error_code = EACCES;
/*mutex*/
CloseHandle (token_handle);
return;
}
if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
token_handle,
DUPLICATE_SAME_ACCESS,
tempnode->attachmap,
&parameters.out.attachmap, TRUE) != 0)
{
printf ("error duplicating attachmap handle (%lu)\n",
GetLastError ());
header.error_code = EACCES;
/*mutex*/
CloseHandle (token_handle);
return;
}
CloseHandle (token_handle);
return;
}
tempnode = tempnode->next;
}
/* couldn't find a currently open shm area. */
/* create one */
/* do this as the client */
conn->impersonate_client ();
/* This may need sh_none... it's only a control structure */
HANDLE filemap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile.
&sa,
PAGE_READWRITE, // protection
0x00000000,
getsystemallocgranularity (),
shmname // object name
);
int lasterr = GetLastError ();
conn->revert_to_self ();
if (filemap == NULL)
{
/* We failed to open the filemapping ? */
system_printf ("failed to open file mapping: %lu\n", GetLastError ());
// free the mutex
// we can assume that it exists, and that it was an access problem.
header.error_code = EACCES;
CloseHandle (token_handle);
return;
}
/* successfully opened the control region mapping */
/* did we create it ? */
int oldmapping = lasterr == ERROR_ALREADY_EXISTS;
if (oldmapping)
{
/* should never happen - we are the global daemon! */
#if 0
if ((parameters.in.shmflg & IPC_CREAT)
&& (parameters.in.shmflg & IPC_EXCL))
#endif #endif
{
/* FIXME free mutex */
CloseHandle (filemap);
header.error_code = EEXIST;
CloseHandle (token_handle);
return;
}
}
/* we created a new mapping */
if (parameters.in.key != IPC_PRIVATE &&
(parameters.in.shmflg & IPC_CREAT) == 0)
{ {
/* FIXME free mutex */
CloseHandle (filemap); CloseHandle (filemap);
header.error_code = EEXIST; /* FIXME free mutex */
header.error_code = ENOENT;
CloseHandle (token_handle); CloseHandle (token_handle);
return; return;
} }
}
/* we created a new mapping */ conn->impersonate_client ();
if (parameters.in.key != IPC_PRIVATE && void *mapptr = MapViewOfFile (filemap, FILE_MAP_WRITE, 0, 0, 0);
(parameters.in.shmflg & IPC_CREAT) == 0) conn->revert_to_self ();
{
CloseHandle (filemap);
/* FIXME free mutex */
header.error_code = ENOENT;
CloseHandle (token_handle);
return;
}
conn->impersonate_client (); if (!mapptr)
void *mapptr = MapViewOfFile (filemap, FILE_MAP_WRITE, 0, 0, 0); {
conn->revert_to_self (); CloseHandle (filemap);
//FIXME: close filemap and free the mutex
/* we couldn't access the mapped area with the requested permissions */
header.error_code = EACCES;
CloseHandle (token_handle);
return;
}
if (!mapptr) conn->impersonate_client ();
{ /* Now get the user data */
CloseHandle (filemap); HANDLE attachmap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile
//FIXME: close filemap and free the mutex &sa,
/* we couldn't access the mapped area with the requested permissions */ PAGE_READWRITE, // protection (FIXME)
header.error_code = EACCES; 0x00000000,
CloseHandle (token_handle); parameters.in.size +
return; parameters.in.size %
} getsystemallocgranularity (),
shmaname // object name
);
conn->revert_to_self ();
conn->impersonate_client (); if (attachmap == NULL)
/* Now get the user data */ {
HANDLE attachmap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile system_printf ("failed to get shm attachmap\n");
&sa, header.error_code = ENOMEM;
PAGE_READWRITE, // protection (FIXME) UnmapViewOfFile (mapptr);
0x00000000, CloseHandle (filemap);
parameters.in.size + /* FIXME exit the mutex */
parameters.in.size % CloseHandle (token_handle);
getsystemallocgranularity (), return;
shmaname // object name }
);
conn->revert_to_self ();
if (attachmap == NULL) shmid_ds *shmtemp = new shmid_ds;
{ if (!shmtemp)
system_printf ("failed to get shm attachmap\n"); {
header.error_code = ENOMEM; system_printf ("failed to malloc shm node\n");
UnmapViewOfFile (mapptr); header.error_code = ENOMEM;
CloseHandle (filemap); UnmapViewOfFile (mapptr);
/* FIXME exit the mutex */ CloseHandle (filemap);
CloseHandle (token_handle); CloseHandle (attachmap);
return; /* FIXME exit mutex */
} CloseHandle (token_handle);
return;
}
shmid_ds *shmtemp = new shmid_ds; /* fill out the node data */
if (!shmtemp) shmtemp->shm_perm.cuid = getuid ();
{ shmtemp->shm_perm.uid = shmtemp->shm_perm.cuid;
system_printf ("failed to malloc shm node\n"); shmtemp->shm_perm.cgid = getgid ();
header.error_code = ENOMEM; shmtemp->shm_perm.gid = shmtemp->shm_perm.cgid;
UnmapViewOfFile (mapptr); shmtemp->shm_perm.mode = parameters.in.shmflg & 0x01ff;
CloseHandle (filemap); shmtemp->shm_lpid = 0;
CloseHandle (attachmap); shmtemp->shm_nattch = 0;
/* FIXME exit mutex */ shmtemp->shm_atime = 0;
CloseHandle (token_handle); shmtemp->shm_dtime = 0;
return; shmtemp->shm_ctime = time (NULL);
} shmtemp->shm_segsz = parameters.in.size;
*(shmid_ds *) mapptr = *shmtemp;
shmtemp->mapptr = mapptr;
/* fill out the node data */ /* no need for InterlockedExchange here, we're serialised by the global mutex */
shmtemp->shm_perm.cuid = getuid (); tempnode = new shmnode;
shmtemp->shm_perm.uid = shmtemp->shm_perm.cuid; tempnode->shmds = shmtemp;
shmtemp->shm_perm.cgid = getgid (); tempnode->shm_id = (int) InterlockedIncrement (&new_id);
shmtemp->shm_perm.gid = shmtemp->shm_perm.cgid; tempnode->key = parameters.in.key;
shmtemp->shm_perm.mode = parameters.in.shmflg & 0x01ff; tempnode->filemap = filemap;
shmtemp->shm_lpid = 0; tempnode->attachmap = attachmap;
shmtemp->shm_nattch = 0; tempnode->next = shm_head;
shmtemp->shm_atime = 0; shm_head = tempnode;
shmtemp->shm_dtime = 0;
shmtemp->shm_ctime = time (NULL);
shmtemp->shm_segsz = parameters.in.size;
*(shmid_ds *) mapptr = *shmtemp;
shmtemp->mapptr = mapptr;
/* no need for InterlockedExchange here, we're serialised by the global mutex */ /* we now have the area in the daemon list, opened.
tempnode = new shmnode;
tempnode->shmds = shmtemp;
tempnode->shm_id = (int) InterlockedIncrement (&new_id);
tempnode->key = parameters.in.key;
tempnode->filemap = filemap;
tempnode->attachmap = attachmap;
tempnode->next = shm_head;
shm_head = tempnode;
/* we now have the area in the daemon list, opened. FIXME: leave the system wide shm mutex */
FIXME: leave the system wide shm mutex */ parameters.out.shm_id = tempnode->shm_id;
if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
parameters.out.shm_id = tempnode->shm_id; token_handle,
if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, DUPLICATE_SAME_ACCESS,
token_handle, tempnode->filemap, &parameters.out.filemap,
DUPLICATE_SAME_ACCESS, TRUE) != 0)
tempnode->filemap, &parameters.out.filemap, {
TRUE) != 0) printf ("error duplicating filemap handle (%lu)\n",
{ GetLastError ());
printf ("error duplicating filemap handle (%lu)\n", GetLastError ()); header.error_code = EACCES;
header.error_code = EACCES; CloseHandle (token_handle);
CloseHandle (token_handle);
/* mutex et al */ /* mutex et al */
return; return;
} }
if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
token_handle, token_handle,
DUPLICATE_SAME_ACCESS, DUPLICATE_SAME_ACCESS,
tempnode->attachmap, &parameters.out.attachmap, tempnode->attachmap,
TRUE) != 0) &parameters.out.attachmap, TRUE) != 0)
{ {
printf ("error duplicating attachmap handle (%lu)\n", GetLastError ()); printf ("error duplicating attachmap handle (%lu)\n",
header.error_code = EACCES; GetLastError ());
CloseHandle (from_process_handle); header.error_code = EACCES;
CloseHandle (token_handle); CloseHandle (from_process_handle);
CloseHandle (token_handle);
/* more cleanup... yay! */ /* more cleanup... yay! */
return;
}
CloseHandle (token_handle);
return; return;
} }
header.error_code = ENOSYS;
CloseHandle (token_handle); CloseHandle (token_handle);
return; return;
} }

View File

@ -17,6 +17,7 @@ details. */
#define SHM_REATTACH 1 #define SHM_REATTACH 1
#define SHM_ATTACH 2 #define SHM_ATTACH 2
#define SHM_DETACH 3 #define SHM_DETACH 3
#define SHM_DEL 4
class client_request_shm : public client_request class client_request_shm : public client_request

View File

@ -1,3 +1,13 @@
2002-03-04 Robert Collins <rbtcollins@hotmail.com>
* cygserver_shm.cc: Run indent.
(deleted_head): New global for storing shm id's pending deletion.
(client_request_shm::serve): Return ENOSYS for invalid request types.
Implement SHM_DEL - delete a shm id.
* cygserver_shm.h (SHM_DEL): New type value.
* shm.cc (delete_inprocess_shmds): New function, does what it's name implies.
(shmctl): Implement shm_rmid control type.
2002-03-04 Robert Collins <rbtcollins@hotmail.com> 2002-03-04 Robert Collins <rbtcollins@hotmail.com>
* Makefile.in (install): Remove install-bin to allow make install to work. * Makefile.in (install): Remove install-bin to allow make install to work.

View File

@ -70,7 +70,8 @@ getsystemallocgranularity ()
} }
client_request_shm::client_request_shm ():client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters)) client_request_shm::client_request_shm ():client_request (CYGSERVER_REQUEST_SHM_GET,
sizeof (parameters))
{ {
buffer = (char *) &parameters; buffer = (char *) &parameters;
} }
@ -80,10 +81,13 @@ client_request_shm::client_request_shm ():client_request (CYGSERVER_REQUEST_SHM_
*/ */
#if 0 #if 0
extern "C" void * extern
"C" void *
shmat (int shmid, const void *shmaddr, int parameters.in.shmflg) shmat (int shmid, const void *shmaddr, int parameters.in.shmflg)
{ {
class shmid_ds *shm = (class shmid_ds *) shmid; //FIXME: verifyable object test class shmid_ds *
shm = (class shmid_ds *)
shmid; //FIXME: verifyable object test
if (shmaddr) if (shmaddr)
{ {
@ -92,12 +96,14 @@ shmat (int shmid, const void *shmaddr, int parameters.in.shmflg)
return (void *) -1; return (void *) -1;
} }
void *rv = MapViewOfFile (shm->attachmap, void *
rv =
MapViewOfFile (shm->attachmap,
(parameters.in.shmflg & SHM_RDONLY) ? (parameters.in.shmflg & SHM_RDONLY) ?
FILE_MAP_READ : FILE_MAP_WRITE, 0, FILE_MAP_READ : FILE_MAP_WRITE, 0,
0, 0); 0, 0);
if (!rv) if (!rv)
{ {
@ -111,7 +117,10 @@ shmat (int shmid, const void *shmaddr, int parameters.in.shmflg)
*/ */
InterlockedIncrement (&shm->shm_nattch); InterlockedIncrement (&shm->shm_nattch);
_shmattach *attachnode = new _shmattach; _shmattach *
attachnode =
new
_shmattach;
attachnode->data = rv; attachnode->data = rv;
attachnode->next = attachnode->next =
@ -136,7 +145,8 @@ shmat (int shmid, const void *shmaddr, int parameters.in.shmflg)
/* FIXME: on NT we should check everything against the SD. On 95 we just emulate. /* FIXME: on NT we should check everything against the SD. On 95 we just emulate.
*/ */
extern GENERIC_MAPPING access_mapping; extern GENERIC_MAPPING
access_mapping;
extern int extern int
check_and_dup_handle (HANDLE from_process, HANDLE to_process, check_and_dup_handle (HANDLE from_process, HANDLE to_process,
@ -146,14 +156,22 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
HANDLE * to_handle_ptr, BOOL bInheritHandle); HANDLE * to_handle_ptr, BOOL bInheritHandle);
//FIXME: where should this live //FIXME: where should this live
static shmnode *shm_head = NULL; static shmnode *
shm_head =
NULL;
//FIXME: ditto.
static shmnode *
deleted_head = NULL;
/* must be long for InterlockedIncrement */ /* must be long for InterlockedIncrement */
static long new_id = 0; static long
static long new_private_key = 0; new_id =
0;
static long
new_private_key =
0;
void void
client_request_shm::serve (transport_layer_base * conn, client_request_shm::serve (transport_layer_base * conn, process_cache * cache)
process_cache * cache)
{ {
// DWORD sd_size = 4096; // DWORD sd_size = 4096;
// char sd_buf[4096]; // char sd_buf[4096];
@ -257,296 +275,335 @@ client_request_shm::serve (transport_layer_base * conn,
{ {
shmnode *tempnode = shm_head; shmnode *tempnode = shm_head;
while (tempnode) while (tempnode)
{ {
if (tempnode->shm_id == parameters.in.shm_id) if (tempnode->shm_id == parameters.in.shm_id)
{ {
InterlockedIncrement (&tempnode->shmds->shm_nattch); InterlockedIncrement (&tempnode->shmds->shm_nattch);
header.error_code = 0; header.error_code = 0;
CloseHandle (token_handle); CloseHandle (token_handle);
return; return;
} }
tempnode = tempnode->next; tempnode = tempnode->next;
} }
header.error_code = EINVAL; header.error_code = EINVAL;
CloseHandle (token_handle); CloseHandle (token_handle);
return; return;
} }
/* it's a original request from the users */ /* Someone wants the ID removed. */
if (parameters.in.type == SHM_DEL)
/* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide
* to prevent races on shmget.
*/
if (parameters.in.key == IPC_PRIVATE)
{ {
/* create the mapping name (CYGWINSHMKPRIVATE_0x01234567 */ shmnode **tempnode = &shm_head;
/* The K refers to Key, the actual mapped area has D */ while (*tempnode)
long private_key = (int) InterlockedIncrement (&new_private_key); {
snprintf (stringbuf, 29, "CYGWINSHMKPRIVATE_0x%0x", private_key); if ((*tempnode)->shm_id == parameters.in.shm_id)
shmname = stringbuf; {
snprintf (stringbuf1, 29, "CYGWINSHMDPRIVATE_0x%0x", private_key); // unlink from the accessible node list
shmaname = stringbuf1; shmnode *temp2 = *tempnode;
} *tempnode = temp2->next;
else // link into the deleted list
{ temp2->next = deleted_head;
/* create the mapping name (CYGWINSHMK0x0123456789abcdef */ deleted_head = temp2;
/* The K refers to Key, the actual mapped area has D */
snprintf (stringbuf, 29, "CYGWINSHMK0x%0qx", parameters.in.key); // FIXME: when/where do we delete the handles?
shmname = stringbuf;
snprintf (stringbuf1, 29, "CYGWINSHMD0x%0qx", parameters.in.key); header.error_code = 0;
shmaname = stringbuf1; CloseHandle (token_handle);
debug_printf ("system id strings are \n%s\n%s\n", shmname, shmaname); return;
debug_printf ("key input value is 0x%0qx\n", parameters.in.key); }
tempnode = &(*tempnode)->next;
}
header.error_code = EINVAL;
CloseHandle (token_handle);
return;
} }
/* attempt to open the key */
/* get an existing key */ if (parameters.in.type == SHM_CREATE)
/* On unix the same shmid identifier is returned on multiple calls to shm_get
* with the same key and size. Different modes is a ?.
*/
/* walk the list of known keys and return the id if found. remember, we are
* authoritative...
*/
shmnode *tempnode = shm_head;
while (tempnode)
{ {
if (tempnode->key == parameters.in.key /* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide
&& parameters.in.key != IPC_PRIVATE) * to prevent races on shmget.
*/
if (parameters.in.key == IPC_PRIVATE)
{ {
// FIXME: free the mutex /* create the mapping name (CYGWINSHMKPRIVATE_0x01234567 */
if (parameters.in.size /* The K refers to Key, the actual mapped area has D */
&& tempnode->shmds->shm_segsz < parameters.in.size) long private_key = (int) InterlockedIncrement (&new_private_key);
snprintf (stringbuf, 29, "CYGWINSHMKPRIVATE_0x%0x", private_key);
shmname = stringbuf;
snprintf (stringbuf1, 29, "CYGWINSHMDPRIVATE_0x%0x", private_key);
shmaname = stringbuf1;
}
else
{
/* create the mapping name (CYGWINSHMK0x0123456789abcdef */
/* The K refers to Key, the actual mapped area has D */
snprintf (stringbuf, 29, "CYGWINSHMK0x%0qx", parameters.in.key);
shmname = stringbuf;
snprintf (stringbuf1, 29, "CYGWINSHMD0x%0qx", parameters.in.key);
shmaname = stringbuf1;
debug_printf ("system id strings are \n%s\n%s\n", shmname,
shmaname);
debug_printf ("key input value is 0x%0qx\n", parameters.in.key);
}
/* attempt to open the key */
/* get an existing key */
/* On unix the same shmid identifier is returned on multiple calls to shm_get
* with the same key and size. Different modes is a ?.
*/
/* walk the list of known keys and return the id if found. remember, we are
* authoritative...
*/
shmnode *tempnode = shm_head;
while (tempnode)
{
if (tempnode->key == parameters.in.key
&& parameters.in.key != IPC_PRIVATE)
{ {
header.error_code = EINVAL; // FIXME: free the mutex
if (parameters.in.size
&& tempnode->shmds->shm_segsz < parameters.in.size)
{
header.error_code = EINVAL;
CloseHandle (token_handle);
return;
}
/* FIXME: can the same process call this twice without error ? test
* on unix
*/
if ((parameters.in.shmflg & IPC_CREAT)
&& (parameters.in.shmflg & IPC_EXCL))
{
header.error_code = EEXIST;
debug_printf
("attempt to exclusively create already created shm_area with key 0x%0qx\n",
parameters.in.key);
// FIXME: free the mutex
CloseHandle (token_handle);
return;
}
// FIXME: do we need to other tests of the requested mode with the
// tempnode->shm_id mode ? testcase on unix needed.
// FIXME how do we do the security test? or
// do we wait for shmat to bother with that?
/* One possibly solution: impersonate the client, and then test we can
* reopen the area. In fact we'll probably have to do that to get
* handles back to them, alternatively just tell them the id, and then
* let them attempt the open.
*/
parameters.out.shm_id = tempnode->shm_id;
if (check_and_dup_handle
(GetCurrentProcess (), from_process_handle, token_handle,
DUPLICATE_SAME_ACCESS, tempnode->filemap,
&parameters.out.filemap, TRUE) != 0)
{
printf ("error duplicating filemap handle (%lu)\n",
GetLastError ());
header.error_code = EACCES;
/*mutex*/
CloseHandle (token_handle);
return;
}
if (check_and_dup_handle
(GetCurrentProcess (), from_process_handle, token_handle,
DUPLICATE_SAME_ACCESS, tempnode->attachmap,
&parameters.out.attachmap, TRUE) != 0)
{
printf ("error duplicating attachmap handle (%lu)\n",
GetLastError ());
header.error_code = EACCES;
/*mutex*/
CloseHandle (token_handle);
return;
}
CloseHandle (token_handle); CloseHandle (token_handle);
return; return;
} }
/* FIXME: can the same process call this twice without error ? test tempnode = tempnode->next;
* on unix }
*/ /* couldn't find a currently open shm area. */
/* create one */
/* do this as the client */
conn->impersonate_client ();
/* This may need sh_none... it's only a control structure */
HANDLE filemap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile.
&sa,
PAGE_READWRITE, // protection
0x00000000,
getsystemallocgranularity (),
shmname // object name
);
int lasterr = GetLastError ();
conn->revert_to_self ();
if (filemap == NULL)
{
/* We failed to open the filemapping ? */
system_printf ("failed to open file mapping: %lu\n",
GetLastError ());
// free the mutex
// we can assume that it exists, and that it was an access problem.
header.error_code = EACCES;
CloseHandle (token_handle);
return;
}
/* successfully opened the control region mapping */
/* did we create it ? */
int oldmapping = lasterr == ERROR_ALREADY_EXISTS;
if (oldmapping)
{
/* should never happen - we are the global daemon! */
#if 0
if ((parameters.in.shmflg & IPC_CREAT) if ((parameters.in.shmflg & IPC_CREAT)
&& (parameters.in.shmflg & IPC_EXCL)) && (parameters.in.shmflg & IPC_EXCL))
{
header.error_code = EEXIST;
debug_printf
("attempt to exclusively create already created shm_area with key 0x%0qx\n",
parameters.in.key);
// FIXME: free the mutex
CloseHandle (token_handle);
return;
}
// FIXME: do we need to other tests of the requested mode with the
// tempnode->shm_id mode ? testcase on unix needed.
// FIXME how do we do the security test? or
// do we wait for shmat to bother with that?
/* One possibly solution: impersonate the client, and then test we can
* reopen the area. In fact we'll probably have to do that to get
* handles back to them, alternatively just tell them the id, and then
* let them attempt the open.
*/
parameters.out.shm_id = tempnode->shm_id;
if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
token_handle,
DUPLICATE_SAME_ACCESS,
tempnode->filemap,
&parameters.out.filemap, TRUE) != 0)
{
printf ("error duplicating filemap handle (%lu)\n",
GetLastError ());
header.error_code = EACCES;
/*mutex*/
CloseHandle (token_handle);
return;
}
if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
token_handle,
DUPLICATE_SAME_ACCESS,
tempnode->attachmap,
&parameters.out.attachmap, TRUE) != 0)
{
printf ("error duplicating attachmap handle (%lu)\n",
GetLastError ());
header.error_code = EACCES;
/*mutex*/
CloseHandle (token_handle);
return;
}
CloseHandle (token_handle);
return;
}
tempnode = tempnode->next;
}
/* couldn't find a currently open shm area. */
/* create one */
/* do this as the client */
conn->impersonate_client ();
/* This may need sh_none... it's only a control structure */
HANDLE filemap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile.
&sa,
PAGE_READWRITE, // protection
0x00000000,
getsystemallocgranularity (),
shmname // object name
);
int lasterr = GetLastError ();
conn->revert_to_self ();
if (filemap == NULL)
{
/* We failed to open the filemapping ? */
system_printf ("failed to open file mapping: %lu\n", GetLastError ());
// free the mutex
// we can assume that it exists, and that it was an access problem.
header.error_code = EACCES;
CloseHandle (token_handle);
return;
}
/* successfully opened the control region mapping */
/* did we create it ? */
int oldmapping = lasterr == ERROR_ALREADY_EXISTS;
if (oldmapping)
{
/* should never happen - we are the global daemon! */
#if 0
if ((parameters.in.shmflg & IPC_CREAT)
&& (parameters.in.shmflg & IPC_EXCL))
#endif #endif
{
/* FIXME free mutex */
CloseHandle (filemap);
header.error_code = EEXIST;
CloseHandle (token_handle);
return;
}
}
/* we created a new mapping */
if (parameters.in.key != IPC_PRIVATE &&
(parameters.in.shmflg & IPC_CREAT) == 0)
{ {
/* FIXME free mutex */
CloseHandle (filemap); CloseHandle (filemap);
header.error_code = EEXIST; /* FIXME free mutex */
header.error_code = ENOENT;
CloseHandle (token_handle); CloseHandle (token_handle);
return; return;
} }
}
/* we created a new mapping */ conn->impersonate_client ();
if (parameters.in.key != IPC_PRIVATE && void *mapptr = MapViewOfFile (filemap, FILE_MAP_WRITE, 0, 0, 0);
(parameters.in.shmflg & IPC_CREAT) == 0) conn->revert_to_self ();
{
CloseHandle (filemap);
/* FIXME free mutex */
header.error_code = ENOENT;
CloseHandle (token_handle);
return;
}
conn->impersonate_client (); if (!mapptr)
void *mapptr = MapViewOfFile (filemap, FILE_MAP_WRITE, 0, 0, 0); {
conn->revert_to_self (); CloseHandle (filemap);
//FIXME: close filemap and free the mutex
/* we couldn't access the mapped area with the requested permissions */
header.error_code = EACCES;
CloseHandle (token_handle);
return;
}
if (!mapptr) conn->impersonate_client ();
{ /* Now get the user data */
CloseHandle (filemap); HANDLE attachmap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile
//FIXME: close filemap and free the mutex &sa,
/* we couldn't access the mapped area with the requested permissions */ PAGE_READWRITE, // protection (FIXME)
header.error_code = EACCES; 0x00000000,
CloseHandle (token_handle); parameters.in.size +
return; parameters.in.size %
} getsystemallocgranularity (),
shmaname // object name
);
conn->revert_to_self ();
conn->impersonate_client (); if (attachmap == NULL)
/* Now get the user data */ {
HANDLE attachmap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile system_printf ("failed to get shm attachmap\n");
&sa, header.error_code = ENOMEM;
PAGE_READWRITE, // protection (FIXME) UnmapViewOfFile (mapptr);
0x00000000, CloseHandle (filemap);
parameters.in.size + /* FIXME exit the mutex */
parameters.in.size % CloseHandle (token_handle);
getsystemallocgranularity (), return;
shmaname // object name }
);
conn->revert_to_self ();
if (attachmap == NULL) shmid_ds *shmtemp = new shmid_ds;
{ if (!shmtemp)
system_printf ("failed to get shm attachmap\n"); {
header.error_code = ENOMEM; system_printf ("failed to malloc shm node\n");
UnmapViewOfFile (mapptr); header.error_code = ENOMEM;
CloseHandle (filemap); UnmapViewOfFile (mapptr);
/* FIXME exit the mutex */ CloseHandle (filemap);
CloseHandle (token_handle); CloseHandle (attachmap);
return; /* FIXME exit mutex */
} CloseHandle (token_handle);
return;
}
shmid_ds *shmtemp = new shmid_ds; /* fill out the node data */
if (!shmtemp) shmtemp->shm_perm.cuid = getuid ();
{ shmtemp->shm_perm.uid = shmtemp->shm_perm.cuid;
system_printf ("failed to malloc shm node\n"); shmtemp->shm_perm.cgid = getgid ();
header.error_code = ENOMEM; shmtemp->shm_perm.gid = shmtemp->shm_perm.cgid;
UnmapViewOfFile (mapptr); shmtemp->shm_perm.mode = parameters.in.shmflg & 0x01ff;
CloseHandle (filemap); shmtemp->shm_lpid = 0;
CloseHandle (attachmap); shmtemp->shm_nattch = 0;
/* FIXME exit mutex */ shmtemp->shm_atime = 0;
CloseHandle (token_handle); shmtemp->shm_dtime = 0;
return; shmtemp->shm_ctime = time (NULL);
} shmtemp->shm_segsz = parameters.in.size;
*(shmid_ds *) mapptr = *shmtemp;
shmtemp->mapptr = mapptr;
/* fill out the node data */ /* no need for InterlockedExchange here, we're serialised by the global mutex */
shmtemp->shm_perm.cuid = getuid (); tempnode = new shmnode;
shmtemp->shm_perm.uid = shmtemp->shm_perm.cuid; tempnode->shmds = shmtemp;
shmtemp->shm_perm.cgid = getgid (); tempnode->shm_id = (int) InterlockedIncrement (&new_id);
shmtemp->shm_perm.gid = shmtemp->shm_perm.cgid; tempnode->key = parameters.in.key;
shmtemp->shm_perm.mode = parameters.in.shmflg & 0x01ff; tempnode->filemap = filemap;
shmtemp->shm_lpid = 0; tempnode->attachmap = attachmap;
shmtemp->shm_nattch = 0; tempnode->next = shm_head;
shmtemp->shm_atime = 0; shm_head = tempnode;
shmtemp->shm_dtime = 0;
shmtemp->shm_ctime = time (NULL);
shmtemp->shm_segsz = parameters.in.size;
*(shmid_ds *) mapptr = *shmtemp;
shmtemp->mapptr = mapptr;
/* no need for InterlockedExchange here, we're serialised by the global mutex */ /* we now have the area in the daemon list, opened.
tempnode = new shmnode;
tempnode->shmds = shmtemp;
tempnode->shm_id = (int) InterlockedIncrement (&new_id);
tempnode->key = parameters.in.key;
tempnode->filemap = filemap;
tempnode->attachmap = attachmap;
tempnode->next = shm_head;
shm_head = tempnode;
/* we now have the area in the daemon list, opened. FIXME: leave the system wide shm mutex */
FIXME: leave the system wide shm mutex */ parameters.out.shm_id = tempnode->shm_id;
if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
parameters.out.shm_id = tempnode->shm_id; token_handle,
if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, DUPLICATE_SAME_ACCESS,
token_handle, tempnode->filemap, &parameters.out.filemap,
DUPLICATE_SAME_ACCESS, TRUE) != 0)
tempnode->filemap, &parameters.out.filemap, {
TRUE) != 0) printf ("error duplicating filemap handle (%lu)\n",
{ GetLastError ());
printf ("error duplicating filemap handle (%lu)\n", GetLastError ()); header.error_code = EACCES;
header.error_code = EACCES; CloseHandle (token_handle);
CloseHandle (token_handle);
/* mutex et al */ /* mutex et al */
return; return;
} }
if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
token_handle, token_handle,
DUPLICATE_SAME_ACCESS, DUPLICATE_SAME_ACCESS,
tempnode->attachmap, &parameters.out.attachmap, tempnode->attachmap,
TRUE) != 0) &parameters.out.attachmap, TRUE) != 0)
{ {
printf ("error duplicating attachmap handle (%lu)\n", GetLastError ()); printf ("error duplicating attachmap handle (%lu)\n",
header.error_code = EACCES; GetLastError ());
CloseHandle (from_process_handle); header.error_code = EACCES;
CloseHandle (token_handle); CloseHandle (from_process_handle);
CloseHandle (token_handle);
/* more cleanup... yay! */ /* more cleanup... yay! */
return;
}
CloseHandle (token_handle);
return; return;
} }
header.error_code = ENOSYS;
CloseHandle (token_handle); CloseHandle (token_handle);
return; return;
} }

View File

@ -17,6 +17,7 @@ details. */
#define SHM_REATTACH 1 #define SHM_REATTACH 1
#define SHM_ATTACH 2 #define SHM_ATTACH 2
#define SHM_DETACH 3 #define SHM_DETACH 3
#define SHM_DEL 4
class client_request_shm : public client_request class client_request_shm : public client_request

View File

@ -134,6 +134,34 @@ build_inprocess_shmds (HANDLE hfilemap, HANDLE hattachmap, key_t key,
return tempnode; return tempnode;
} }
static void
delete_inprocess_shmds (shmnode **nodeptr)
{
shmnode *node = *nodeptr;
// remove from the list
if (node == shm_head)
shm_head = shm_head->next;
else
{
shmnode *tempnode = shm_head;
while (tempnode && tempnode->next != node)
tempnode = tempnode->next;
if (tempnode)
tempnode->next = node->next;
// else log the unexpected !
}
// release the shared data view
UnmapViewOfFile (node->shmds);
CloseHandle (node->filemap);
CloseHandle (node->attachmap);
// free the memory
delete node;
nodeptr = NULL;
}
int __stdcall int __stdcall
fixup_shms_after_fork () fixup_shms_after_fork ()
{ {
@ -352,8 +380,7 @@ shmctl (int shmid, int cmd, struct shmid_ds *buf)
* and each process, as they touch this area detaches. eventually only the * and each process, as they touch this area detaches. eventually only the
* daemon has an attach. The daemon gets asked to detach immediately. * daemon has an attach. The daemon gets asked to detach immediately.
*/ */
#if 0 //waiting for the daemon to handle terminating process's
//waiting for the daemon to handle terminating process's
client_request_shm *req = client_request_shm *req =
new client_request_shm (SHM_DEL, shmid, GetCurrentProcessId ()); new client_request_shm (SHM_DEL, shmid, GetCurrentProcessId ());
int rc; int rc;
@ -374,7 +401,8 @@ shmctl (int shmid, int cmd, struct shmid_ds *buf)
/* the daemon has deleted it's references */ /* the daemon has deleted it's references */
/* now for us */ /* now for us */
#endif // FIXME: create a destructor
delete_inprocess_shmds (&tempnode);
} }
break; break;