Coverage Report

Created: 2023-09-25 06:56

/src/FreeRDP/winpr/libwinpr/thread/process.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Process Thread Functions
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2014 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
#include <winpr/config.h>
22
23
#include <winpr/handle.h>
24
#include "../handle/nonehandle.h"
25
26
#include <winpr/thread.h>
27
28
/**
29
 * CreateProcessA
30
 * CreateProcessW
31
 * CreateProcessAsUserA
32
 * CreateProcessAsUserW
33
 * ExitProcess
34
 * GetCurrentProcess
35
 * GetCurrentProcessId
36
 * GetExitCodeProcess
37
 * GetProcessHandleCount
38
 * GetProcessId
39
 * GetProcessIdOfThread
40
 * GetProcessMitigationPolicy
41
 * GetProcessTimes
42
 * GetProcessVersion
43
 * OpenProcess
44
 * OpenProcessToken
45
 * ProcessIdToSessionId
46
 * SetProcessAffinityUpdateMode
47
 * SetProcessMitigationPolicy
48
 * SetProcessShutdownParameters
49
 * TerminateProcess
50
 */
51
52
#ifndef _WIN32
53
54
#include <winpr/assert.h>
55
#include <winpr/crt.h>
56
#include <winpr/path.h>
57
#include <winpr/environment.h>
58
59
#include <grp.h>
60
61
#include <signal.h>
62
#include <sys/types.h>
63
#include <sys/wait.h>
64
65
#ifdef __linux__
66
#include <sys/syscall.h>
67
#include <fcntl.h>
68
#include <errno.h>
69
#endif /* __linux__ */
70
71
#include "thread.h"
72
73
#include "../security/security.h"
74
75
#ifndef NSIG
76
#ifdef SIGMAX
77
#define NSIG SIGMAX
78
#else
79
#define NSIG 64
80
#endif
81
#endif
82
83
/**
84
 * If the file name does not contain a directory path, the system searches for the executable file
85
 * in the following sequence:
86
 *
87
 * 1) The directory from which the application loaded.
88
 * 2) The current directory for the parent process.
89
 * 3) The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of
90
 * this directory. 4) The 16-bit Windows system directory. There is no function that obtains the
91
 * path of this directory, but it is searched. The name of this directory is System. 5) The Windows
92
 * directory. Use the GetWindowsDirectory function to get the path of this directory. 6) The
93
 * directories that are listed in the PATH environment variable. Note that this function does not
94
 * search the per-application path specified by the App Paths registry key. To include this
95
 * per-application path in the search sequence, use the ShellExecute function.
96
 */
97
98
static char* FindApplicationPath(char* application)
99
0
{
100
0
  LPCSTR pathName = "PATH";
101
0
  char* path;
102
0
  char* save;
103
0
  DWORD nSize;
104
0
  LPSTR lpSystemPath;
105
0
  char* filename = NULL;
106
107
0
  if (!application)
108
0
    return NULL;
109
110
0
  if (application[0] == '/')
111
0
    return _strdup(application);
112
113
0
  nSize = GetEnvironmentVariableA(pathName, NULL, 0);
114
115
0
  if (!nSize)
116
0
    return _strdup(application);
117
118
0
  lpSystemPath = (LPSTR)malloc(nSize);
119
120
0
  if (!lpSystemPath)
121
0
    return NULL;
122
123
0
  if (GetEnvironmentVariableA(pathName, lpSystemPath, nSize) != nSize - 1)
124
0
  {
125
0
    free(lpSystemPath);
126
0
    return NULL;
127
0
  }
128
129
0
  save = NULL;
130
0
  path = strtok_s(lpSystemPath, ":", &save);
131
132
0
  while (path)
133
0
  {
134
0
    filename = GetCombinedPath(path, application);
135
136
0
    if (winpr_PathFileExists(filename))
137
0
    {
138
0
      break;
139
0
    }
140
141
0
    free(filename);
142
0
    filename = NULL;
143
0
    path = strtok_s(NULL, ":", &save);
144
0
  }
145
146
0
  free(lpSystemPath);
147
0
  return filename;
148
0
}
149
150
static HANDLE CreateProcessHandle(pid_t pid);
151
static BOOL ProcessHandleCloseHandle(HANDLE handle);
152
153
static BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags, LPCSTR lpApplicationName,
154
                              LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
155
                              LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
156
                              DWORD dwCreationFlags, LPVOID lpEnvironment,
157
                              LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
158
                              LPPROCESS_INFORMATION lpProcessInformation)
159
0
{
160
0
  pid_t pid;
161
0
  int numArgs;
162
0
  LPSTR* pArgs = NULL;
163
0
  char** envp = NULL;
164
0
  char* filename = NULL;
165
0
  HANDLE thread;
166
0
  HANDLE process;
167
0
  WINPR_ACCESS_TOKEN* token;
168
0
  LPTCH lpszEnvironmentBlock;
169
0
  BOOL ret = FALSE;
170
0
  sigset_t oldSigMask;
171
0
  sigset_t newSigMask;
172
0
  BOOL restoreSigMask = FALSE;
173
0
  numArgs = 0;
174
0
  lpszEnvironmentBlock = NULL;
175
  /* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
176
   */
177
0
  if (lpCommandLine)
178
0
    pArgs = CommandLineToArgvA(lpCommandLine, &numArgs);
179
0
  else
180
0
    pArgs = CommandLineToArgvA(lpApplicationName, &numArgs);
181
182
0
  if (!pArgs)
183
0
    return FALSE;
184
185
0
  token = (WINPR_ACCESS_TOKEN*)hToken;
186
187
0
  if (lpEnvironment)
188
0
  {
189
0
    envp = EnvironmentBlockToEnvpA(lpEnvironment);
190
0
  }
191
0
  else
192
0
  {
193
0
    lpszEnvironmentBlock = GetEnvironmentStrings();
194
195
0
    if (!lpszEnvironmentBlock)
196
0
      goto finish;
197
198
0
    envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock);
199
0
  }
200
201
0
  if (!envp)
202
0
    goto finish;
203
204
0
  filename = FindApplicationPath(pArgs[0]);
205
206
0
  if (NULL == filename)
207
0
    goto finish;
208
209
  /* block all signals so that the child can safely reset the caller's handlers */
210
0
  sigfillset(&newSigMask);
211
0
  restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask);
212
  /* fork and exec */
213
0
  pid = fork();
214
215
0
  if (pid < 0)
216
0
  {
217
    /* fork failure */
218
0
    goto finish;
219
0
  }
220
221
0
  if (pid == 0)
222
0
  {
223
    /* child process */
224
0
#ifndef __sun
225
0
    int maxfd;
226
0
#endif
227
0
    int fd;
228
0
    int sig;
229
0
    sigset_t set = { 0 };
230
0
    struct sigaction act = { 0 };
231
    /* set default signal handlers */
232
0
    act.sa_handler = SIG_DFL;
233
0
    act.sa_flags = 0;
234
0
    sigemptyset(&act.sa_mask);
235
236
0
    for (sig = 1; sig < NSIG; sig++)
237
0
      sigaction(sig, &act, NULL);
238
239
    /* unblock all signals */
240
0
    sigfillset(&set);
241
0
    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
242
243
0
    if (lpStartupInfo)
244
0
    {
245
0
      int handle_fd;
246
0
      handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput);
247
248
0
      if (handle_fd != -1)
249
0
        dup2(handle_fd, STDOUT_FILENO);
250
251
0
      handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError);
252
253
0
      if (handle_fd != -1)
254
0
        dup2(handle_fd, STDERR_FILENO);
255
256
0
      handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput);
257
258
0
      if (handle_fd != -1)
259
0
        dup2(handle_fd, STDIN_FILENO);
260
0
    }
261
262
#ifdef __sun
263
    closefrom(3);
264
#else
265
#ifdef F_MAXFD // on some BSD derivates
266
    maxfd = fcntl(0, F_MAXFD);
267
#else
268
0
    maxfd = sysconf(_SC_OPEN_MAX);
269
0
#endif
270
271
0
    for (fd = 3; fd < maxfd; fd++)
272
0
      close(fd);
273
274
0
#endif // __sun
275
276
0
    if (token)
277
0
    {
278
0
      if (token->GroupId)
279
0
      {
280
0
        int rc = setgid((gid_t)token->GroupId);
281
282
0
        if (rc < 0)
283
0
        {
284
0
        }
285
0
        else
286
0
        {
287
0
          initgroups(token->Username, (gid_t)token->GroupId);
288
0
        }
289
0
      }
290
291
0
      if (token->UserId)
292
0
      {
293
0
        int rc = setuid((uid_t)token->UserId);
294
0
        if (rc != 0)
295
0
          goto finish;
296
0
      }
297
0
    }
298
299
    /* TODO: add better cwd handling and error checking */
300
0
    if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
301
0
    {
302
0
      int rc = chdir(lpCurrentDirectory);
303
0
      if (rc != 0)
304
0
        goto finish;
305
0
    }
306
307
0
    if (execve(filename, pArgs, envp) < 0)
308
0
    {
309
      /* execve failed - end the process */
310
0
      _exit(1);
311
0
    }
312
0
  }
313
0
  else
314
0
  {
315
    /* parent process */
316
0
  }
317
318
0
  process = CreateProcessHandle(pid);
319
320
0
  if (!process)
321
0
  {
322
0
    goto finish;
323
0
  }
324
325
0
  thread = CreateNoneHandle();
326
327
0
  if (!thread)
328
0
  {
329
0
    ProcessHandleCloseHandle(process);
330
0
    goto finish;
331
0
  }
332
333
0
  lpProcessInformation->hProcess = process;
334
0
  lpProcessInformation->hThread = thread;
335
0
  lpProcessInformation->dwProcessId = (DWORD)pid;
336
0
  lpProcessInformation->dwThreadId = (DWORD)pid;
337
0
  ret = TRUE;
338
0
finish:
339
340
  /* restore caller's original signal mask */
341
0
  if (restoreSigMask)
342
0
    pthread_sigmask(SIG_SETMASK, &oldSigMask, NULL);
343
344
0
  free(filename);
345
0
  free(pArgs);
346
347
0
  if (lpszEnvironmentBlock)
348
0
    FreeEnvironmentStrings(lpszEnvironmentBlock);
349
350
0
  if (envp)
351
0
  {
352
0
    int i = 0;
353
354
0
    while (envp[i])
355
0
    {
356
0
      free(envp[i]);
357
0
      i++;
358
0
    }
359
360
0
    free(envp);
361
0
  }
362
363
0
  return ret;
364
0
}
365
366
BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
367
                    LPSECURITY_ATTRIBUTES lpProcessAttributes,
368
                    LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
369
                    DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
370
                    LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
371
0
{
372
0
  return _CreateProcessExA(NULL, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
373
0
                           lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
374
0
                           lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
375
0
}
376
377
BOOL CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
378
                    LPSECURITY_ATTRIBUTES lpProcessAttributes,
379
                    LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
380
                    DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
381
                    LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
382
0
{
383
0
  return FALSE;
384
0
}
385
386
BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine,
387
                          LPSECURITY_ATTRIBUTES lpProcessAttributes,
388
                          LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
389
                          DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
390
                          LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
391
0
{
392
0
  return _CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
393
0
                           lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
394
0
                           lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
395
0
}
396
397
BOOL CreateProcessAsUserW(HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
398
                          LPSECURITY_ATTRIBUTES lpProcessAttributes,
399
                          LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
400
                          DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
401
                          LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
402
0
{
403
0
  return FALSE;
404
0
}
405
406
BOOL CreateProcessWithLogonA(LPCSTR lpUsername, LPCSTR lpDomain, LPCSTR lpPassword,
407
                             DWORD dwLogonFlags, LPCSTR lpApplicationName, LPSTR lpCommandLine,
408
                             DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
409
                             LPSTARTUPINFOA lpStartupInfo,
410
                             LPPROCESS_INFORMATION lpProcessInformation)
411
0
{
412
0
  return FALSE;
413
0
}
414
415
BOOL CreateProcessWithLogonW(LPCWSTR lpUsername, LPCWSTR lpDomain, LPCWSTR lpPassword,
416
                             DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
417
                             DWORD dwCreationFlags, LPVOID lpEnvironment,
418
                             LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
419
                             LPPROCESS_INFORMATION lpProcessInformation)
420
0
{
421
0
  return FALSE;
422
0
}
423
424
BOOL CreateProcessWithTokenA(HANDLE hToken, DWORD dwLogonFlags, LPCSTR lpApplicationName,
425
                             LPSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment,
426
                             LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
427
                             LPPROCESS_INFORMATION lpProcessInformation)
428
0
{
429
0
  return _CreateProcessExA(NULL, 0, lpApplicationName, lpCommandLine, NULL, NULL, FALSE,
430
0
                           dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
431
0
                           lpProcessInformation);
432
0
}
433
434
BOOL CreateProcessWithTokenW(HANDLE hToken, DWORD dwLogonFlags, LPCWSTR lpApplicationName,
435
                             LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment,
436
                             LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
437
                             LPPROCESS_INFORMATION lpProcessInformation)
438
0
{
439
0
  return FALSE;
440
0
}
441
442
VOID ExitProcess(UINT uExitCode)
443
0
{
444
0
  exit((int)uExitCode);
445
0
}
446
447
BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
448
0
{
449
0
  WINPR_PROCESS* process;
450
451
0
  if (!hProcess)
452
0
    return FALSE;
453
454
0
  if (!lpExitCode)
455
0
    return FALSE;
456
457
0
  process = (WINPR_PROCESS*)hProcess;
458
0
  *lpExitCode = process->dwExitCode;
459
0
  return TRUE;
460
0
}
461
462
HANDLE _GetCurrentProcess(VOID)
463
0
{
464
0
  return NULL;
465
0
}
466
467
DWORD GetCurrentProcessId(VOID)
468
0
{
469
0
  return ((DWORD)getpid());
470
0
}
471
472
BOOL TerminateProcess(HANDLE hProcess, UINT uExitCode)
473
0
{
474
0
  WINPR_PROCESS* process;
475
0
  process = (WINPR_PROCESS*)hProcess;
476
477
0
  if (!process || (process->pid <= 0))
478
0
    return FALSE;
479
480
0
  if (kill(process->pid, SIGTERM))
481
0
    return FALSE;
482
483
0
  return TRUE;
484
0
}
485
486
static BOOL ProcessHandleCloseHandle(HANDLE handle)
487
0
{
488
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
489
0
  WINPR_ASSERT(process);
490
0
  if (process->fd >= 0)
491
0
  {
492
0
    close(process->fd);
493
0
    process->fd = -1;
494
0
  }
495
0
  free(process);
496
0
  return TRUE;
497
0
}
498
499
static BOOL ProcessHandleIsHandle(HANDLE handle)
500
0
{
501
0
  return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);
502
0
}
503
504
static int ProcessGetFd(HANDLE handle)
505
0
{
506
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
507
508
0
  if (!ProcessHandleIsHandle(handle))
509
0
    return -1;
510
511
0
  return process->fd;
512
0
}
513
514
static DWORD ProcessCleanupHandle(HANDLE handle)
515
0
{
516
0
  WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
517
518
0
  WINPR_ASSERT(process);
519
0
  if (process->fd > 0)
520
0
  {
521
0
    if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)
522
0
      process->dwExitCode = (DWORD)process->status;
523
0
  }
524
0
  return WAIT_OBJECT_0;
525
0
}
526
527
static HANDLE_OPS ops = { ProcessHandleIsHandle,
528
                        ProcessHandleCloseHandle,
529
                        ProcessGetFd,
530
                        ProcessCleanupHandle, /* CleanupHandle */
531
                        NULL,
532
                        NULL,
533
                        NULL,
534
                        NULL,
535
                        NULL,
536
                        NULL,
537
                        NULL,
538
                        NULL,
539
                        NULL,
540
                        NULL,
541
                        NULL,
542
                        NULL,
543
                        NULL,
544
                        NULL,
545
                        NULL,
546
                        NULL,
547
                        NULL };
548
549
static int _pidfd_open(pid_t pid)
550
0
{
551
0
#ifdef __linux__
552
#if !defined(__NR_pidfd_open)
553
#define __NR_pidfd_open 434
554
#endif /* __NR_pidfd_open */
555
556
0
#ifndef PIDFD_NONBLOCK
557
0
#define PIDFD_NONBLOCK O_NONBLOCK
558
0
#endif /* PIDFD_NONBLOCK */
559
560
0
  int fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);
561
0
  if (fd < 0 && errno == EINVAL)
562
0
  {
563
    /* possibly PIDFD_NONBLOCK is not supported, let's try to create a pidfd and set it
564
     * non blocking afterward */
565
0
    int flags;
566
0
    fd = syscall(__NR_pidfd_open, pid, 0);
567
0
    if (fd < 0)
568
0
      return -1;
569
570
0
    flags = fcntl(fd, F_GETFL);
571
0
    if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
572
0
    {
573
0
      close(fd);
574
0
      fd = -1;
575
0
    }
576
0
  }
577
0
  return fd;
578
#else
579
  return -1;
580
#endif
581
0
}
582
583
HANDLE CreateProcessHandle(pid_t pid)
584
0
{
585
0
  WINPR_PROCESS* process;
586
0
  process = (WINPR_PROCESS*)calloc(1, sizeof(WINPR_PROCESS));
587
588
0
  if (!process)
589
0
    return NULL;
590
591
0
  process->pid = pid;
592
0
  process->common.Type = HANDLE_TYPE_PROCESS;
593
0
  process->common.ops = &ops;
594
0
  process->fd = _pidfd_open(pid);
595
0
  if (process->fd >= 0)
596
0
    process->common.Mode = WINPR_FD_READ;
597
0
  return (HANDLE)process;
598
0
}
599
600
#endif