WSL/test/linux/unit_tests/get_set_id.c
WSL Team 697572d664 Initial open source commit for WSL.
Many Microsoft employees have contributed to the Windows Subsystem for Linux, this commit is the result of their work since 2016.

The entire history of the Windows Subsystem for Linux can't be shared here, but here's an overview of WSL's history after it moved to it own repository in 2021:

Number of commits on the main branch: 2930
Number of contributors: 31

Head over https://github.com/microsoft/WSL/releases for a more detailed history of the features added to WSL since 2021.
2025-05-15 12:09:45 -07:00

1161 lines
27 KiB
C

/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
get_set_id.c
Abstract:
This file is a test for the get*id and set*id system calls.
--*/
#include "lxtcommon.h"
#include "unittests.h"
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <limits.h>
#define LXT_NAME "get_set_id"
#if !defined(__amd64__) && !defined(__aarch64__)
#define __NR_getuid16 24
#define __NR_geteuid16 49
#define __NR_getgid16 47
#define __NR_getegid16 50
#define __NR_getresuid16 165
#define __NR_getresgid16 171
int GetSetId16Bit(PLXT_ARGS Args);
#endif
typedef unsigned short USHORT;
//
// uid16_t and gid16_t are unsigned 16-bit integers.
//
typedef USHORT uid16_t;
#define MAX_UID16_T USHRT_MAX
typedef USHORT gid16_t;
#define MAX_GID16_T USHRT_MAX
int GetSetId0(PLXT_ARGS Args);
int GetSetId1(PLXT_ARGS Args);
int GetSetIdParseArgs(int Argc, char* Argv[], LXT_ARGS* Args);
int GetSetPgid(PLXT_ARGS Args);
int GetSetPgidChildProcess(void);
int GetSetPgidChildProcess2(pid_t GroupId);
int GetSetPgidExecve(PLXT_ARGS Args);
int GetSetPgidExecveChild(void);
int GetSetSid(PLXT_ARGS Args);
//
// Global constants
//
static const LXT_VARIATION g_LxtVariations[] = {
{"GetSetId Basic", GetSetId0},
{"GetResuid-GetResgid Basic", GetSetId1},
#if !defined(__amd64__) && !defined(__aarch64__)
{"GetSetId 16-bit versions", GetSetId16Bit},
#endif
{"GetSetPgid Basic", GetSetPgid},
{"GetSetPgid with execve", GetSetPgidExecve},
{"GetSetSid Basic", GetSetSid}};
static const char* g_SocketPath = "/data/test/lxt_get_set_id_sock";
int GetSetIdTestEntry(int Argc, char* Argv[])
/*++
Routine Description:
This routine main entry point for the test for get*id,set*id system call.
Arguments:
Argc - Supplies the number of command line arguments.
Argv - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
LXT_ARGS Args;
int Result;
LxtCheckResult(GetSetIdParseArgs(Argc, Argv, &Args));
ErrorExit:
LxtUninitialize();
return !LXT_SUCCESS(Result);
}
int GetSetId0(PLXT_ARGS Args)
/*++
Routine Description:
This routine validates the various get*id and set*id system
calls.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
gid_t Egid;
gid_t EgidFromGetResgid;
uid_t Euid;
uid_t EuidFromGetResuid;
gid_t Gid;
gid_t GidFromGetResgid;
pid_t Pgid;
pid_t Pgid0;
pid_t Pid;
pid_t Ppid;
int Result;
uid_t SuidFromGetResuid;
gid_t SgidFromGetResgid;
pid_t Tid;
uid_t Uid;
uid_t UidFromGetResuid;
Pid = getpid();
Ppid = getppid();
Gid = getgid();
Egid = getegid();
Uid = getuid();
Euid = geteuid();
Tid = gettid();
LxtCheckResult((Pgid0 = getpgid(0)));
LxtCheckResult((Pgid = getpgid(Pid)));
LxtCheckErrnoFailure(getpgid(-1), ESRCH);
LxtCheckResult(getresuid(&UidFromGetResuid, &EuidFromGetResuid, &SuidFromGetResuid));
LxtCheckResult(getresgid(&GidFromGetResgid, &EgidFromGetResgid, &SgidFromGetResgid));
LxtLogInfo(
"ID Details. Pid:%d, Ppid:%d, Gid:%u, Egid:%u, Uid:%u, "
"Euid:%u, Tid:%u, Pgid:%d, Uid From GetResuid:%u, "
"Euid From GetResuid:%u, Suid From GetResuid:%u, Gid From "
"GetResgid:%u, Egid From GetResgid:%u, Sgid From GetResgid:%u",
Pid,
Ppid,
Gid,
Egid,
Uid,
Euid,
Tid,
Pgid,
UidFromGetResuid,
EuidFromGetResuid,
SuidFromGetResuid,
GidFromGetResgid,
EgidFromGetResgid,
SgidFromGetResgid);
//
// getpgid(Pid) == getpgid(0)
//
if (Pgid != Pgid0)
{
LxtLogError(
"getpgid(<self>) == getpgid(0). getpgid(<self>):%d, "
"getpgid(0): %d",
Pgid,
Pgid0);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
//
// For a signle threaded process, Thread ID == Process ID
//
if (Pid != Tid)
{
LxtLogError(
"For a single threaded process, Process ID == Thread ID. "
"Process ID:%u, Thread ID:%u",
Pid,
Tid);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
//
// ID's from get*id and getresuid/getresgid should match
//
if (Uid != UidFromGetResuid)
{
LxtLogError(
"UID from getuid and getresuid do not match. "
"uid from getuid:%u, uid from getresuid:%u",
Uid,
UidFromGetResuid);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
if (Euid != EuidFromGetResuid)
{
LxtLogError(
"EUID from geteuid and getresuid do not match. "
"euid from getuid:%u, euid from getresuid:%u",
Euid,
EuidFromGetResuid);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
if (Gid != GidFromGetResgid)
{
LxtLogError(
"GID from getgid and getresgid do not match. "
"gid from getgid:%u, gid from getresgid:%u",
Gid,
GidFromGetResgid);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
if ((Egid != EgidFromGetResgid))
{
LxtLogError(
"EGID from getegid and getresgid do not match. "
"egid from getegid:%u, egid from getresgid:%u",
Egid,
EgidFromGetResgid);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
Result = LXT_RESULT_SUCCESS;
ErrorExit:
return Result;
}
int GetSetId1(PLXT_ARGS Args)
/*++
Routine Description:
This routine validates the GetResuid/GetResgid system calls.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
gid_t EgidFromGetResgid;
uid_t EuidFromGetResuid;
gid_t GidFromGetResgid;
int Result;
uid_t SuidFromGetResuid;
gid_t SgidFromGetResgid;
uid_t UidFromGetResuid;
LxtCheckErrnoFailure(getresuid(NULL, NULL, NULL), EFAULT);
LxtCheckErrnoFailure(getresuid(&UidFromGetResuid, NULL, NULL), EFAULT);
LxtCheckErrnoFailure(getresuid(NULL, &EuidFromGetResuid, &SuidFromGetResuid), EFAULT);
LxtCheckResult(getresuid(&UidFromGetResuid, &EuidFromGetResuid, &SuidFromGetResuid));
LxtCheckErrnoFailure(getresgid(NULL, NULL, NULL), EFAULT);
LxtCheckErrnoFailure(getresgid(&GidFromGetResgid, NULL, NULL), EFAULT);
LxtCheckErrnoFailure(getresgid(NULL, &EgidFromGetResgid, &SgidFromGetResgid), EFAULT);
LxtCheckResult(getresgid(&GidFromGetResgid, &EgidFromGetResgid, &SgidFromGetResgid));
Result = LXT_RESULT_SUCCESS;
ErrorExit:
return Result;
}
#if !defined(__amd64__) && !defined(__aarch64__)
int GetSetId16Bit(PLXT_ARGS Args)
/*++
Routine Description:
This routine validates the various 16-bit versions of the
get*id and set*id system calls.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
gid_t Egid;
gid16_t Egid16;
gid16_t EgidFromGetResgid16;
uid_t Euid;
uid16_t Euid16;
uid16_t EuidFromGetResuid16;
gid_t Gid;
gid16_t Gid16;
gid16_t GidFromGetResgid16;
int Result;
uid16_t SuidFromGetResuid16;
gid16_t SgidFromGetResgid16;
uid_t Uid;
uid16_t Uid16;
uid16_t UidFromGetResuid16;
Gid = getgid();
Gid16 = 0;
Egid = getegid();
Uid = getuid();
Uid16 = 0;
Euid = geteuid();
LxtLogInfo("UID and GID Details. Gid:%d, Egid:%d, Uid:%u, Euid:%u", Gid, Egid, Uid, Euid);
//
// Before calling the 16-bit versions, make sure the IDs are
// within the range.
//
if (Gid <= MAX_GID16_T)
{
Gid16 = syscall(__NR_getgid16);
if (Gid != Gid16)
{
LxtLogError(
"GID from getgid and getgid16 do not match. "
"gid from getgid:%d, gid from getgid16:%d",
Gid,
Gid16);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
}
if (Egid <= MAX_GID16_T)
{
Egid16 = syscall(__NR_getegid16);
if (Egid != Egid16)
{
LxtLogError(
"EGID from getegid and getegid16 do not match. "
"egid from getegid:%d, egid from getegid16:%d",
Egid,
Egid16);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
}
if ((Gid <= MAX_GID16_T) && (Egid <= MAX_GID16_T))
{
LxtCheckResult(syscall(__NR_getresgid16, &GidFromGetResgid16, &EgidFromGetResgid16, &SgidFromGetResgid16));
LxtLogInfo("SGID16:%d", SgidFromGetResgid16);
if (Gid16 != GidFromGetResgid16)
{
LxtLogError(
"GID from getgid16 and getresgid16 do not match. "
"gid from getgid16:%d, gid from getresgid16:%d",
Gid16,
GidFromGetResgid16);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
if ((Egid16 != EgidFromGetResgid16))
{
LxtLogError(
"EGID from getegid16 and getresgid16 do not match. "
"egid from getegid16:%d, egid from getresgid16:%d",
Egid16,
EgidFromGetResgid16);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
LxtCheckErrnoFailure(syscall(__NR_getresgid16, NULL, NULL, NULL), EFAULT);
LxtCheckErrnoFailure(syscall(__NR_getresgid16, &GidFromGetResgid16, NULL, NULL), EFAULT);
LxtCheckErrnoFailure(syscall(__NR_getresgid16, NULL, &EgidFromGetResgid16, &SgidFromGetResgid16), EFAULT);
}
if (Uid <= MAX_UID16_T)
{
Uid16 = syscall(__NR_getuid16);
if (Uid != Uid16)
{
LxtLogError(
"UID from getuid and getuid16 do not match. "
"uid from getuid:%d, uid from getuid16:%d",
Uid,
Uid16);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
}
if (Euid <= MAX_UID16_T)
{
Euid16 = syscall(__NR_geteuid16);
if (Euid != Euid16)
{
LxtLogError(
"EUID from geteuid and geteuid16 do not match. "
"egid from geteuid:%d, egid from geteuid16:%d",
Euid,
Euid16);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
}
if ((Uid <= MAX_UID16_T) && (Euid <= MAX_UID16_T))
{
LxtCheckResult(syscall(__NR_getresuid16, &UidFromGetResuid16, &EuidFromGetResuid16, &SuidFromGetResuid16));
LxtLogInfo("SUID16:%d", SuidFromGetResuid16);
if (Uid16 != UidFromGetResuid16)
{
LxtLogError(
"UID from getuid16 and getresuid16 do not match. "
"uid from getuid16:%d, uid from getresuid16:%d",
Uid16,
UidFromGetResuid16);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
if (Euid16 != EuidFromGetResuid16)
{
LxtLogError(
"EUID from geteuid16 and getresuid16 do not match. "
"euid from getuid16:%d, euid from getresuid16:%d",
Euid16,
EuidFromGetResuid16);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
LxtCheckErrnoFailure(syscall(__NR_getresuid16, NULL, NULL, NULL), EFAULT);
LxtCheckErrnoFailure(syscall(__NR_getresuid16, &UidFromGetResuid16, NULL, NULL), EFAULT);
LxtCheckErrnoFailure(syscall(__NR_getresuid16, NULL, &EuidFromGetResuid16, &SuidFromGetResuid16), EFAULT);
}
Result = LXT_RESULT_SUCCESS;
ErrorExit:
return Result;
}
#endif
int GetSetIdParseArgs(int Argc, char* Argv[], LXT_ARGS* Args)
/*++
Routine Description:
This routine parses command line arguments for the get_set_id tests.
Arguments:
Argc - Supplies the number of arguments.
Argv - Supplies an array of arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int ArgvIndex;
int Result;
int ValidArguments;
Result = LXT_RESULT_FAILURE;
ValidArguments = 0;
if (Argc < 1)
{
goto ErrorExit;
}
for (ArgvIndex = 1; ArgvIndex < Argc; ++ArgvIndex)
{
if (Argv[ArgvIndex][0] != '-')
{
printf("Unexpected character %s", Argv[ArgvIndex]);
goto ErrorExit;
}
switch (Argv[ArgvIndex][1])
{
case 'c':
//
// Run the setpgid execve test child
//
ValidArguments = 1;
Result = GetSetPgidExecveChild();
goto ErrorExit;
case 'v':
//
// This was already taken care of by LxtInitialize.
//
++ArgvIndex;
break;
default:
goto ErrorExit;
}
}
//
// If -c was not specified, just run the tests
//
ValidArguments = 1;
LxtCheckResult(LxtInitialize(Argc, Argv, Args, LXT_NAME));
LxtCheckResult(LxtRunVariations(Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
ErrorExit:
if (ValidArguments == 0)
{
printf("\nuse: get_set_id <One of the below arguments>");
printf("\t-c : Run getsetpgid execve test child (don't use directly)");
}
return Result;
}
int GetSetPgid(PLXT_ARGS Args)
/*++
Routine Description:
This routine validates the getpgid and setpgid system calls.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
const int Processes = 2;
pid_t Child;
pid_t GroupId;
pid_t NewGroup;
int Process;
pid_t ProcessIds[2];
int Result;
int Status;
//
// Check that a child process initially inherits our process group ID.
//
LxtCheckErrno(Child = fork());
if (Child == 0)
{
_exit(GetSetPgidChildProcess());
}
LxtCheckResult(LxtWaitPidPoll(Child, 0));
//
// Create two processes; the first will be the group leader and the second
// will use the group id of the first. The method used here reflects how
// job control shells create groups for pipelines.
//
GroupId = 0;
for (Process = 0; Process < Processes; Process += 1)
{
LxtCheckErrno(Child = fork());
ProcessIds[Process] = Child;
if (Child == 0)
{
_exit(GetSetPgidChildProcess2(GroupId));
}
if (GroupId == 0)
{
GroupId = Child;
}
LxtCheckErrnoZeroSuccess(setpgid(Child, GroupId));
LxtCheckErrno(NewGroup = getpgid(Child));
if (NewGroup != GroupId)
{
LxtLogError(
"getpgid() return value does not match the "
"value set by setpgid. Expected: %i; actual: %i",
GroupId,
NewGroup);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
}
for (Process = 0; Process < Processes; Process += 1)
{
LxtCheckResult(LxtWaitPidPoll(ProcessIds[Process], 0));
}
//
// After the child processes were waited on, the process group is no longer
// valid, nor are the children pids. There is currently a race condition
// that causes waitpid to return before the process group is cleaned up
// so sleep before trying this.
//
sleep(1);
LxtCheckErrnoFailure(setpgid(0, GroupId), EPERM);
LxtCheckErrnoFailure(setpgid(ProcessIds[0], 0), ESRCH);
LxtCheckErrnoFailure(getpgid(ProcessIds[0]), ESRCH);
//
// Getpgid for non-child process should succeed, setpgid should fail
//
LxtCheckErrno(getpgid(getppid()));
LxtCheckErrnoFailure(setpgid(getppid(), 0), ESRCH);
//
// Cannot change process group of session leader.
//
LxtCheckResult(LxtSignalBlock(SIGUSR1));
LxtCheckErrno(Child = fork());
if (Child == 0)
{
LxtCheckErrno(setsid());
LxtCheckErrnoFailure(setpgid(0, getppid()), EPERM);
LxtCheckErrnoFailure(setpgid(0, 0), EPERM);
LxtCheckErrnoZeroSuccess(kill(getppid(), SIGUSR1));
LxtCheckResult(LxtSignalWaitBlocked(SIGUSR1, getppid(), 2));
_exit(LXT_RESULT_SUCCESS);
}
LxtCheckResult(LxtSignalWaitBlocked(SIGUSR1, Child, 2));
LxtCheckErrnoFailure(setpgid(Child, 0), EPERM);
LxtCheckErrnoFailure(setpgid(Child, getpgid(0)), EPERM);
//
// Cannot change to process group which is in a different session.
//
LxtCheckErrnoFailure(setpgid(0, Child), EPERM);
//
// Tell the child to exit.
//
LxtCheckErrnoZeroSuccess(kill(Child, SIGUSR1));
LxtCheckResult(LxtWaitPidPoll(Child, 0));
//
// Bogus pid and pgid values. The fact that setpgid returns different
// errors for a negative pid if pgid==0 is consistent with Linux.
//
LxtCheckErrnoFailure(getpgid(-1), ESRCH);
LxtCheckErrnoFailure(setpgid(-1, 1), ESRCH);
LxtCheckErrnoFailure(setpgid(-1, 0), EINVAL);
LxtCheckErrnoFailure(setpgid(0, -1), EINVAL);
ErrorExit:
return Result;
}
int GetSetPgidChildProcess(void)
/*++
Routine Description:
This routine runs the child process for GetSetPgid that checks its pgid.
Arguments:
None.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t Parent;
pid_t ParentGroupId;
pid_t GroupId;
int Result;
Parent = getppid();
LxtCheckErrno(ParentGroupId = getpgid(Parent));
LxtCheckErrno(GroupId = getpgid(0));
LxtLogInfo("Process %i pgid: %i, parent %i pgid: %i", getpid(), GroupId, Parent, ParentGroupId);
Result = LXT_RESULT_FAILURE;
if (GroupId == 0)
{
LxtLogError("Group ID should never be zero.");
goto ErrorExit;
}
if (GroupId != ParentGroupId)
{
LxtLogError("Pgid %i did not match parent pgid %i", GroupId, ParentGroupId);
goto ErrorExit;
}
Result = LXT_RESULT_SUCCESS;
ErrorExit:
return Result;
}
int GetSetPgidChildProcess2(pid_t GroupId)
/*++
Routine Description:
This routine runs the child processes for GetSetPgid that set their pgid.
Arguments:
GroupId - The process group ID for this child process (0 if this is the
new leader)
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int NewGroup;
int Pid;
int Result;
LxtCheckErrnoZeroSuccess(setpgid(0, GroupId));
//
// If we were passed 0, the expected result should match the process ID.
//
Pid = getpid();
if (GroupId == 0)
{
GroupId = Pid;
}
LxtCheckErrno(NewGroup = getpgid(0));
if (NewGroup != GroupId)
{
LxtLogError(
"getpgid(0) return value does not match the value set by "
"setpgid. Expected: %i; actual: %i",
GroupId,
NewGroup);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
LxtLogInfo("Process %i pgid: %i", Pid, NewGroup);
LxtCheckErrno(NewGroup = getpgid(Pid));
if (NewGroup != GroupId)
{
LxtLogError(
"getpgid(getpid()) return value does not match the value "
"set by setpgid. Expected: %i; actual: %i",
GroupId,
NewGroup);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
//
// The sleep is to keep the group alive until the second process
// runs. Remove it once zombie processes are implemented.
//
sleep(1);
Result = LXT_RESULT_SUCCESS;
ErrorExit:
return Result;
}
int GetSetPgidExecve(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks whether setpgid returns the correct failure if it is
called on a process that has already called execve.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
struct sockaddr_un Address;
int ClientSocket;
char* Argv[4];
char* Envp[1];
int Result;
int ServerSocket;
int Status;
int Child;
ClientSocket = -1;
Child = -1;
//
// To make sure we call setpgid after the child process runs execve and
// before it exits, we use a unix socket to let the child signal us when
// it's running, and then we signal the child to exit after the test.
//
LxtCheckErrno(ServerSocket = socket(AF_UNIX, SOCK_STREAM, 0));
//
// Remove the path name in case it exists from a failed prior test run;
// ignore errors.
//
unlink(g_SocketPath);
//
// Bind to the address and start listening
//
memset(&Address, 0, sizeof(Address));
Address.sun_family = AF_UNIX;
strncpy(Address.sun_path, g_SocketPath, sizeof(Address.sun_path) - 1);
Address.sun_path[sizeof(Address.sun_path) - 1] = 0;
LxtCheckErrnoZeroSuccess(bind(ServerSocket, (struct sockaddr*)&Address, sizeof(Address)));
LxtCheckErrnoZeroSuccess(listen(ServerSocket, 1));
//
// Start the child process.
//
LxtCheckErrno(Child = fork());
if (Child == 0)
{
Argv[0] = WSL_UNIT_TEST_BINARY; // adhere to new single test binary design
Argv[1] = Args->Argv[0];
Argv[2] = "-c";
Argv[3] = Envp[0] = NULL;
execve(Argv[0], Argv, Envp);
LxtLogError("Execve failed, errno: %d (%s)", errno, strerror(errno));
_exit(LXT_RESULT_FAILURE);
}
//
// Wait for the client to tell us it's running; this guarantees we
// call setpgid after the execve call.
//
LxtCheckErrno(ClientSocket = accept(ServerSocket, NULL, NULL));
LxtCheckResult(LxtReceiveMessage(ClientSocket, "execve"));
//
// The child is now running inside the binary loaded by execve, so we
// can try to call setpgid, which should fail with EACCES.
//
LxtCheckErrnoFailure(setpgid(Child, 0), EACCES);
//
// Tell the client it can exit.
//
LxtCheckResult(LxtSendMessage(ClientSocket, "exit")) LxtCheckResult(LxtWaitPidPoll(Child, 0));
ErrorExit:
if (ClientSocket >= 0)
{
close(ClientSocket);
}
if (ServerSocket >= 0)
{
close(ServerSocket);
}
unlink(g_SocketPath);
return Result;
}
int GetSetPgidExecveChild(void)
/*++
Routine Description:
This routine runs the child process for GetSetPgidExecve.
Arguments:
None.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
struct sockaddr_un Address;
int ClientSocket;
int Result;
LxtLogInfo("Child executable running, pid = %i", getpid());
LxtCheckErrno(ClientSocket = socket(AF_UNIX, SOCK_STREAM, 0));
//
// Connect to the parent process via AF_UNIX socket.
//
memset(&Address, 0, sizeof(Address));
Address.sun_family = AF_UNIX;
strncpy(Address.sun_path, g_SocketPath, sizeof(Address.sun_path) - 1);
Address.sun_path[sizeof(Address.sun_path) - 1] = 0;
LxtCheckErrnoZeroSuccess(connect(ClientSocket, (struct sockaddr*)&Address, sizeof(Address)));
//
// Tell the parent the process is running inside the execve'd binary.
//
LxtCheckResult(LxtSendMessage(ClientSocket, "execve"));
//
// Wait for the parent to tell this process it can exit so it has the
// chance to call setpgid.
//
LxtCheckResult(LxtReceiveMessage(ClientSocket, "exit"));
//
// This process should be able to change its own process group.
//
LxtCheckErrnoZeroSuccess(setpgid(0, 0));
LxtLogInfo("Child executable finished");
Result = LXT_RESULT_SUCCESS;
ErrorExit:
if (ClientSocket >= 0)
{
close(ClientSocket);
}
return Result;
}
int GetSetSid(PLXT_ARGS Args)
/*++
Routine Description:
This routine tests the getsid() and setsid() system calls..
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
pid_t ParentSid;
int Result;
pid_t Sid;
LxtCheckResult(LxtSignalBlock(SIGUSR1));
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
//
// Initial values.
//
LxtCheckErrno(ParentSid = getsid(getppid()));
LxtCheckNotEqual(ParentSid, 0, "%d") LxtCheckErrno(Sid = getsid(0));
LxtCheckEqual(ParentSid, Sid, "%d");
LxtCheckErrno(Sid = getsid(getpid()));
LxtCheckEqual(ParentSid, Sid, "%d");
//
// Create a new session.
//
LxtCheckErrno(Sid = setsid());
LxtCheckNotEqual(ParentSid, Sid, "%d");
LxtCheckEqual(Sid, getpid(), "%d");
LxtCheckEqual(Sid, getpgid(0), "%d");
//
// Tell the parent the new session was created.
//
LxtCheckErrnoZeroSuccess(kill(getppid(), SIGUSR1));
//
// Wait for the signal to exit.
//
LxtCheckResult(LxtSignalWaitBlocked(SIGUSR1, getppid(), 2));
_exit(LXT_RESULT_SUCCESS);
}
//
// Wait until the child has created the session.
//
LxtCheckResult(LxtSignalWaitBlocked(SIGUSR1, ChildPid, 2));
LxtCheckErrno(Sid = getsid(ChildPid));
LxtCheckErrno(ParentSid = getsid(0));
LxtCheckNotEqual(ParentSid, Sid, "%d");
LxtCheckEqual(Sid, ChildPid, "%d");
LxtCheckEqual(Sid, getpgid(ChildPid), "%d");
//
// Tell the child to exit.
//
LxtCheckErrnoZeroSuccess(kill(ChildPid, SIGUSR1));
LxtWaitPidPoll(ChildPid, 0);
//
// If the process is a process group leader, it can't create a new
// session. The test is already the process group leader if it is launched
// from the shell but not from all test environments.
//
if (getpid() != getpgid(0))
{
LxtCheckResult(setpgid(getpid(), 0));
}
LxtCheckErrnoFailure(setsid(), EPERM);
//
// Getsid with invalid arguments.
//
LxtCheckErrnoFailure(getsid(-1), ESRCH);
ErrorExit:
return Result;
}