This addresses an extremely difficult to debug deadlock when running
under emulation on ARM64.
A relatively easy way to trigger this bug is to call `fork()`, then within the
child process immediately call another `fork()` and then `exit()` the
intermediate process.
It would seem that there is a "code emulation" lock on the wait thread at
this stage, and if the thread is terminated too early, that lock still exists
albeit without a thread, and nothing moves forward.
It seems that a `SuspendThread()` combined with a `GetThreadContext()`
(to force the thread to _actually_ be suspended, for more details see
https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743)
makes sure the thread is "booted" from emulation before it is suspended.
Hopefully this means it won't be holding any locks or otherwise leave
emulation in a bad state when the thread is terminated.
Also, attempt to use `CancelSynchonousIo()` (as seen in `flock.cc`) to avoid
the need for `TerminateThread()` altogether. This doesn't always work,
however, so was not a complete fix for the deadlock issue.
Addresses: https://cygwin.com/pipermail/cygwin-developers/2024-May/012694.html
Signed-off-by: Jeremy Drake <cygwin@jdrake.com>
Fix warnings with gcc 12 about narrowing conversions of NTSTATUS
constants when used as case labels, e.g:
> ../../../../src/winsup/cygwin/exceptions.cc: In static member function ‘static int exception::handle(EXCEPTION_RECORD*, void*, CONTEXT*, PDISPATCHER_CONTEXT)’:
> ../../../../src/winsup/cygwin/exceptions.cc:670:10: error: narrowing conversion of ‘-1073741682’ from ‘NTSTATUS’ {aka ‘int’} to ‘unsigned int’ [-Wnarrowing]
See also: c5bdf60ac4
Signed-off-by: Jon Turney <jon.turney@dronecode.org.uk>
IsBadStringPtr is deprecated and just gives a wrong sense
of memory safety. Replace with check for NULL pointer.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This patch replaces ctty constants with more descriptive macros
(CTTY_UNINITIALIZED and CTTY_RELEASED) rather than -1 and -2 as
well as checking sign with CTTY_IS_VALID().
Fixes: 3b7df69aaa (Cygwin: ctty: Add comments for the special values: -1 and -2.)
Suggested-by: Corinna Vinschen <corinna@vinschen.de>
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
So far, the addresses printed for the shared regions of a process
were faked. The assumption was that the shared regions are always
in the same place in all processes, so we just printed the addresses
of the current process. This is no safe bet. The only safe bet is
the address of the cygheap. So keep track of the addresses in the
cygheap and read the addresses from the cygheap of the observed
processes. Add output for the shared console.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
For ages, open_shared uses the shared_locations parameter as
output to indicate if the mapping for a shared region has been
created or just opened. Split this into two parameters. Use
the shared_locations parameter as input only, return the creation
state of the mapping in a bool reference parameter.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
_pinfo::ctty has two special values other than the device id of
the allocated ctty:
-1: CTTY is not initialized yet. Can be associated with the TTY
which is associated with the session leader.
-2: CTTY has been released by setsid(). Can be associate only with
new TTY which is not associated with any other session as CTTY,
but cannot be associate with the TTYs already associated with
other sessions.
This patch adds the comments in some source files.
Suggested-by: Corinna Vinschen <corinna@vinschen.de>
Signedoff-by: Takashi Yano <takashi.yano@nifty.ne.jp>
The commit 25c4ad6ea5 did not fix the CTTY behavior enough. For
example, in the following test case, TTY will be associated as
a CTTY on the second open() call even though the TTY is already
CTTY of another session. This patch fixes the issue.
#include <unistd.h>
#include <sys/fcntl.h>
int main()
{
if (fork () == 0) {
char *tty = ttyname(0);
int fd;
setsid();
fd = open(tty, O_RDWR);
close(fd);
fd = open(tty, O_RDWR);
usleep (60000000L);
}
return 0;
}
Fixes: 25c4ad6ea5 ("Cygwin: pinfo: Align CTTY behavior to the
statement of POSIX.")
Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
The code generating the signal info in _pinfo::siginfo() and in
commune_process() are doing the same thing. Create a local static
function commune_process_siginfo() to have the code in one place
only. Remove a useless sigpending() call.
Fixes: 9a3c058f66 ("Cygwin: /proc/<PID>/status: Fill SigPnd, SigBlk and SigIgn values with life")
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
POSIX states "A terminal may be the controlling terminal for at most
one session."
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html
However, in cygwin, multiple sessions could be associated with the
same TTY. This patch aligns CTTY behavior to the statement of POSIX.
Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Back in early Cygwin development a function based access to the
environment was exported, the internal environ in Cygwin was called
__cygwin_environ and cur_environ() was used to access the environment
indirectly . The history of that necessity is not documented,
but kept in i686 for backward compatibility.
The x86_64 port eventually used __cygwin_environ directly and exported
it as DATA under the usual name environ.
We don't need the i686 workaround anymore, so just rename
__cygwin_environ to environ, drop the cur_environ() macro and
simply export environ under its own name.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
These have no effect on x86_64. Retain a few occurrences of __cdecl
in files imported from other sources.
Also retain all occurrences of WINAPI, even though the latter is
simply a macro that expands to __stdcall. Most of these occurrences
are associated with Windows API functions, and removing them might
make the code confusing instead of simpler.
killpg(pgid, 0) (or kill_pgrp(pgid, si_signo=0), in signal.cc)
fails (returns -1) even when there is a process in the process
group pgid, if the process is in the middle of spawnve(), see
https://cygwin.com/pipermail/cygwin/2022-May/251479.html
When exec'ing a process the assumption is that the exec'ed process creates its
own symlink (in pinfo::thisproc() in pinfo.cc). If the exec'ing process
calls NtClose on it's own winpid symlink, but the exec'ed process didn't
progress enough into initialization, there's a slim chance that neither
the exec'ing process, nor the exec'ed process has a winpid symlink
attached.
Always create the winpid symlink in spawn.cc, even for exec'ed Cygwin
processes. Make sure to dup the handle into the new process, and stop
creating the winpid symlink in exec'ed processes.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
So far the values of SigPnd and SigBlk were always 0 and SigIgn
was incorrectly set to the block mask of the current thread of
the calling process.
Fix that by adding a _pinfo::siginfo method and a PICOM_SIGINFO
message to allow to request actual signal info of any running process.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
- Previously, if non-cygwin app exits by Ctrl-C, exit code was
0x00007f00. With this patch, the exit code will be 0x00000002,
which means process exited by SIGINT.
Due to reports on the Cygwin mailing list[1][2], it was uncovered
that a NtOpenDirectoryObject/NtQueryDirectoryObject/NtClose sequence
with NtQueryDirectoryObject iterating over the directory entries,
one entry per invocation, is not running atomically. If new entries
are inserted into the queried directory, other entries may be moved
around and then accidentally show up twice while iterating.
Change (almost) all NtQueryDirectoryObject invocations so that it gets
a really big buffer (64K) and ideally fetches all entries at once.
This appears to work atomically.
"Almost" all, because fhandler_procsys::readdir can't be easily changed.
[1] https://cygwin.com/pipermail/cygwin/2021-July/248998.html
[2] https://cygwin.com/pipermail/cygwin/2021-August/249124.html
Fixes: e9c8cb3193 ("(format_proc_partitions): Revamp loop over existing harddisks by scanning the NT native \Device object directory and looking for Harddisk entries.")
Fixes: a998dd7055 ("Implement advisory file locking.")
Fixes: 3b7cd74bfd ("(winpids::enum_processes): Fetch Cygwin processes from listing of shared cygwin object dir in the native NT namespace.")
Fixes: 0d6f2b0117 ("syscalls.cc (sync_worker): Rewrite using native NT functions.")
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This option has been disabled long ago and nobody missed it.
Removing drops a bit of unneeded code
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Commit 5a0f2c00aa "Cygwin: fork/exec: fix child process permissions"
removed the PROCESS_DUP_HANDLE handle permission of the parent process
handle in the child to avoid a security problem.
It turned out that this broke the following scenario: If a process forks
and then the parent execs, the child loses the ability to register the
parent's death. To wit, after the parent died the child process does
not set its own PPID to 1 anymore.
The current exec mechanism copies required handle values (handles to
keep contact to the child processes) into the child_info for the
about-to-be-exec'ed process. The exec'ed process is supposed to
duplicate these handles. This fails, given that we don't allow the
exec'ed process PROCESS_DUP_HANDLE access to the exec'ing process since
commit 5a0f2c00aa.
The fix is to avoid the DuplicateHandle calls in the exec'ed process.
This patch sets the affected handles to "inheritable" in the exec'ing
process at exec time. The exec'ed process just copies the handle values
and resets handle inheritance to "non-inheritable". The exec'ing
process doesn't have to reset handle inheritance, it exits after setting
up the exec'ed process anyway.
Testcase: $ ssh-agent /bin/sleep 3
ssh-agent forks and the parent exec's sleep. After sleep exits, `ps'
should show ssh-agent to have PPID 1, and eventually ssh-agent exits.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Introducing an independent Cygwin PID introduced a regression:
The expectation is that the myself pinfo pointer always points to a
specific address right in front of the loaded Cygwin DLL.
However, the independent Cygwin PID changes broke this. To create
myself at the right address requires to call init with h0 set to
INVALID_HANDLE_VALUE or an existing address:
void
pinfo::init (pid_t n, DWORD flag, HANDLE h0)
{
[...]
if (!h0 || myself.h)
[...]
else
{
shloc = SH_MYSELF;
if (h0 == INVALID_HANDLE_VALUE) <-- !!!
h0 = NULL;
}
The aforementioned commits changed that so h0 was always NULL, this way
creating myself at an arbitrary address.
This patch makes sure to set the handle to INVALID_HANDLE_VALUE again
when creating a new process, so init knows that myself has to be created
in the right spot. While at it, fix a potential uninitialized handle
value in child_info_spawn::handle_spawn.
Fixes: b5e1003722 ("Cygwin: processes: use dedicated Cygwin PID rather than Windows PID")
Fixes: 88605243a1 ("Cygwin: fix child getting another pid after spawnve")
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
_pinfo::set_ctty sets myself's pgid to the ctty pgid if the process has
been started from a non-Cygwin process. This isn't the right thing to
do when started from GDB. GDB starts the application via standard
Windows means, not via Cygwin fork/exec, so it's treated as being
a non-Cygwin parent.
But we want the app running in it's own process group. So skip this
step when running under a debugger
Signed-off-by: Corinna Vinschen <corinna-cygwin@cygwin.com>
commit d1be0a59d4,
"Cygwin: winpids: Fix getting process multiple times"
fixed duplicate processes in ps -W output, but it fixed
the symptom, not the cause. It also didn't fix the problem
that the `ps' process itself may show up twice in its own
output.
This patch fixes it. The spawn worker only deleted the
"winpid.PID" symlink of the current process if the child is
a non-Cygwin process, under the assumption that the exec'ing
process exits anyway. However, the Window in which both
winpid.PID symlinks point to the same cygpid.PID area is just
too long. The spawn worker now also deletes its own winpid.PID
symlink if the exec'ed process is a Cygwin process.
Additionally the fix from d1be0a59d4
is now performed on the calling process, too.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Switching to Cywin-only PIDs introduced a new problem when collecting
Cygwin processes for `ps -W': A process can show up multiple times
again, if the Cygwin procinfo has been opened for a just execing
process. The execed process then shows up twice, once as Cygwin
process, but with the wrong Windows PID of the execing process,
once as Windows-only process.
The mechanism used to exclude these stray processes didn't work with
the new Cygwin pid handling anymore. To fix this
* check if the incoming Windows PID is the same as the PID in the
procinfo. If not, we have the PID of the execing process while
procinfo was already changed,
* always check if the process has already been handled, not only
for processes we got a procinfo for,
* simplify adding pid to pidlist since pid is now always correct.
While at it, fix comments and comment formatting.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
The winpid symlinks got created with no query permissions, so
only admins could see all Cygwin processes. Create symlinks
so everyone has query permissions instead.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Revert "Cywin: user profile: unload impersonation user profile on exit"
Revert "Cygwin: seteuid: allow inheriting impersonation user profile handle"
Revert "Cygwin: user profile: add debug output to unload_user_profile"
Revert "Cygwin: user profile: Make an effort to unload unused user profiles"
This reverts commit bcb33dc4f0.
This reverts commit dd3730ed9c.
This reverts commit 8eee25241e.
This reverts commit 71b8777a71.
This patchset actually results in the following problem:
- After a couple of ssh logon/logoff attempts, an interactive session
of the same user loging in, is broken.
Apparently UnloadUserProfile manages to unload the user's profile
even while a parallel interactive session still uses the user's
profile.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
When calling spawnve, in contrast to execve, the parent has
to create the pid for the child. With the old technique
this was simply the Windows pid, but now we have to inform
the child about its new pid.
Add a cygpid member to class child_info_spawn. Set it in
child_info_spawn::worker, just prior to calling CreateProcess
rather than afterwards. Overwrite cygheap->pid in
child_info_spawn::handle_spawn before calling pinfo::thisproc.
Make sure pinfo::thisproc knows the pid is already set by
setting the handle argument to INVALID_HANDLE_VALUE.
Also set procinfo->dwProcessId to myself_initial.dwProcessId
instead of to myself_initial.pid for clarity.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
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.
* Makefile.in (DLL_OFILES): Add forkable.o.
* dll_init.h (struct dll): Declare member variables fbi, fii,
forkable_ntname. Declare methods nominate_forkable,
create_forkable.
(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,
set_forkables_inheritance, request_forkables. Declare public
static methods ntopenfile, read_fii, read_fbi. Declare public
methods release_forkables, cleanup_forkables. Define public
inline method setup_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.
(dll_list::load_after_fork): Call release_forkables method.
* fork.cc: Rename public fork function to static dofork, add
with_forkables as bool pointer parameter. Add new fork function
calling dofork. (struct frok): Add bool pointer member
with_forkables, add as constructor parameter.
(frok::parent): Call dlls.setup_forkables before CreateProcessW,
dlls.release_forkables afterwards.
* 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.
* forkable.cc: New file.
Implement static functions mkdirs, rmdirs, rmdirs_synchronized,
stat_real_file_once, format_IndexNumber, rootname, sidname,
exename, lwtimename. Define static array forkable_nameparts.
(struct dll): Implement nominate_forkable, create_forkable.
(struct dll_list): Implement static methods ntopenfile,
read_fii, read_fbi. Implement forkable_ntnamesize,
The arguments are not used anyway, so drop them. When called,
procinfo->dwProcessId is already set right, so we don't have
to access myself_initial.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Since commit b5e1003722, native
Windows processes not started by Cygwin processes don't have a
Cygwin PID anymore. This breaks ps -W and kill -f <WINPID>.
Introduce MAX_PID (65536 for now).
Cygwin processes as well as native Windows processes started
from a Cygwin process get a PID < MAX_PID. All other native
Windows processes get a faked Cygwin PID >= MAX_PID.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Using the Windows PID as Cygwin PID has a few drawbacks:
- the PIDs on Windows get reused quickly. Some POSIX applications choke
on that, so we need extra code to avoid too quick PID reuse.
- The code to avoid PID reuse keeps parent process handles and
(depending on a build option) child processes open unnecessarily.
- After an execve, the process has a split personality: Its Windows PID
is a new PID, while its Cygwin PID is the PID of the execve caller
process. This requires to keep two procinfo shared sections open, the
second just to redirect process info requests to the first, correct
one.
This patch changes the way Cygwin PIDs are generated:
- Cygwin PIDs are generated independently of the Windows PID, in a way
expected by POSIX processes. The PIDs are created incrementally in
the range between 2 and 65535, round-robin.
- On startup of the first Cygwin process, choose a semi-random start PID
for the first process in the lower PID range to make the PIDs slightly
unpredictable. This may not be necessary but it seems kind of inviting
to know that the first Cygwin process always starts with PID 2.
- Every process not only creates the shared procinfo section, but also a
symlink in the NT namespace, symlinking the Windows PID to the Cygwin
PID. This drops the need for the extra procinfo section after execve.
- Don't keep other process handles around unnecessarily.
- Simplify the code creating/opening the shared procinfo section and
make a clear distinction between interfaces getting a Cygwin PID and
interfaces getting a Windows PID.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
The new proc fd code accidentally allowed to linkat an O_TMPFILE
even if the file has been opened with O_EXCL. This patch fixes it.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
To allow reopening a file open in another process by HANDLE, introduce
a matching file_pathconv method, taking a file descriptor as parameter.
The result is a serialized path_conv and a HANDLE value. The HANDLE is
valid in the foreign process and MUST be duplicated into the target
process before usage.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>