WSL/test/linux/unit_tests/auxv.c

571 lines
13 KiB
C
Raw Permalink Normal View History

/*++
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;
}