Re: [PATCH 06/11] Remove always true nonnull check on "this" pointer.

2016-03-30 Thread Corinna Vinschen
Hi Peter,

On Mar 19 13:45, Peter Foley wrote:
> G++ 6.0 can assert that the this pointer is non-null for member functions.

Maybe, but if it compains, it's bound to find false positives...

> @@ -502,7 +502,7 @@ fhandler_dev_dsp::Audio_out::buf_info (audio_buf_info *p,
>  int rate, int bits, int channels)
>  {
>p->fragstotal = MAX_BLOCKS;
> -  if (this && dev_)
> +  if (dev_)
>  {
>/* If the device is running we use the internal values,
>possibly set from the wave file. */

This is wrong.  fhandler_dev_dsp::Audio_out::buf_info is called from
fhandler_dev_dsp::_ioctl.  An application can call ioctl without
an open audio channel.  If so, audio_out_ may be NULL and the
Audio_out::buf_info method is called with a NULL this pointer..

> @@ -959,7 +959,7 @@ fhandler_dev_dsp::Audio_in::buf_info (audio_buf_info *p,
>  {
>p->fragstotal = MAX_BLOCKS;
>p->fragsize = blockSize (rate, bits, channels);
> -  if (this && dev_)
> +  if (dev_)

Ditto.

>  {
>p->fragments = Qisr2app_->query ();
>if (pHdr_ != NULL)
> diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
> index 20391bf..df09d70 100644
> --- a/winsup/cygwin/path.cc
> +++ b/winsup/cygwin/path.cc
> @@ -3937,7 +3937,7 @@ fcwd_access_t::Free (PVOID heap)
>  {
>/* Decrement the reference count.  If it's down to 0, free
>   structure from heap. */
> -  if (this && InterlockedDecrement (&ReferenceCount ()) == 0)
> +  if (InterlockedDecrement (&ReferenceCount ()) == 0)

Very unlikely, but *fast_cwd_ptr *might be NULL.  Better save than sorry.

>  {
>/* In contrast to pre-Vista, the handle on init is always a
>fresh one and not the handle inherited from the parent
> diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
> index be32cfd..409a0b7 100644
> --- a/winsup/cygwin/pinfo.cc
> +++ b/winsup/cygwin/pinfo.cc
> @@ -514,7 +514,7 @@ _pinfo::set_ctty (fhandler_termios *fh, int flags)
>  bool __reg1
>  _pinfo::exists ()
>  {
> -  return this && process_state && !(process_state & (PID_EXITED | PID_REAPED 
> | PID_EXECED));
> +  return process_state && !(process_state & (PID_EXITED | PID_REAPED | 
> PID_EXECED));

Assuming a pinfo constructor called like this:

  pinfo p (non_existent_pid);

then p->_procinfo is NULL.  Calling p->exists then calls _pinfo::exists
with a NULL this pointer.  Analog for the other _pinfo methods.


Corinna

-- 
Corinna Vinschen  Please, send mails regarding Cygwin to
Cygwin Maintainer cygwin AT cygwin DOT com
Red Hat


signature.asc
Description: PGP signature


Re: [PATCH v2 1/3] Add option to not build mingw programs when cross compiling.

2016-03-30 Thread Corinna Vinschen
On Mar 23 09:34, Peter Foley wrote:
> Add an option to not require a mingw compiler when bootstrapping a cross 
> toolchain.
> Defaults to existing behavior.
> Also update some obsolete macros.

Applied with changes.  The below check was skewed.

> +if test "x$with_mingw_progs" != xyes; then
> +AC_CONFIG_SUBDIRS([utils lsaauth])
> +fi

Thanks,
Corinna

-- 
Corinna Vinschen  Please, send mails regarding Cygwin to
Cygwin Maintainer cygwin AT cygwin DOT com
Red Hat


signature.asc
Description: PGP signature


Re: [PATCH 3/3] Use just-built gcc for windres

2016-03-30 Thread Corinna Vinschen
On Mar 23 09:34, Peter Foley wrote:
> When building cygwin in a combined tree with binutils,
> the just-built windres cannot find the just-buit gcc automatically.
> Parse the CC env variable to use the correct compiler, rather then
> falling back to the build-system's gcc which does not define the proper
> preprocessor macros.
> 
> winsup/cygwin/ChangeLog
> mkvers.sh: Manually specify preprocessor based on $CC

Are you sure this works as desired?  In my standard cross build
environment, the only -B option added here is

  --preprocessor-arg=-B/build/cygwin/x86_64/vanilla/x86_64-pc-cygwin/newlib/

?


Thanks,
Corinna

-- 
Corinna Vinschen  Please, send mails regarding Cygwin to
Cygwin Maintainer cygwin AT cygwin DOT com
Red Hat


signature.asc
Description: PGP signature


Re: [PATCH 3/3] Use just-built gcc for windres

2016-03-30 Thread Peter Foley
On Wed, Mar 30, 2016 at 8:31 AM, Corinna Vinschen
 wrote:
> Are you sure this works as desired?  In my standard cross build
> environment, the only -B option added here is
>
>   --preprocessor-arg=-B/build/cygwin/x86_64/vanilla/x86_64-pc-cygwin/newlib/

The only case in which -B is needed at all is for an in-tree build.
That is, gcc and winsup are in the same source tree, so CC is set to
something like ./gcc/xgcc.
In that case, the -B is necessary so that gcc knows where to find the
cc1 binary.
If gcc and winsup are built from separate source trees, it isn't an issue.

Thanks,

Peter


Re: [PATCH v2 1/3] Add option to not build mingw programs when cross compiling.

2016-03-30 Thread Peter Foley
On Wed, Mar 30, 2016 at 8:11 AM, Corinna Vinschen
 wrote:
> Applied with changes.  The below check was skewed.
>
>> +if test "x$with_mingw_progs" != xyes; then
>> +AC_CONFIG_SUBDIRS([utils lsaauth])
>> +fi

Whoops, good catch.


Re: [PATCH 06/11] Remove always true nonnull check on "this" pointer.

2016-03-30 Thread Peter Foley
On Wed, Mar 30, 2016 at 7:24 AM, Corinna Vinschen
 wrote:
> Hi Peter,
>
> On Mar 19 13:45, Peter Foley wrote:
>> G++ 6.0 can assert that the this pointer is non-null for member functions.
>
> Maybe, but if it compains, it's bound to find false positives...
>

Alright, I'll take a closer look at this.


[PATCH] fix typo in netinit/ip.h

2016-03-30 Thread Peter Foley
The type for the ip_tos member was typoed, fix it.

winsup/cygwin/ChangeLog:
include/netinet/ip.h: fix type of ip_tos

Signed-off-by: Peter Foley 
---
 winsup/cygwin/include/netinet/ip.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/cygwin/include/netinet/ip.h 
b/winsup/cygwin/include/netinet/ip.h
index b952d53..1f6ebbe 100644
--- a/winsup/cygwin/include/netinet/ip.h
+++ b/winsup/cygwin/include/netinet/ip.h
@@ -63,7 +63,7 @@ struct ip {
 ip_hl:4;   /* header length */
 #endif
 #endif /* not _IP_VHL */
-   u_int_8   ip_tos;   /* type of service */
+   u_int8_t   ip_tos;  /* type of service */
u_int16_t ip_len;   /* total length */
u_int16_t ip_id;/* identification */
u_int16_t ip_off;   /* fragment offset field */
-- 
2.8.0



Re: [PATCH] fix typo in netinit/ip.h

2016-03-30 Thread Corinna Vinschen
On Mar 30 09:15, Peter Foley wrote:
> The type for the ip_tos member was typoed, fix it.
> 
> winsup/cygwin/ChangeLog:
> include/netinet/ip.h: fix type of ip_tos

Thanks for catching.  Applied.


Corinna

-- 
Corinna Vinschen  Please, send mails regarding Cygwin to
Cygwin Maintainer cygwin AT cygwin DOT com
Red Hat


signature.asc
Description: PGP signature


Re: [PATCH 3/3] Use just-built gcc for windres

2016-03-30 Thread Corinna Vinschen
On Mar 23 09:34, Peter Foley wrote:
> When building cygwin in a combined tree with binutils,
> the just-built windres cannot find the just-buit gcc automatically.
> Parse the CC env variable to use the correct compiler, rather then
> falling back to the build-system's gcc which does not define the proper
> preprocessor macros.
> 
> winsup/cygwin/ChangeLog
> mkvers.sh: Manually specify preprocessor based on $CC

Applied.


Thanks,
Corinna

-- 
Corinna Vinschen  Please, send mails regarding Cygwin to
Cygwin Maintainer cygwin AT cygwin DOT com
Red Hat


signature.asc
Description: PGP signature


[PATCH 2/6] forkables: Track main executable and cygwin1.dll.

2016-03-30 Thread Michael Haubenwallner
In preparation to protect fork() against dll- and exe-updates, even for
the main executable and cygwin1.dll store the file name as full NT path,
and keep handles to the files open for subsequent hardlink creation.
Create the child process using the main executable's file name converted
from the full NT path stored before.

* dll_init.cc (dll_list::alloc): Search for DLL_SELF type entry
with module name like for DLL_LINK, use full NT path to search
for DLL_LOAD type only.  For DLL_SELF type do not indicate
having a destructor to be called.
(dll_list::find): Ignore DLL_SELF type entries.
(dll_list::init): Ditto.  Call track_self method.
(dll_list::track_self): New.
(dll_list::load_after_fork): Call track_self method.
* dll_init.h (enum dll_type): Add DLL_SELF, for the main
executable and cygwin1.dll.
(struct dll_list): Declare method track_self.  Declare member
variable main_executable.
* fork.cc (frok::parent): Use ntname from dlls.main_executable
to create child process, converted to short path using
dll_list::buffered_shortname.
---
 winsup/cygwin/dll_init.cc | 26 --
 winsup/cygwin/dll_init.h  |  3 +++
 winsup/cygwin/fork.cc | 15 ---
 3 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
index 0494297..fd807c9 100644
--- a/winsup/cygwin/dll_init.cc
+++ b/winsup/cygwin/dll_init.cc
@@ -343,8 +343,9 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
   guard (true);
   /* Already loaded?  For linked DLLs, only compare the basenames.  Linked
  DLLs are loaded using just the basename and the default DLL search path.
- The Windows loader picks up the first one it finds.  */
-  dll *d = (type == DLL_LINK) ? dlls.find_by_modname (modname) : dlls[ntname];
+ The Windows loader picks up the first one it finds.
+ This also applies to cygwin1.dll and the main-executable (DLL_SELF).  */
+  dll *d = (type != DLL_LOAD) ? dlls.find_by_modname (modname) : dlls[ntname];
   if (d)
 {
   if (!in_forkee)
@@ -380,7 +381,8 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
   wcscpy (d->ntname, ntname);
   d->modname = d->ntname + (modname - ntname);
   d->handle = h;
-  d->has_dtors = true;
+  /* DLL_SELF dtors (main-executable, cygwin1.dll) are run elsewhere */
+  d->has_dtors = type != DLL_SELF;
   d->p = p;
   d->ndeps = 0;
   d->deps = NULL;
@@ -529,7 +531,7 @@ dll_list::find (void *retaddr)
 
   dll *d = &start;
   while ((d = d->next))
-if (d->handle == h)
+if (d->type != DLL_SELF && d->handle == h)
   break;
   return d;
 }
@@ -579,11 +581,22 @@ dll_list::detach (void *retaddr)
 void
 dll_list::init ()
 {
+  track_self ();
+
   /* Walk the dll chain, initializing each dll */
   dll *d = &start;
   dll_global_dtors_recorded = d->next != NULL;
   while ((d = d->next))
-d->init ();
+if (d->type != DLL_SELF) /* linked and early loaded dlls */
+  d->init ();
+}
+
+void
+dll_list::track_self ()
+{
+  /* for cygwin1.dll and main-executable: maintain hardlinks only */
+  alloc (cygwin_hmodule, user_data, DLL_SELF);
+  main_executable = alloc (GetModuleHandle (NULL), user_data, DLL_SELF);
 }
 
 #define A64K (64 * 1024)
@@ -650,7 +663,7 @@ dll_list::reserve_space ()
 
 /* Reload DLLs after a fork.  Iterates over the list of dynamically loaded
DLLs and attempts to load them in the same place as they were loaded in the
-   parent. */
+   parent.  Updates main-executable and cygwin1.dll tracking. */
 void
 dll_list::load_after_fork (HANDLE parent)
 {
@@ -662,6 +675,7 @@ dll_list::load_after_fork (HANDLE parent)
   in_load_after_fork = true;
   if (reload_on_fork)
 load_after_fork_impl (parent, dlls.istart (DLL_LOAD), 0);
+  track_self ();
   in_load_after_fork = false;
 }
 
diff --git a/winsup/cygwin/dll_init.h b/winsup/cygwin/dll_init.h
index d4cbd3d..c50f889 100644
--- a/winsup/cygwin/dll_init.h
+++ b/winsup/cygwin/dll_init.h
@@ -43,6 +43,7 @@ struct per_module
 typedef enum
 {
   DLL_NONE,
+  DLL_SELF, /* main-program.exe, cygwin1.dll */
   DLL_LINK,
   DLL_LOAD,
   DLL_ANY
@@ -82,6 +83,7 @@ struct dll
 
 class dll_list
 {
+  void track_self ();
   void set_forkables_inheritance (bool);
 
   dll *end;
@@ -92,6 +94,7 @@ class dll_list
   static WCHAR NO_COPY nt_max_path_buffer[NT_MAX_PATH];
 public:
   /* forkables */
+  dll *main_executable;
   void request_forkables ();
   void release_forkables ();
 
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 4361f58..7bc3dec 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -188,7 +188,7 @@ frok::child (volatile char * volatile here)
 
   MALLOC_CHECK;
 
-  /* load dynamic dlls, if any */
+  /* load dynamic dlls, if any, re-track main-executable and cygwin1.dll */
   dlls.load_after_fork (hParent);
 
   cygheap->fdtab.fix

[PATCH 0/6] Protect fork() against dll- and exe-updates.

2016-03-30 Thread Michael Haubenwallner
Hi,

this is the updated and split series of patches to use hardlinks
for creating the child process by fork(), in reply to
https://cygwin.com/ml/cygwin-developers/2016-01/msg2.html
https://cygwin.com/ml/cygwin-developers/2016-03/msg5.html
http://thread.gmane.org/gmane.os.cygwin.devel/1378

Thanks for review!
/haubi/



[PATCH 4/6] forkables: Protect fork against dll-, exe-updates.

2016-03-30 Thread Michael Haubenwallner
To support in-cygwin package managers, the fork() implementation must
not rely on .exe and .dll files to stay in their original location, as
the package manager's job is to replace these files.  Instead, we use
the hardlinks to the original binaries in /var/run/cygfork/ to create
the child process during fork, and let the main.exe.local file enable
the "DotLocal Dll Redirection" feature for dlls.

The (probably few) users that need an update-safe fork manually have to
create the /var/run/cygfork/ directory for now, using:
mkdir --mode=a=rwxt /var/run/cygfork

* dll_init.h (struct dll_list): Declare find_by_forkedntname.
* dll_init.cc (struct dll_list): Implement find_by_forkedntname.
(dll_list::alloc): Use find_by_forkedntname when in load after fork.
(dll_list::load_after_fork_impl): Use dll::forkedntname to load dlls.
* fork.cc (frok::parent): Use forkedntname of dlls.main_executable.
---
 winsup/cygwin/dll_init.cc | 47 +--
 winsup/cygwin/dll_init.h  |  1 +
 winsup/cygwin/fork.cc |  2 +-
 3 files changed, 35 insertions(+), 15 deletions(-)

diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
index e44ee84..71a7456 100644
--- a/winsup/cygwin/dll_init.cc
+++ b/winsup/cygwin/dll_init.cc
@@ -325,6 +325,19 @@ dll_list::find_by_modname (PCWCHAR modname)
   return NULL;
 }
 
+/* Look for a dll based on the ntname used
+   to dynamically reload in forked child. */
+dll *
+dll_list::find_by_forkedntname (PCWCHAR ntname)
+{
+  dll *d = &start;
+  while ((d = d->next) != NULL)
+if (!wcscasecmp (ntname, d->forkedntname ()))
+  return d;
+
+  return NULL;
+}
+
 #define RETRIES 1000
 
 /* Allocate space for a dll struct. */
@@ -344,8 +357,11 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type 
type)
   /* Already loaded?  For linked DLLs, only compare the basenames.  Linked
  DLLs are loaded using just the basename and the default DLL search path.
  The Windows loader picks up the first one it finds.
- This also applies to cygwin1.dll and the main-executable (DLL_SELF).  */
-  dll *d = (type != DLL_LOAD) ? dlls.find_by_modname (modname) : dlls[ntname];
+ This also applies to cygwin1.dll and the main-executable (DLL_SELF).
+ When in_load_after_fork, dynamically loaded dll's are reloaded
+ using their parent's forkable_ntname, if available.  */
+  dll *d = (type != DLL_LOAD) ? dlls.find_by_modname (modname) :
+  in_load_after_fork ? dlls.find_by_forkedntname (ntname) : 
dlls[ntname];
   if (d)
 {
   if (!in_forkee)
@@ -728,14 +744,16 @@ void dll_list::load_after_fork_impl (HANDLE parent, dll* 
d, int retries)
  fabort ("unable to release protective reservation (%p) for %W, %E",
  d->handle, d->ntname);
 
-   HMODULE h = LoadLibraryExW (buffered_shortname (d->ntname),
+   HMODULE h = LoadLibraryExW (buffered_shortname (d->forkedntname ()),
NULL, DONT_RESOLVE_DLL_REFERENCES);
if (!h)
- fabort ("unable to create interim mapping for %W, %E", d->ntname);
+ fabort ("unable to create interim mapping for %W (using %W), %E",
+ d->ntname, buffered_shortname (d->forkedntname ()));
if (h != d->handle)
  {
-   sigproc_printf ("%W loaded in wrong place: %p != %p",
-   d->ntname, h, d->handle);
+   sigproc_printf ("%W (using %W) loaded in wrong place: %p != %p",
+   d->ntname, buffered_shortname (d->forkedntname ()),
+   h, d->handle);
FreeLibrary (h);
PVOID reservation = reserve_at (d->ntname, h,
d->handle, d->image_size);
@@ -746,8 +764,8 @@ void dll_list::load_after_fork_impl (HANDLE parent, dll* d, 
int retries)
if (retries < DLL_RETRY_MAX)
  load_after_fork_impl (parent, d, retries+1);
else
-  fabort ("unable to remap %W to same address as parent (%p) - try 
running rebaseall",
-  d->ntname, d->handle);
+  fabort ("unable to remap %W (using %W) to same address as parent 
(%p) - try running rebaseall",
+  d->ntname, buffered_shortname (d->forkedntname ()), 
d->handle);
 
/* once the above returns all the dlls are mapped; release
   the reservation and continue unwinding */
@@ -775,17 +793,18 @@ void dll_list::load_after_fork_impl (HANDLE parent, dll* 
d, int retries)
  /* Free the library using our parent's handle: it's identical
 to ours or we wouldn't have gotten this far */
  if (!FreeLibrary (d->handle))
-   fabort ("unable to unload interim mapping of %W, %E",
-   d->ntname);
+   fabort ("unable to unload interim mapping of %W (using %W), %E",
+   d->ntname, buffered_shortname (d->forkedntname ()));
  

[PATCH 1/6] forkables: Store dll file name as full NT path.

2016-03-30 Thread Michael Haubenwallner
In preparation to protect fork() against dll- and exe-updates, store
any dll file name as full NT path.  Additionally, keep a file handle
open for each loaded dll file for subsequent hardlink creation.  The
earlier we open a handle to the dll file, the lower is the chance the
dll file has been renamed since first loading.  To lower that chance
even more, the dll file handle is inherited by child processes rather
than opened again.

* Makefile.in (DLL_OFILES): Add forkable.o.
* dll_init.h (struct dll): Declare member fhandle.
Rename member variable name to ntname.
(struct dll_list): Declare private method
set_forkables_inheritance.  Declare public methods
request_forkables, release_forkables.  Declare public static
methods ntopenfile, form_ntname, form_shortname, nt_max_path_buf,
buffered_ntname, buffered_shortname.
(dll_list::operator []): Use PCWCHAR rather than const PWCHAR.
(dll_list::find_by_modname): Ditto.
* dll_init.cc (in_load_after_fork): Define earlier in file.
(struct dll_list): Rename member variable name to ntname.
Define nt_max_path_buffer variable.
Implement static methods form_ntname, form_shortname, ntopenfile.
(dll_list::operator []): Use PCWCHAR rather than const PWCHAR.
(dll_list::find_by_modname): Ditto.
(reserve_at): Ditto.
(release_at): Ditto.
(dll_list::alloc): Use nt_max_path_buf method instead of local
buffer.  Store module file name as full NT path, convert using
the form_ntname static method.  Open file handle as fhandle for
the loaded dll.
(dll_list::detach): Close the fhandle.
(dll_list::load_after_fork): Call release_forkables method.
Call load_after_fork_impl only when reload_on_fork is set.
* fork.cc (frok::child): Call dlls.load_after_fork even without
need to dynamically load dlls, to release_forkables at least.
(frok::parent): Call dlls.request_forkables before
CreateProcessW, dlls.release_forkables afterwards.
* forkable.cc: New file.
(struct dll_list): Implement methods set_forkables_inheritance,
request_forkables, release_forkables.
---
 winsup/cygwin/Makefile.in |   1 +
 winsup/cygwin/dll_init.cc | 250 +-
 winsup/cygwin/dll_init.h  |  37 ++-
 winsup/cygwin/fork.cc |  33 +++---
 winsup/cygwin/forkable.cc |  55 ++
 5 files changed, 310 insertions(+), 66 deletions(-)
 create mode 100644 winsup/cygwin/forkable.cc

diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index 43919bd..15ddce8 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -307,6 +307,7 @@ DLL_OFILES:= \
flock.o \
fnmatch.o \
fork.o \
+   forkable.o \
fts.o \
ftw.o \
getopt.o \
diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
index 8deceb9..0494297 100644
--- a/winsup/cygwin/dll_init.cc
+++ b/winsup/cygwin/dll_init.cc
@@ -33,10 +33,162 @@ extern void __stdcall check_sanity_and_sync (per_process 
*);
 
 dll_list dlls;
 
+WCHAR NO_COPY dll_list::nt_max_path_buffer[NT_MAX_PATH];
+
 muto dll_list::protect;
 
 static bool dll_global_dtors_recorded;
 
+/* We need the in_load_after_fork flag so dll_dllcrt0_1 can decide at fork
+   time if this is a linked DLL or a dynamically loaded DLL.  In either case,
+   both, cygwin_finished_initializing and in_forkee are true, so they are not
+   sufficient to discern the situation. */
+static bool NO_COPY in_load_after_fork;
+
+/* Into ntbuf with ntbufsize, prints name prefixed with "\\??\\"
+   or "\\??\\UNC" as necessary to form the native NT path name.
+   Returns the end of the resulting string in ntbuf.
+   Supports using (a substring of) ntbuf as name argument. */
+PWCHAR dll_list::form_ntname (PWCHAR ntbuf, size_t ntbufsize, PCWCHAR name)
+{
+  while (true)
+{
+  /* avoid using path_conv here: cygheap might not be
+initialized when started from non-cygwin process,
+or still might be frozen in_forkee */
+  if (name[0] == L'\0' || ntbufsize < 8)
+   break;
+  if (name[1] == L':') /* short Win32 drive letter path name */
+   {
+ int winlen = min (ntbufsize - 5, wcslen (name));
+ if (ntbuf + 4 != name)
+   memmove (ntbuf + 4, name, sizeof (*ntbuf) * winlen);
+ wcsncpy (ntbuf, L"\\??\\", 4);
+ ntbuf += 4 + winlen;
+ break;
+   }
+  if (!wcsncmp (name, L"?\\", 4)) /* long Win32 path name */
+   {
+ int winlen = min (ntbufsize - 1, wcslen (name));
+ if (ntbuf != name)
+   memmove (ntbuf, name, sizeof (*ntbuf) * winlen);
+ ntbuf[1] = L'?';
+ ntbuf += winlen;
+ break;
+   }
+  if (!wcsncmp (name, L"", 2)) /* short Win32 UNC path name */
+   {
+ name += 1; /* skip first backslash */
+   

[PATCH 3/6] forkables: Create forkable hardlinks, yet unused.

2016-03-30 Thread Michael Haubenwallner
In preparation to protect fork() against dll- and exe-updates, create
hardlinks to the main executable and each loaded dll in subdirectories
of /var/run/cygfork/, if that one exists on the NTFS file system.

The directory names consist of the user sid, the main executable's NTFS
IndexNumber, and the most recent LastWriteTime of all involved binaries
(dlls and main executable).  Next to the main.exe hardlink we create the
empty file main.exe.local to enable dll redirection.

The name of the mutex to synchronize hardlink creation/cleanup also is
assembled from these directory names, to allow for synchronized cleanup
of even orphaned hardlink directories.

The hardlink to each dynamically loaded dll goes into another directory,
named using the NTFS IndexNumber of the dll's original directory.

* dll_init.h (struct dll): Declare member variables fbi, fii,
forkable_ntname.  Declare methods nominate_forkable,
create_forkable.  Define inline method forkedntname.
(struct dll_list): Declare enum forkables_needs.  Declare member
variables forkables_dirx_size, forkables_dirx_ntname,
forkables_mutex_name, forkables_mutex.  Declare private methods
forkable_ntnamesize, prepare_forkables_nomination,
update_forkables_needs, update_forkables, create_forkables,
denominate_forkables, close_mutex, try_remove_forkables.
Declare public method cleanup_forkables.
* dll_init.cc (dll_list::alloc): Allocate memory to hold the
name of the hardlink in struct dll member forkable_ntname.
Initialize struct dll members fbi, fii.
* forkable.cc: Implement static functions mkdirs, rmdirs,
rmdirs_synchronized, read_fii, read_fbi, format_IndexNumber,
rootname, sidname, exename, lwtimename.  Define static array
forkable_nameparts.
(struct dll): Implement nominate_forkable, create_forkable.
(struct dll_list): Implement forkable_ntnamesize,
prepare_forkables_nomination, update_forkables_needs,
update_forkables, create_forkables, close_mutex,
cleanup_forkables, try_remove_forkables, denominate_forkables.
(dll_list::set_forkables_inheritance): Also for forkables_mutex.
(dll_list::request_forkables): Use new methods to create the
hardlinks as necessary.
(dll_list::release_forkables): When hardlink creation turned out
to be impossible, close all the related handles and free the
distinct memory.
* pinfo.cc (pinfo::exit): Call dlls.cleanup_forkables.
* syscalls.cc (_unlink_nt): Rename public unlink_nt function to
static _unlink_nt, with 'shareable' as additional argument.
(unlink_nt): New, wrap _unlink_nt for original behaviour.
(unlink_nt_shareable): New, wrap _unlink_nt to keep a binary
file still loadable while removing one of its hardlinks.
---
 winsup/cygwin/dll_init.cc |   28 +-
 winsup/cygwin/dll_init.h  |   33 ++
 winsup/cygwin/forkable.cc | 1036 +
 winsup/cygwin/pinfo.cc|3 +
 winsup/cygwin/syscalls.cc |   24 +-
 5 files changed, 1115 insertions(+), 9 deletions(-)

diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
index fd807c9..e44ee84 100644
--- a/winsup/cygwin/dll_init.cc
+++ b/winsup/cygwin/dll_init.cc
@@ -372,8 +372,11 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type 
type)
 }
   else
 {
+  size_t forkntsize = forkable_ntnamesize (type, ntname, modname);
+
   /* FIXME: Change this to new at some point. */
-  d = (dll *) cmalloc (HEAP_2_DLL, sizeof (*d) + (ntnamelen * sizeof 
(*ntname)));
+  d = (dll *) cmalloc (HEAP_2_DLL, sizeof (*d)
+  + ((ntnamelen + forkntsize) * sizeof (*ntname)));
 
   /* Now we've allocated a block of information.  Fill it in with the
 supplied info about this DLL. */
@@ -389,11 +392,24 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type 
type)
   d->image_size = ((pefile*)h)->optional_hdr ()->SizeOfImage;
   d->preferred_base = (void*) ((pefile*)h)->optional_hdr()->ImageBase;
   d->type = type;
-  NTSTATUS status;
-  d->fhandle = ntopenfile (d->ntname, &status);
-  if (!d->fhandle)
-   system_printf ("Unable (ntstatus %y) to open file %W",
-  status, d->ntname);
+  d->fhandle = NULL;
+  d->fbi.FileAttributes = INVALID_FILE_ATTRIBUTES;
+  d->fii.IndexNumber.QuadPart = 0;
+  d->forkable_ntname = NULL;
+  if (forkntsize)
+   {
+ NTSTATUS status;
+ d->fhandle = ntopenfile (d->ntname, &status);
+ if (!d->fhandle)
+   system_printf ("Unable (ntstatus %y) to open file %W",
+  status, d->ntname);
+ else
+   {
+ /* may create a hardlink */
+ d->forkable_ntname = d->ntname + ntnamelen + 1;
+ *d->forkable_ntname = L'\0';
+   }
+ 

Re: [PATCH 0/6] Protect fork() against dll- and exe-updates.

2016-03-30 Thread Daniel Colascione


On 03/30/2016 11:53 AM, Michael Haubenwallner wrote:
> Hi,
> 
> this is the updated and split series of patches to use hardlinks
> for creating the child process by fork(), in reply to
> https://cygwin.com/ml/cygwin-developers/2016-01/msg2.html
> https://cygwin.com/ml/cygwin-developers/2016-03/msg5.html
> http://thread.gmane.org/gmane.os.cygwin.devel/1378
> 
> Thanks for review!
> /haubi/
> 
> 

Creating a new process now requires a write operation on the filesystem
hosting the binary? Seriously? I don't think that's worth it no matter
the other benefits.



signature.asc
Description: OpenPGP digital signature


Re: [PATCH 4/6] forkables: Protect fork against dll-, exe-updates.

2016-03-30 Thread Yaakov Selkowitz

On 2016-03-30 13:53, Michael Haubenwallner wrote:

To support in-cygwin package managers, the fork() implementation must
not rely on .exe and .dll files to stay in their original location, as
the package manager's job is to replace these files.  Instead, we use
the hardlinks to the original binaries in /var/run/cygfork/ to create
the child process during fork, and let the main.exe.local file enable
the "DotLocal Dll Redirection" feature for dlls.

The (probably few) users that need an update-safe fork manually have to
create the /var/run/cygfork/ directory for now, using:
mkdir --mode=a=rwxt /var/run/cygfork


Have the security implications of this been considered?

--
Yaakov


Re: [PATCH 0/6] Protect fork() against dll- and exe-updates.

2016-03-30 Thread Michael Haubenwallner
On 03/30/2016 08:55 PM, Daniel Colascione wrote:
> 
> 
> On 03/30/2016 11:53 AM, Michael Haubenwallner wrote:
>> Hi,
>>
>> this is the updated and split series of patches to use hardlinks
>> for creating the child process by fork(), in reply to
>> https://cygwin.com/ml/cygwin-developers/2016-01/msg2.html
>> https://cygwin.com/ml/cygwin-developers/2016-03/msg5.html
>> http://thread.gmane.org/gmane.os.cygwin.devel/1378
>>
>> Thanks for review!
>> /haubi/
>>
>>
> 
> Creating a new process now requires a write operation on the filesystem
> hosting the binary? Seriously? I don't think that's worth it no matter
> the other benefits.
> 

Only if the original binaries necessary to create the new child process
by fork() are not available any more - and the /var/run/cygfork/
directory does exist and is on NTFS.  I do prefer a working fork() even
when updating dlls and executables while the parent process is running.

/haubi/


Re: [PATCH 4/6] forkables: Protect fork against dll-, exe-updates.

2016-03-30 Thread Michael Haubenwallner
On 03/30/2016 09:04 PM, Yaakov Selkowitz wrote:
> On 2016-03-30 13:53, Michael Haubenwallner wrote:
>> To support in-cygwin package managers, the fork() implementation must
>> not rely on .exe and .dll files to stay in their original location, as
>> the package manager's job is to replace these files.  Instead, we use
>> the hardlinks to the original binaries in /var/run/cygfork/ to create
>> the child process during fork, and let the main.exe.local file enable
>> the "DotLocal Dll Redirection" feature for dlls.
>>
>> The (probably few) users that need an update-safe fork manually have to
>> create the /var/run/cygfork/ directory for now, using:
>> mkdir --mode=a=rwxt /var/run/cygfork
> 
> Have the security implications of this been considered?

Which security implications do you think of?

Removed but in-use binaries are available in the recycle bin anyway,
and can manually be hardlinked to wherever one likes...

/haubi/


[PATCH 5/6] forkables: Keep hardlinks disabled via shared mem.

2016-03-30 Thread Michael Haubenwallner
To avoid the need for each process to check the filesystem to detect
that hardlink creation is impossible or disabled, cache this fact in
shared memory.  Removing cygfork directory while in use does disable
hardlinks creation.  To (re-)enable hardlinks creation, the cygfork
directory has to exist before the first cygwin process does fork.

* forkable.cc (dll_list::forkable_ntnamesize): Short cut
forkables needs to impossible when disabled via shared memory.
(dll_list::update_forkables_needs): When detecting hardlink
creation as impossible (not on NTFS) while still (we are the
first one checking) enabled via shared memory, disable the
shared memory value.
* (dll_list::request_forkables): Disable the shared memory value
when hardlinks creation is disabled, that is when the cygfork
directory is (or became) absent.
---
 winsup/cygwin/forkable.cc  | 13 +
 winsup/cygwin/include/cygwin/version.h |  5 +++--
 winsup/cygwin/shared.cc|  1 +
 winsup/cygwin/shared_info.h|  3 ++-
 4 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/winsup/cygwin/forkable.cc b/winsup/cygwin/forkable.cc
index 0a8a528..83b5731 100644
--- a/winsup/cygwin/forkable.cc
+++ b/winsup/cygwin/forkable.cc
@@ -412,6 +412,11 @@ dll::create_forkable ()
 size_t
 dll_list::forkable_ntnamesize (dll_type type, PCWCHAR fullntname, PCWCHAR 
modname)
 {
+  /* per process, this is the first forkables-method ever called */
+  if (forkables_needs == forkables_unknown &&
+  !cygwin_shared->prefer_forkable_hardlinks)
+  forkables_needs = forkables_impossible; /* short cut */
+
   if (forkables_needs == forkables_impossible)
 return 0;
 
@@ -553,6 +558,7 @@ dll_list::update_forkables_needs ()
{
  debug_printf ("impossible, not on NTFS %W", fn.Buffer);
  forkables_needs = forkables_impossible;
+ cygwin_shared->prefer_forkable_hardlinks = 0;
}
 }
 
@@ -1048,6 +1054,13 @@ dll_list::request_forkables ()
 
   set_forkables_inheritance (true);
 
+  if (forkables_needs == forkables_disabled)
+{
+  /* we do not support (re-)enabling on the fly */
+  forkables_needs = forkables_impossible;
+  cygwin_shared->prefer_forkable_hardlinks = 0;
+}
+
   if (forkables_needs <= forkables_needless)
 return;
 
diff --git a/winsup/cygwin/include/cygwin/version.h 
b/winsup/cygwin/include/cygwin/version.h
index 8b1a8fc..7ac5899 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -503,9 +503,10 @@ details. */
shared mutexes, semaphores, etc.   The arbitrary starting
version was 0 (cygwin release 98r2).
Bump to 4 since this hasn't been rigorously updated in a
-   while.  */
+   while.
+   6. Add prefer_forkable_hardlinks (using /var/run/cygfork/). */
 
-#define CYGWIN_VERSION_SHARED_DATA 5
+#define CYGWIN_VERSION_SHARED_DATA 6
 
  /* An identifier used in the names used to create shared objects.
The full names include the CYGWIN_VERSION_SHARED_DATA version
diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc
index 202d8cc..2bc9c7a 100644
--- a/winsup/cygwin/shared.cc
+++ b/winsup/cygwin/shared.cc
@@ -331,6 +331,7 @@ shared_info::initialize ()
   init_obcaseinsensitive ();   /* Initialize obcaseinsensitive */
   tty.init (); /* Initialize tty table  */
   mt.initialize ();/* Initialize shared tape 
information */
+  prefer_forkable_hardlinks = 1;/* Yes */
   /* 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. */
diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h
index 90b386f..dd4cb3d 100644
--- a/winsup/cygwin/shared_info.h
+++ b/winsup/cygwin/shared_info.h
@@ -35,7 +35,7 @@ public:
 /* Data accessible to all tasks */
 
 
-#define CURR_SHARED_MAGIC 0x8fe4d9eeU
+#define CURR_SHARED_MAGIC 0xbc5d6a9cU
 
 #define USER_VERSION   1
 
@@ -51,6 +51,7 @@ class shared_info
   LONG last_used_bindresvport;
   DWORD obcaseinsensitive;
   mtinfo mt;
+  char prefer_forkable_hardlinks; /* single byte access always is atomic */
 
   void initialize ();
   void init_obcaseinsensitive ();
-- 
2.7.3



[PATCH 6/6] forkables: Document hardlink creation at forktime.

2016-03-30 Thread Michael Haubenwallner
* faq-api.xml: Mention hardlink creation by fork.
* highlights.xml: Describe hardlink creation.
---
 winsup/doc/faq-api.xml|  5 +
 winsup/doc/highlights.xml | 41 +
 2 files changed, 46 insertions(+)

diff --git a/winsup/doc/faq-api.xml b/winsup/doc/faq-api.xml
index 993274a..4c1f138 100644
--- a/winsup/doc/faq-api.xml
+++ b/winsup/doc/faq-api.xml
@@ -155,6 +155,11 @@ child, releases the mutex the child is waiting on and 
returns from the
 fork call.  Child wakes from blocking on mutex, recreates any mmapped
 areas passed to it via shared area and then returns from fork itself.
 
+When the executable or any dll in use by the parent was renamed
+or moved into the hidden recycle bin, fork tries to create hardlinks
+for the old executable and any dll into per-user subdirectories in the
+/var/run/cygfork/ directory, when that one exists and resides on NTFS.
+
 
 
 
diff --git a/winsup/doc/highlights.xml b/winsup/doc/highlights.xml
index 65407ab..c000f24 100644
--- a/winsup/doc/highlights.xml
+++ b/winsup/doc/highlights.xml
@@ -195,6 +195,47 @@ difficult to implement correctly.  Currently, the Cygwin 
fork is a
 non-copy-on-write implementation similar to what was present in early
 flavors of UNIX.
 
+As the child process is created as new process, both the main
+executable and all the dlls loaded either statically or dynamically have
+to be identical as to when the parent process has started or loaded a dll.
+While Windows does not allow to remove binaries in use from the file
+system, they still can be renamed or moved into the recycle bin, as
+outlined for unlink(2) in .
+To allow an existing process to fork, the original binary files need to be
+available via their original file names, but they may reside in
+different directories when using the https://social.msdn.microsoft.com/search/en-US?query=dotlocal%20dll%20redirection";
+>DotLocal (.local) Dll Redirection feature.
+Since NTFS does support hardlinks, we create a private directory
+containing hardlinks to the original files as well as the .local file.
+The private directory for the hardlinks is /var/run/cygfork/, which you
+have to create manually for now if you need to protect fork against exe-
+and dll- updates on your Cygwin instance.  As hardlinks cannot be used
+across multiple NTFS file systems, please make sure your exe- and dll-
+replacing operations operate on the same single NTFS file system as your
+Cygwin instance and the /var/run/cygfork/ directory.
+
+We create one directory per user, application and application age,
+and remove it when no more processes use that directory.  To indicate
+whether a directory still is in use, we define a mutex name similar to
+the directory name.  As mutexes are destroyed when no process holds a
+handle open any more, we can clean up even after power loss or similar:
+Both the parent and child process, at exit they lock the mutex with
+almost no timeout, and close it.
+If the lock succeeded before closing, directory cleanup is started:
+For each directory found, the corresponding mutex is created with lock.
+If that succeeds, the directory is removed, as it is unused now, and the
+corresponding mutex handle is closed.
+
+Before fork, when about to create hardlinks for the first time, the
+mutex is opened and locked with infinite timeout, to wait for the cleanup
+that may run at the same time.  Once locked, the mutex is unlocked
+immediately, but the mutex handle stays open until exit, and the hardlinks
+are created.  It is fine for multiple processes to concurrently create
+the same hardlinks, as the result really should be identical.  Once the
+mutex is open, we can create more hardlinks within this one directory
+without the need to lock the mutex again.
+
 The first thing that happens when a parent process
 forks a child process is that the parent initializes a space in the
 Cygwin process table for the child.  It then creates a suspended
-- 
2.7.3