mirror of
https://github.com/microsoft/WSL.git
synced 2025-07-04 07:43:21 +00:00
571 lines
13 KiB
C
571 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;
|
||
|
}
|