diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 4922d6120..89a97ea1a 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,47 @@ +2009-10-31 Corinna Vinschen + + * cygprops.h: New file. + * dtable.cc (handle_to_fn): Add check for correct installation_key + string in object name for pipes and ttys. + * external.cc (cygwin_internal): Add CW_GET_INSTKEY to allow fetching + the installation_key from cygserver. + * fhandler_fifo.cc (fhandler_fifo::fifo_name): Add installation_key + to fifo name. + * globals.cc: Include cygprops.h. + (_RDATA): Move slightly and add comment. + (cygwin_props): Define. + * mount.cc (mount_info::init): Accommodate the fact that + installation_root is now a global variable in DLL common shared memory, + rather than a member of cygwin_shared. + * pipe.cc (fhandler_pipe::create_selectable): Add installation_key to + pipe name. + * shared.cc (installation_root): Define here for storage in DLL + common shared memory. + (installation_key): Ditto. + (installation_key_buf): Ditto. + (init_installation_root): Convert from shared_info method to ordinary + function. Add initializing installation_key. Invalidate + installation_key depending of value of disable_key property. Add + comment to explain. + (get_shared_parent_dir): Add installation_key to directory name. + (get_session_parent_dir): Ditto. + (shared_info::initialize): Move call to init_installation_root from + here... + (memory_init): ...to here. Add debug output to print installation root + and installation key. Add comment to explain why. + * shared_info.h (SHARED_INFO_CB): Recalculate. + (CURR_SHARED_MAGIC): Ditto. + (class shared_info): Remove definition of installation_root and + declaration of init_installation_root. + (init_installation_root): Declare. + (installation_root): Declare. + (installation_key): Declare. + * uinfo.cc (pwdgrp::load): Accommodate the fact that installation_root + is now a global variable in DLL common shared memory. + * include/cygwin/version.h: Bump API minor number. + (CYGWIN_INFO_INSTALLATIONS_NAME): Add. + * include/sys/cygwin.h (cygwin_getinfo_types): Add CW_GET_INSTKEY. + 2009-10-31 Corinna Vinschen * sec_helper.cc (security_descriptor::realloc): Call free first if diff --git a/winsup/cygwin/cygprops.h b/winsup/cygwin/cygprops.h new file mode 100644 index 000000000..fa367bc5b --- /dev/null +++ b/winsup/cygwin/cygprops.h @@ -0,0 +1,20 @@ +/* cygprops.h: Cygwin DLL properties + + Copyright 2009 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* DLL properties data. */ +struct cygwin_props_t +{ + char magic[68]; + ULONG size; + ULONG disable_key; +}; + +#define CYGWIN_PROPS_MAGIC \ + "Fortunately, I keep my feathers numbered for just such an emergency" diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index ab4d1fbfd..61be7fc97 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -929,6 +929,14 @@ handle_to_fn (HANDLE h, char *posix_fn) if (wcsncmp (w32, L"cygwin-", WCLEN (L"cygwin-")) != 0) return false; w32 += WCLEN (L"cygwin-"); + /* Check for installation key and trailing dash. */ + w32len = installation_key.Length / sizeof (WCHAR); + if (w32len && wcsncmp (w32, installation_key.Buffer, w32len) != 0) + return false; + w32 += w32len; + if (*w32 != L'-') + return false; + ++w32; bool istty = wcsncmp (w32, L"tty", WCLEN (L"tty")) == 0; if (istty) decode_tty (posix_fn, w32 + WCLEN (L"tty")); diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc index 0b607f178..4d7f03d1b 100644 --- a/winsup/cygwin/external.cc +++ b/winsup/cygwin/external.cc @@ -460,6 +460,14 @@ cygwin_internal (cygwin_getinfo_types t, ...) res = 0; } break; + case CW_GET_INSTKEY: + { + extern WCHAR installation_key_buf[18]; + PWCHAR dest = va_arg (arg, PWCHAR); + wcscpy (dest, installation_key_buf); + res = 0; + } + break; default: set_errno (ENOSYS); diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc index d96616fc5..b612094dd 100644 --- a/winsup/cygwin/fhandler_fifo.cc +++ b/winsup/cygwin/fhandler_fifo.cc @@ -19,6 +19,7 @@ #include "cygheap.h" #include "sigproc.h" #include "cygtls.h" +#include "shared_info.h" fhandler_fifo::fhandler_fifo (): wait_state (fifo_unknown), dummy_client (NULL) @@ -58,8 +59,8 @@ char * fhandler_fifo::fifo_name (char *buf) { /* Generate a semi-unique name to associate with this fifo. */ - __small_sprintf (buf, "\\\\.\\pipe\\__cygfifo__%08x_%016X", - get_dev (), get_ino ()); + __small_sprintf (buf, "\\\\.\\pipe\\__cygfifo__%S_%08x_%016X", + &installation_key, get_dev (), get_ino ()); return buf; } diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index a1a4ae946..f30b6d02a 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -13,6 +13,7 @@ details. */ #include "winsup.h" #include "cygtls.h" #include "perprocess.h" +#include "cygprops.h" #include "thread.h" #include #include @@ -72,6 +73,9 @@ char NO_COPY almost_null[1]; char *old_title; +/* Define globally used, but readonly variables using the _RDATA attribute. */ +#define _RDATA __attribute__ ((section(".rdata"))) + /* Heavily-used const UNICODE_STRINGs are defined here once. The idea is a speed improvement by not having to initialize a UNICODE_STRING every time we make a string comparison. The strings are not defined as const, @@ -83,7 +87,6 @@ char *old_title; { Length: sizeof (_s) - sizeof (WCHAR), \ MaximumLength: sizeof (_s), \ Buffer: (PWSTR) (_s) } -#define _RDATA __attribute__ ((section(".rdata"))) UNICODE_STRING _RDATA ro_u_empty = _ROU (L""); UNICODE_STRING _RDATA ro_u_lnk = _ROU (L".lnk"); UNICODE_STRING _RDATA ro_u_exe = _ROU (L".exe"); @@ -102,9 +105,22 @@ UNICODE_STRING _RDATA ro_u_sunwnfs = _ROU (L"SUNWNFS"); UNICODE_STRING _RDATA ro_u_udf = _ROU (L"UDF"); UNICODE_STRING _RDATA ro_u_unixfs = _ROU (L"UNIXFS"); UNICODE_STRING _RDATA ro_u_volume = _ROU (L"\\??\\Volume{"); -#undef _RDATA #undef _ROU +/* Cygwin properties are meant to be readonly data placed in the DLL, but + which can be changed by external tools to make adjustments to the + behaviour of a DLL based on the binary of the DLL itself. This is + different from $CYGWIN since it only affects that very DLL, not all + DLLs which have access to the $CYGWIN environment variable. */ +cygwin_props_t _RDATA cygwin_props = +{ + CYGWIN_PROPS_MAGIC, + sizeof (cygwin_props_t), + 0 +}; + +#undef _RDATA + extern "C" { /* This is an exported copy of environ which can be used by DLLs diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 89f8587ae..e88bb9d9a 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -370,12 +370,13 @@ details. */ 214: Export execvpe, fexecve. 215: CW_EXIT_PROCESS added. 216: CW_SET_EXTERNAL_TOKEN added. + 217: CW_GET_INSTKEY added. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 216 +#define CYGWIN_VERSION_API_MINOR 217 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible @@ -410,6 +411,7 @@ details. */ #define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "Cygwin" #define CYGWIN_INFO_PROGRAM_OPTIONS_NAME "Program Options" +#define CYGWIN_INFO_INSTALLATIONS_NAME "Installations" /* The default cygdrive prefix. */ diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index ce9bebfdd..60fc9f05e 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -144,7 +144,8 @@ typedef enum CW_SET_PRIV_KEY, CW_SETERRNO, CW_EXIT_PROCESS, - CW_SET_EXTERNAL_TOKEN + CW_SET_EXTERNAL_TOKEN, + CW_GET_INSTKEY } cygwin_getinfo_types; /* Token type for CW_SET_EXTERNAL_TOKEN */ diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index a0b4b6782..8c9b72a2f 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -350,7 +350,7 @@ mount_info::init () PWCHAR pathend; WCHAR path[PATH_MAX]; - pathend = wcpcpy (path, cygwin_shared->installation_root); + pathend = wcpcpy (path, installation_root); create_root_entry (path); pathend = wcpcpy (pathend, L"\\etc\\fstab"); diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc index 5e557d8c6..aad1531d1 100644 --- a/winsup/cygwin/pipe.cc +++ b/winsup/cygwin/pipe.cc @@ -21,6 +21,7 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "pinfo.h" +#include "shared_info.h" fhandler_pipe::fhandler_pipe () : fhandler_base (), popen_pid (0), overlapped (NULL) @@ -216,7 +217,10 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r, if (psize < PIPE_BUF) psize = PIPE_BUF; - char pipename[MAX_PATH] = PIPE_INTRO; + char pipename[MAX_PATH]; + const size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-", + &installation_key); + /* FIXME: Eventually make ttys work with overlapped I/O. */ DWORD overlapped = name ? 0 : FILE_FLAG_OVERLAPPED; @@ -228,10 +232,10 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r, { static volatile ULONG pipe_unique_id; if (!name) - __small_sprintf (pipename + strlen(PIPE_INTRO), "pipe-%p-%p", myself->pid, + __small_sprintf (pipename + len, "pipe-%p-%p", myself->pid, InterlockedIncrement ((LONG *) &pipe_unique_id)); else - strcpy (pipename + strlen(PIPE_INTRO), name); + strcpy (pipename + len, name); debug_printf ("CreateNamedPipe: name %s, size %lu", pipename, psize); diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc index aad6c9499..ed3021cab 100644 --- a/winsup/cygwin/shared.cc +++ b/winsup/cygwin/shared.cc @@ -26,12 +26,96 @@ details. */ #include "ntdll.h" #include #include +#include +#include shared_info NO_COPY *cygwin_shared; user_info NO_COPY *user_shared; HANDLE NO_COPY cygwin_shared_h; HANDLE NO_COPY cygwin_user_h; +WCHAR installation_root[PATH_MAX] __attribute__((section (".cygwin_dll_common"), shared)); +UNICODE_STRING installation_key __attribute__((section (".cygwin_dll_common"), shared)); +WCHAR installation_key_buf[18] __attribute__((section (".cygwin_dll_common"), shared)); + +/* Use absolute path of cygwin1.dll to derive the Win32 dir which + is our installation_root. Note that we can't handle Cygwin installation + root dirs of more than 4K path length. I assume that's ok... + + This function also generates the installation_key value. It's a 64 bit + hash value based on the path of the Cygwin DLL itself. It's subsequently + used when generating shared object names. Thus, different Cygwin + installations generate different object names and so are isolated from + each other. + + Having this information, the installation key together with the + installation root path is written to the registry. The idea is that + cygcheck can print the paths into which the Cygwin DLL has been + installed for debugging purposes. + + Last but not least, the new cygwin properties datastrcuture is checked + for the "disabled_key" value, which is used to determine whether the + installation key is actually added to all object names or not. This is + used as a last resort for debugging purposes, usually. However, there + could be another good reason to re-enable object name collisions between + multiple Cygwin DLLs, which we're just not aware of right now. Cygcheck + can be used to change the value in an existing Cygwin DLL binary. */ + +void +init_installation_root () +{ + if (!GetModuleFileNameW (cygwin_hmodule, installation_root, PATH_MAX)) + api_fatal ("Can't initialize Cygwin installation root dir.\n" + "GetModuleFileNameW(%p, %p, %u), %E", + cygwin_hmodule, installation_root, PATH_MAX); + PWCHAR p = installation_root; + if (wcsncmp (p, L"\\\\?\\", 4)) /* No long path prefix. */ + { + if (!wcsncasecmp (p, L"\\\\", 2)) /* UNC */ + { + p = wcpcpy (p, L"\\??\\UN"); + GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 6); + *p = L'C'; + } + else + { + p = wcpcpy (p, L"\\??\\"); + GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 4); + } + } + installation_root[1] = L'?'; + + RtlInitEmptyUnicodeString (&installation_key, installation_key_buf, + sizeof installation_key_buf); + RtlInt64ToHexUnicodeString (hash_path_name (0, installation_root), + &installation_key, FALSE); + + PWCHAR w = wcsrchr (installation_root, L'\\'); + if (w) + { + *w = L'\0'; + w = wcsrchr (installation_root, L'\\'); + } + if (!w) + api_fatal ("Can't initialize Cygwin installation root dir.\n" + "Invalid DLL path"); + *w = L'\0'; + + for (int i = 1; i >= 0; --i) + { + reg_key r (i, KEY_WRITE, CYGWIN_INFO_INSTALLATIONS_NAME, NULL); + if (r.set_string (installation_key_buf, installation_root) + == ERROR_SUCCESS) + break; + } + + if (cygwin_props.disable_key) + { + installation_key.Length = 0; + installation_key.Buffer[0] = L'\0'; + } +} + /* This function returns a handle to the top-level directory in the global NT namespace used to implement global objects including shared memory. */ @@ -46,9 +130,10 @@ get_shared_parent_dir () if (!dir) { WCHAR bnoname[MAX_PATH]; - __small_swprintf (bnoname, L"\\BaseNamedObjects\\%s%s", + __small_swprintf (bnoname, L"\\BaseNamedObjects\\%s%s-%S", cygwin_version.shared_id, - _cygwin_testing ? cygwin_version.dll_build_date : ""); + _cygwin_testing ? cygwin_version.dll_build_date : "", + &installation_key); RtlInitUnicodeString (&uname, bnoname); InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF, NULL, everyone_sd (CYG_SHARED_DIR_ACCESS)); @@ -79,9 +164,10 @@ get_session_parent_dir () { WCHAR bnoname[MAX_PATH]; __small_swprintf (bnoname, - L"\\Sessions\\BNOLINKS\\%d\\%s%s", + L"\\Sessions\\BNOLINKS\\%d\\%s%s-%S", psi.SessionId, cygwin_version.shared_id, - _cygwin_testing ? cygwin_version.dll_build_date : ""); + _cygwin_testing ? cygwin_version.dll_build_date : "", + &installation_key); RtlInitUnicodeString (&uname, bnoname); InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF, NULL, everyone_sd(CYG_SHARED_DIR_ACCESS)); @@ -270,46 +356,6 @@ shared_destroy () UnmapViewOfFile (user_shared); } -/* Use absolute path of cygwin1.dll to derive the Win32 dir which - is our installation root. Note that we can't handle Cygwin installation - root dirs of more than 4K path length. I assume that's ok... */ -void -shared_info::init_installation_root () -{ - if (!GetModuleFileNameW (cygwin_hmodule, installation_root, PATH_MAX)) - api_fatal ("Can't initialize Cygwin installation root dir.\n" - "GetModuleFileNameW(%p, %p, %u), %E", - cygwin_hmodule, installation_root, PATH_MAX); - PWCHAR p = installation_root; - if (wcsncmp (p, L"\\\\?\\", 4)) /* No long path prefix. */ - { - if (!wcsncasecmp (p, L"\\\\", 2)) /* UNC */ - { - p = wcpcpy (p, L"\\??\\UN"); - GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 6); - *p = L'C'; - } - else - { - p = wcpcpy (p, L"\\??\\"); - GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 4); - } - } - installation_root[1] = L'?'; - - PWCHAR w = wcsrchr (installation_root, L'\\'); - if (w) - { - *w = L'\0'; - w = wcsrchr (installation_root, L'\\'); - } - if (!w) - api_fatal ("Can't initialize Cygwin installation root dir.\n" - "Invalid DLL path"); - - *w = L'\0'; -} - /* Initialize obcaseinsensitive. Default to case insensitive on pre-XP. */ void shared_info::init_obcaseinsensitive () @@ -349,7 +395,6 @@ shared_info::initialize () if (!sversion) { - init_installation_root ();/* Initialize installation root dir. */ init_obcaseinsensitive ();/* Initialize obcaseinsensitive. */ tty.init (); /* Initialize tty table. */ mt.initialize (); /* Initialize shared tape information. */ @@ -373,6 +418,10 @@ memory_init (bool init_cygheap) cygheap->user.init (); } + /* Initialize installation root dir. */ + if (!installation_root[0]) + init_installation_root (); + /* Initialize general shared memory */ shared_locations sh_cygwin_shared; cygwin_shared = (shared_info *) open_shared (L"shared", @@ -380,6 +429,11 @@ memory_init (bool init_cygheap) cygwin_shared_h, sizeof (*cygwin_shared), sh_cygwin_shared = SH_CYGWIN_SHARED); + /* Defer debug output printing the installation root and installation key + up to this point. Debug output except for system_printf requires + the global shared memory to exist. */ + debug_printf ("Installation root: <%W> key: <%S>", + installation_root, &installation_key); cygwin_shared->initialize (); user_shared_create (false); } diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h index c92358f2c..1fcb8ff86 100644 --- a/winsup/cygwin/shared_info.h +++ b/winsup/cygwin/shared_info.h @@ -29,9 +29,9 @@ public: cygwin_version.api_minor) #define SHARED_VERSION_MAGIC CYGWIN_VERSION_MAGIC (SHARED_MAGIC, SHARED_VERSION) -#define SHARED_INFO_CB 39328 +#define SHARED_INFO_CB 31136 -#define CURR_SHARED_MAGIC 0x22f9ff0bU +#define CURR_SHARED_MAGIC 0x18da899eU #define USER_VERSION 1 // increment when mount table changes and #define USER_VERSION_MAGIC CYGWIN_VERSION_MAGIC (USER_MAGIC, USER_VERSION) @@ -51,12 +51,10 @@ class shared_info DWORD sys_mount_table_counter; tty_list tty; LONG last_used_bindresvport; - WCHAR installation_root[PATH_MAX]; DWORD obcaseinsensitive; mtinfo mt; void initialize (); - void init_installation_root (); void init_obcaseinsensitive (); unsigned heap_chunk_size (); unsigned heap_slop_size (); @@ -105,4 +103,6 @@ void *__stdcall open_shared (const WCHAR *name, int n, HANDLE &shared_h, DWORD access = FILE_MAP_READ | FILE_MAP_WRITE); extern void user_shared_create (bool reinit); extern void user_shared_initialize (); - +extern void init_installation_root (); +extern WCHAR installation_root[PATH_MAX]; +extern UNICODE_STRING installation_key; diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 51fd8ad76..440efbb38 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -518,13 +518,13 @@ pwdgrp::load (const wchar_t *rel_path) curr_lines = 0; if (!path && - !(path = (PWCHAR) malloc ((wcslen (cygwin_shared->installation_root) + !(path = (PWCHAR) malloc ((wcslen (installation_root) + wcslen (rel_path) + 1) * sizeof (WCHAR)))) { paranoid_printf ("malloc (%W) failed", rel_path); goto out; } - wcpcpy (wcpcpy (path, cygwin_shared->installation_root), rel_path); + wcpcpy (wcpcpy (path, installation_root), rel_path); RtlInitUnicodeString (&upath, path); InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);