mirror of
https://github.com/microsoft/WSL.git
synced 2025-07-03 07:23:20 +00:00

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.
570 lines
13 KiB
C
570 lines
13 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
auxv.c
|
|
|
|
Abstract:
|
|
|
|
This file is a test for the auxiliary vector functionality.
|
|
|
|
--*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/auxv.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include "lxtcommon.h"
|
|
#include "unittests.h"
|
|
|
|
#define AUXV_UID 1004
|
|
#define AUXV_GID 1004
|
|
|
|
#define LXT_NAME "auxv"
|
|
|
|
#define AUXV_TEST_SCRIPT "auxv_test_script.sh"
|
|
#define AUXV_TEST_SCRIPT_SOURCE "#!" AUXV_TEST_PROGRAM_PATH
|
|
#define AUXV_TEST_PROGRAM "auxv_test_program"
|
|
#define AUXV_TEST_PROGRAM_PATH "/data/test/" AUXV_TEST_PROGRAM
|
|
#define AUXV_TEST_PROGRAM_SOURCE_FILE "auxv_test_program.c"
|
|
#define AUXV_TEST_PROGRAM_SOURCE \
|
|
"#include <stdio.h>\n" \
|
|
"#include <string.h>\n" \
|
|
"#include <stdlib.h>\n" \
|
|
"#include <sys/auxv.h>\n" \
|
|
"\n" \
|
|
"int main(int Argc, char** Argv)\n" \
|
|
"{\n" \
|
|
" int Index;\n" \
|
|
" char* Filename = (char*)getauxval(AT_EXECFN);\n" \
|
|
" char* Platform = (char*)getauxval(AT_PLATFORM);\n" \
|
|
" printf(\"AT_EXECFN: %%s {%%p}\\n\", Filename, Filename);\n" \
|
|
" printf(\"AT_PLATFORM: %%s {%%p}\\n\", Platform, Platform);\n" \
|
|
" for (Index = 0; Index < Argc; Index += 1) {\n" \
|
|
" printf(\"Argv[%%d] = %%s\\n\", Index, Argv[Index]);\n" \
|
|
" }\n" \
|
|
" if (Platform > Filename) {\n" \
|
|
" return -1;\n" \
|
|
" }\n" \
|
|
" if ((strcmp(Platform, \"%s\") != 0) ||\n" \
|
|
" (strcmp(Filename, \"%s\") != 0)) {\n" \
|
|
" return -1;\n" \
|
|
" }\n" \
|
|
" return 0;\n" \
|
|
"}"
|
|
|
|
int AuxvAtExecfn(PLXT_ARGS Args);
|
|
|
|
int AuxvGetAuxv(PLXT_ARGS Args);
|
|
|
|
int AuxvGetAuxvChild(void);
|
|
|
|
static const LXT_VARIATION g_LxtVariations[] = {{"getauxv", AuxvGetAuxv}, {"AT_EXECFN", AuxvAtExecfn}};
|
|
|
|
int AuxvTestEntry(int Argc, char* Argv[])
|
|
{
|
|
|
|
LXT_ARGS Args;
|
|
int ArgvIndex;
|
|
int Result;
|
|
|
|
Result = LXT_RESULT_FAILURE;
|
|
|
|
//
|
|
// Parse the arguments.
|
|
//
|
|
|
|
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 getauxv child variation.
|
|
//
|
|
|
|
return AuxvGetAuxvChild();
|
|
|
|
//
|
|
// The below arguments are taken care of by LxtInitialize.
|
|
//
|
|
|
|
case 'a':
|
|
break;
|
|
|
|
case 'v':
|
|
case 'l':
|
|
++ArgvIndex;
|
|
|
|
break;
|
|
|
|
default:
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If -c was not specified, just run the tests
|
|
//
|
|
|
|
LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
|
|
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
|
|
|
|
ErrorExit:
|
|
LxtUninitialize();
|
|
return 0;
|
|
}
|
|
|
|
int AuxvGetAuxv(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
char* Argv[4];
|
|
struct stat Buffer;
|
|
int ChildPid;
|
|
int Mode;
|
|
int OriginalMode;
|
|
gid_t OriginalGid;
|
|
uid_t OriginalUid;
|
|
int Result;
|
|
unsigned long Value;
|
|
|
|
ChildPid = -1;
|
|
OriginalMode = 0;
|
|
OriginalUid = 0;
|
|
OriginalGid = 0;
|
|
Value = getauxval(AT_SECURE);
|
|
LxtLogInfo("Parent AT_SECURE = %u", Value);
|
|
LxtCheckEqual(Value, 0, "%u");
|
|
|
|
// change Args->Argv[0] so that it points to the new single test binary design
|
|
Args->Argv[0] = Argv[0] = WSL_UNIT_TEST_BINARY;
|
|
LxtLogInfo("calling stat(%s)", Args->Argv[0]);
|
|
LxtCheckErrno(stat(Args->Argv[0], &Buffer));
|
|
OriginalMode = Buffer.st_mode;
|
|
OriginalGid = Buffer.st_gid;
|
|
OriginalUid = Buffer.st_uid;
|
|
|
|
LxtLogInfo("Setting the set-user-ID bit");
|
|
Mode = OriginalMode | S_ISUID;
|
|
|
|
LxtCheckErrno(chown(Args->Argv[0], AUXV_UID, AUXV_UID));
|
|
LxtCheckErrno(chmod(Args->Argv[0], Mode));
|
|
|
|
//
|
|
// Start a child process to verify the value of AT_SECURE.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Argv[1] = "auxv";
|
|
Argv[2] = "-c";
|
|
Argv[3] = NULL;
|
|
execve(Args->Argv[0], Argv, NULL);
|
|
LxtLogError("Execve failed, errno: %d (%s)", errno, strerror(errno));
|
|
_exit(LXT_RESULT_FAILURE);
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
LxtLogInfo("Setting the set-group-ID bit");
|
|
Mode = OriginalMode | S_ISGID;
|
|
LxtCheckErrno(chmod(Args->Argv[0], Mode));
|
|
|
|
//
|
|
// Start a child process to verify the value of AT_SECURE.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Argv[1] = "auxv";
|
|
Argv[2] = "-c";
|
|
Argv[3] = NULL;
|
|
execve(Argv[0], Argv, NULL);
|
|
LxtLogError("Execve failed, errno: %d (%s)", errno, strerror(errno));
|
|
_exit(LXT_RESULT_FAILURE);
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
if (OriginalMode != 0)
|
|
{
|
|
chmod(Args->Argv[0], OriginalMode);
|
|
chown(Args->Argv[0], OriginalUid, OriginalGid);
|
|
}
|
|
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int AuxvGetAuxvChild(void)
|
|
|
|
{
|
|
|
|
int ChildPid;
|
|
int Result;
|
|
unsigned long Value;
|
|
|
|
ChildPid = -1;
|
|
Value = getauxval(AT_SECURE);
|
|
LxtLogInfo("child AT_SECURE = %u", Value);
|
|
LxtCheckEqual(Value, 1, "%u");
|
|
|
|
//
|
|
// Start a child process to verify the value of AT_SECURE.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Value = getauxval(AT_SECURE);
|
|
LxtLogInfo("child fork AT_SECURE = %u", Value);
|
|
LxtCheckEqual(Value, 1, "%u");
|
|
Result = LXT_RESULT_SUCCESS;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int AuxvAtExecfnCompile(char* Filename)
|
|
|
|
{
|
|
|
|
char* Argv[5];
|
|
char Buffer[1024];
|
|
int ByteCount;
|
|
int ChildPid;
|
|
int Fd;
|
|
char* Platform;
|
|
int Result;
|
|
|
|
ChildPid = -1;
|
|
Fd = -1;
|
|
Platform = (char*)getauxval(AT_PLATFORM);
|
|
|
|
ByteCount = snprintf(Buffer, sizeof(Buffer), AUXV_TEST_PROGRAM_SOURCE, Platform, Filename);
|
|
|
|
if (ByteCount < 0)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Formatting test source failed %d", errno);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the source file to be compiled.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = creat(AUXV_TEST_PROGRAM_SOURCE_FILE, 0755));
|
|
LxtCheckErrno(ByteCount = write(Fd, Buffer, ByteCount));
|
|
|
|
//
|
|
// Compile the binary
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Filename = "/usr/bin/gcc";
|
|
Argv[0] = "gcc";
|
|
Argv[1] = AUXV_TEST_PROGRAM_SOURCE_FILE;
|
|
Argv[2] = "-o";
|
|
Argv[3] = AUXV_TEST_PROGRAM_PATH;
|
|
Argv[4] = NULL;
|
|
LxtCheckErrno(execv(Filename, Argv));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPollOptions(ChildPid, LXT_RESULT_SUCCESS, 0, 30));
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
if (Fd != -1)
|
|
{
|
|
LxtClose(Fd);
|
|
}
|
|
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
unlink(AUXV_TEST_PROGRAM_SOURCE_FILE);
|
|
return Result;
|
|
}
|
|
|
|
int AuxvAtExecfn(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
char* Argv[2];
|
|
int ByteCount;
|
|
int ChildPid;
|
|
char* Environment[2];
|
|
int Fd;
|
|
char* Filename;
|
|
int Result;
|
|
|
|
ChildPid = -1;
|
|
Fd = -1;
|
|
Filename = AUXV_TEST_PROGRAM_PATH;
|
|
LxtCheckResult(AuxvAtExecfnCompile(Filename));
|
|
|
|
//
|
|
// Run the binary with a non-null argument array.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Argv[0] = AUXV_TEST_PROGRAM_PATH;
|
|
Argv[1] = NULL;
|
|
LxtCheckErrno(execv(Filename, Argv));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Run the binary with a null argument array.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Environment[0] = "FOO=bar";
|
|
Environment[1] = NULL;
|
|
LxtCheckErrno(LxtExecve(Filename, NULL, Environment));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Run the binary with an Argv[0] that does not match the filename.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Argv[0] = "FOO";
|
|
Argv[1] = NULL;
|
|
LxtCheckErrno(execv(Filename, Argv));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Run the binary an empty command line.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Environment[0] = "FOO=bar";
|
|
Environment[1] = NULL;
|
|
LxtCheckErrno(LxtExecve(Filename, NULL, Environment));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Run the binary with null argument and environment arrays.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
LxtCheckErrno(LxtExecve(Filename, NULL, NULL));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Create a script that uses #! to launch the test binary.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = creat(AUXV_TEST_SCRIPT, 0755));
|
|
LxtCheckErrno(ByteCount = write(Fd, AUXV_TEST_SCRIPT_SOURCE, sizeof(AUXV_TEST_SCRIPT_SOURCE)));
|
|
LxtClose(Fd);
|
|
Fd = -1;
|
|
|
|
//
|
|
// Recompile the binary with the script as the expected AT_EXECFN.
|
|
//
|
|
|
|
Filename = AUXV_TEST_SCRIPT;
|
|
LxtCheckResult(AuxvAtExecfnCompile(Filename));
|
|
|
|
//
|
|
// Run the script with a non-null argument array.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Argv[0] = Filename;
|
|
Argv[1] = NULL;
|
|
LxtCheckErrno(execv(Filename, Argv));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Run the script with a null argument array.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Environment[0] = "FOO=bar";
|
|
Environment[1] = NULL;
|
|
LxtCheckErrno(LxtExecve(Filename, NULL, Environment));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Run the script with an Argv[0] that does not match the filename.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Argv[0] = "FOO";
|
|
Argv[1] = NULL;
|
|
LxtCheckErrno(execv(Filename, Argv));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Run the script an empty command line.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
Environment[0] = "FOO=bar";
|
|
Environment[1] = NULL;
|
|
LxtCheckErrno(LxtExecve(Filename, NULL, Environment));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Run the script with null argument and environment arrays.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
LxtCheckErrno(LxtExecve(Filename, NULL, NULL));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
if (Fd != -1)
|
|
{
|
|
LxtClose(Fd);
|
|
}
|
|
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
unlink(AUXV_TEST_PROGRAM_PATH);
|
|
unlink(AUXV_TEST_SCRIPT);
|
|
return Result;
|
|
}
|