/*++ Copyright (c) Microsoft. All rights reserved. Module Name: Keymgmt.c Abstract: This file is a keymgmt test. --*/ #include "lxtcommon.h" #include "unittests.h" #include #define LXT_NAME "Keymgmt" #define LXT_KEYMGMT_DESCRIBE_LENGTH 128 #define LxtKeyCtl(_Cmd, _Arg2, _Arg3, _Arg4, _Arg5) syscall(SYS_keyctl, (_Cmd), (_Arg2), (_Arg3), (_Arg4), (_Arg5)) #define LxtAdd_Key(_Type, _Desc, _Payload, _Length, _KeyRing) \ syscall(SYS_add_key, (_Type), (_Desc), (_Payload), (_Length), (_KeyRing)) #define LxtRequest_Key(_Type, _Desc, _Info, _KeyRing) syscall(SYS_request_key, (_Type), (_Desc), (_Info), (_KeyRing)) #define KEY_POS_VIEW 0x01000000 #define KEY_POS_READ 0x02000000 #define KEY_POS_WRITE 0x04000000 #define KEY_POS_SEARCH 0x08000000 #define KEY_POS_LINK 0x10000000 #define KEY_POS_SETATTR 0x20000000 #define KEY_POS_ALL 0x3f000000 #define KEY_USR_VIEW 0x00010000 #define KEY_USR_READ 0x00020000 #define KEY_USR_WRITE 0x00040000 #define KEY_USR_SEARCH 0x00080000 #define KEY_USR_LINK 0x00100000 #define KEY_USR_SETATTR 0x00200000 #define KEY_USR_ALL 0x003f0000 #define KEY_GRP_VIEW 0x00000100 #define KEY_GRP_READ 0x00000200 #define KEY_GRP_WRITE 0x00000400 #define KEY_GRP_SEARCH 0x00000800 #define KEY_GRP_LINK 0x00001000 #define KEY_GRP_SETATTR 0x00002000 #define KEY_GRP_ALL 0x00003f00 #define KEY_OTH_VIEW 0x00000001 #define KEY_OTH_READ 0x00000002 #define KEY_OTH_WRITE 0x00000004 #define KEY_OTH_SEARCH 0x00000008 #define KEY_OTH_LINK 0x00000010 #define KEY_OTH_SETATTR 0x00000020 #define KEY_OTH_ALL 0x0000003f #define KEY_INVALID -1 #define LXT_KEYMGMT_ALLPERMS (KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL) #define LXT_KEYMGMT_DEFAULTPERMS (0x3f130000) #define LXT_KEYMGMT_DEFAULTPERMS_STRING "3f130000" #define LXT_KEYMGMT_NEWPERMS (0x3f3f0000) #define LXT_KEYMGMT_NEWPERMS_STRING "3f3f0000" #define LXT_KEYMGMT_SESIONKEYRING_NAME "sessionkeyring" #define LXT_KEYMGMT_SESIONKEYRING_DEFAULTPERMS "keyring;0;0;" LXT_KEYMGMT_DEFAULTPERMS_STRING ";" LXT_KEYMGMT_SESIONKEYRING_NAME #define LXT_KEYMGMT_SESIONKEYRING_NEWPERMS "keyring;0;0;" LXT_KEYMGMT_NEWPERMS_STRING ";" LXT_KEYMGMT_SESIONKEYRING_NAME #define LXT_KEYMGMT_SESIONKEYRING2_NAME "sessionkeyring2" #define LXT_KEYMGMT_SESIONKEYRING2_DEFAULTPERMS "keyring;0;0;" LXT_KEYMGMT_DEFAULTPERMS_STRING ";" LXT_KEYMGMT_SESIONKEYRING2_NAME #define LX_KEYMGMT_LONG_NAME_SIZE (4096 + 1) LXT_VARIATION_HANDLER KeymgmtSessionKeyringAssociation; LXT_VARIATION_HANDLER KeymgmtJoinSessionKeyring; LXT_VARIATION_HANDLER KeymgmtDescribe; LXT_VARIATION_HANDLER KeymgmtSetPerm; // // Global constants // // // TODO_LX: Enable KeymgmtSessionKeyringAssociation when supported. // static const LXT_VARIATION g_LxtVariations[] = { {"Keymgmt - KEYCTL_JOIN_SESSION_KEYRING", KeymgmtJoinSessionKeyring}, {"Keymgmt - KEYCTL_DESCRIBE", KeymgmtDescribe}, {"Keymgmt - KEYCTL_SETPERM", KeymgmtSetPerm}, /*{"Keymgmt session keyring association", KeymgmtSessionKeyringAssociation}*/}; int KeymgmtTestEntry(int Argc, char* Argv[]) /*++ --*/ { LXT_ARGS Args; int Result; LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME)); LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations))); ErrorExit: LxtUninitialize(); return !LXT_SUCCESS(Result); } void* KeymgmtSessionKeyringAssociationThread(void* Args) { char KeyBufferNew[LXT_KEYMGMT_DESCRIBE_LENGTH]; int32_t* KeySerial; int32_t KeySerialNew; int KeyType; int Result; KeyType = KEY_SPEC_SESSION_KEYRING; // // Check that the session keyring id didn't change. // KeySerial = Args; LxtCheckErrno(KeySerialNew = LxtKeyCtl(KEYCTL_GET_KEYRING_ID, KeyType, 0, 0, 0)); LxtCheckEqual(*KeySerial, KeySerialNew, "%d"); LxtCheckErrno(LxtKeyCtl(KEYCTL_SETPERM, KeySerialNew, LXT_KEYMGMT_ALLPERMS, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerialNew, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringNotEqual(LXT_KEYMGMT_SESIONKEYRING_DEFAULTPERMS, KeyBufferNew); ErrorExit: pthread_exit(&Result); } int KeymgmtSessionKeyringAssociation(PLXT_ARGS Args) /*++ --*/ { pid_t ChildPid; char KeyBuffer[LXT_KEYMGMT_DESCRIBE_LENGTH]; char KeyBufferNew[LXT_KEYMGMT_DESCRIBE_LENGTH]; int32_t KeySerial; int32_t KeySerialNew; int32_t KeySerialOriginal; int KeyType; int Result; pthread_t Thread = {0}; ChildPid = -1; KeyType = KEY_SPEC_SESSION_KEYRING; // // This test checks to see where the session keyring is associated. The // documentation is unclear if it is the threadgroup, thread, or user // namespace. The test below validates that the session keyring is // associated to the threadgroup and inherited across fork. // // // Get the current session keyring and check that is changes when a new // session keyring is created. // KeySerialOriginal = LxtKeyCtl(KEYCTL_GET_KEYRING_ID, KeyType, 0, 0, 0); if (KeySerialOriginal == -1) { KeySerialOriginal = 0; } LxtCheckErrno(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, LXT_KEYMGMT_SESIONKEYRING_NAME, 0, 0, 0)); LxtCheckNotEqual(KeySerialOriginal, KeySerial, "%d"); LxtLogInfo("Key %d", KeySerial); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBuffer, sizeof(KeyBuffer), 0)); LxtCheckStringEqual(KeyBuffer, LXT_KEYMGMT_SESIONKEYRING_DEFAULTPERMS); LxtCheckErrno(LxtKeyCtl(KEYCTL_SETPERM, KeySerial, LXT_KEYMGMT_ALLPERMS, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringNotEqual(KeyBuffer, KeyBufferNew); LxtCheckErrno(LxtKeyCtl(KEYCTL_SETPERM, KeySerial, LXT_KEYMGMT_DEFAULTPERMS, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringEqual(KeyBuffer, KeyBufferNew); // // Create a child process and thread, checking that the session keyring id // continues to be associated. // LxtCheckErrno(ChildPid = fork()); if (ChildPid == 0) { LxtCheckErrno(KeySerialNew = LxtKeyCtl(KEYCTL_GET_KEYRING_ID, KeyType, 0, 0, 0)); LxtCheckEqual(KeySerial, KeySerialNew, "%d"); LxtCheckErrno(LxtKeyCtl(KEYCTL_SETPERM, KeySerial, LXT_KEYMGMT_ALLPERMS, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringNotEqual(KeyBuffer, KeyBufferNew); _exit(LXT_RESULT_SUCCESS); } LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS)); // // The changes from the child threadgroup should reflect into the parent. // LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringNotEqual(KeyBuffer, KeyBufferNew); LxtCheckErrno(LxtKeyCtl(KEYCTL_SETPERM, KeySerial, LXT_KEYMGMT_DEFAULTPERMS, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringEqual(KeyBuffer, KeyBufferNew); // // Repeat the scenario with a thread. // LxtCheckErrno(pthread_create(&Thread, NULL, KeymgmtSessionKeyringAssociationThread, &KeySerial)); pthread_join(Thread, NULL); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringNotEqual(KeyBuffer, KeyBufferNew); LxtCheckErrno(LxtKeyCtl(KEYCTL_SETPERM, KeySerial, LXT_KEYMGMT_DEFAULTPERMS, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringEqual(KeyBuffer, KeyBufferNew); // // Create a user namespace and check that the session keyring id continues // to be associated. // LxtCheckErrno(ChildPid = fork()); if (ChildPid == 0) { LxtCheckErrno(KeySerialNew = LxtKeyCtl(KEYCTL_GET_KEYRING_ID, KeyType, 0, 0, 0)); LxtCheckEqual(KeySerial, KeySerialNew, "%d"); LxtCheckErrno(unshare(CLONE_NEWUSER)); LxtCheckErrno(KeySerialNew = LxtKeyCtl(KEYCTL_GET_KEYRING_ID, KeyType, 0, 0, 0)); LxtCheckEqual(KeySerial, KeySerialNew, "%d"); LxtCheckErrno(LxtKeyCtl(KEYCTL_SETPERM, KeySerial, LXT_KEYMGMT_ALLPERMS, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringNotEqual(KeyBuffer, KeyBufferNew); _exit(LXT_RESULT_SUCCESS); } LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS)); // // The changes from the child threadgroup should reflect into the parent. // LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringNotEqual(KeyBuffer, KeyBufferNew); LxtCheckErrno(LxtKeyCtl(KEYCTL_SETPERM, KeySerial, LXT_KEYMGMT_DEFAULTPERMS, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBufferNew, sizeof(KeyBufferNew), 0)); LxtCheckStringEqual(KeyBuffer, KeyBufferNew); Result = LXT_RESULT_SUCCESS; ErrorExit: if (ChildPid == 0) { _exit(Result); } return Result; } int KeymgmtJoinSessionKeyring(PLXT_ARGS Args) /*++ --*/ { pid_t ChildPid = -1; int Index; char* LongName = NULL; char KeyBuffer[LXT_KEYMGMT_DESCRIBE_LENGTH]; int32_t KeySerial; int32_t KeySerial2; LXT_PIPE Pipe = {-1, -1}; int Result; char* ValidNames[] = {"1", "a", "1a", ";", "name with a space ", "name with a tab\t", "name with a new line\n"}; // // This test checks how KEYCTL_JOIN_SESSION_KEYRING handles keyrings. // // // Check for valid names. // for (Index = 0; Index < LXT_COUNT_OF(ValidNames); ++Index) { LxtCheckErrno(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, ValidNames[Index], 0, 0, 0)); } // // Check for a really long name. // LongName = LxtAlloc(LX_KEYMGMT_LONG_NAME_SIZE); if (LongName == 0) { Result = LXT_RESULT_FAILURE; goto ErrorExit; } memset(LongName, 'a', LX_KEYMGMT_LONG_NAME_SIZE); LongName[LX_KEYMGMT_LONG_NAME_SIZE - 1] = 0; LxtCheckErrnoFailure(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, LongName, 0, 0, 0), EINVAL); LongName[LX_KEYMGMT_LONG_NAME_SIZE - 2] = 0; LxtCheckErrno(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, LongName, 0, 0, 0)); // // TODO_LX: Add support for NULL name when supported. // // // Invalid parameters. // LxtCheckErrnoFailure(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, (void*)0x1, 0, 0, 0), EFAULT); // // Check for lifetime. // LxtCheckResult(LxtCreatePipe(&Pipe)); LxtCheckResult(ChildPid = fork()); if (ChildPid == 0) { LxtCheckErrno(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, LXT_KEYMGMT_SESIONKEYRING_NAME, 0, 0, 0)); LxtCheckErrno(write(Pipe.Write, &KeySerial, sizeof(KeySerial))); _exit(0); } LxtCheckErrno(read(Pipe.Read, &KeySerial, sizeof(KeySerial))); LxtCheckResult(LxtWaitPidPoll(ChildPid, 0)); sleep(1); LxtCheckErrnoFailure(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBuffer, sizeof(KeyBuffer), 0), ENOKEY); LxtCheckResult(ChildPid = fork()); if (ChildPid == 0) { LxtCheckErrno(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, LXT_KEYMGMT_SESIONKEYRING_NAME, 0, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBuffer, sizeof(KeyBuffer), 0)); LxtCheckStringEqual(KeyBuffer, LXT_KEYMGMT_SESIONKEYRING_DEFAULTPERMS); LxtCheckErrno(KeySerial2 = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, LXT_KEYMGMT_SESIONKEYRING2_NAME, 0, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial2, KeyBuffer, sizeof(KeyBuffer), 0)); LxtCheckStringEqual(KeyBuffer, LXT_KEYMGMT_SESIONKEYRING2_DEFAULTPERMS); sleep(1); LxtCheckErrnoFailure(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBuffer, sizeof(KeyBuffer), 0), ENOKEY); _exit(0); } LxtCheckResult(LxtWaitPidPoll(ChildPid, 0)); Result = LXT_RESULT_SUCCESS; ErrorExit: if (ChildPid == 0) { _exit(Result); } if (LongName != NULL) { LxtFree(LongName); } LxtClosePipe(&Pipe); return Result; } int KeymgmtDescribe(PLXT_ARGS Args) /*++ --*/ { pid_t ChildPid = -1; int BytesRequired; char KeyBuffer[LXT_KEYMGMT_DESCRIBE_LENGTH]; int32_t KeySerial; int Result; // // This test checks how KEYCTL_DESCRIBE handles parameters. // // // Check for the default values. // LxtCheckResult(ChildPid = fork()); if (ChildPid == 0) { LxtCheckErrno(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, LXT_KEYMGMT_SESIONKEYRING_NAME, 0, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBuffer, sizeof(KeyBuffer), 0)); LxtCheckStringEqual(KeyBuffer, LXT_KEYMGMT_SESIONKEYRING_DEFAULTPERMS); LxtCheckErrno(BytesRequired = LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, NULL, 0, 0)); LxtCheckEqual(BytesRequired, sizeof(LXT_KEYMGMT_SESIONKEYRING_DEFAULTPERMS), "%d"); LxtCheckErrno(BytesRequired = LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, (void*)0x1, 1, 0)); LxtCheckEqual(BytesRequired, sizeof(LXT_KEYMGMT_SESIONKEYRING_DEFAULTPERMS), "%d"); _exit(0); } LxtWaitPidPoll(ChildPid, 0); // // TODO_LX: Add support for NULL name when supported. // // // Invalid parameters. // LxtCheckResult(ChildPid = fork()); if (ChildPid == 0) { LxtCheckErrno(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, LXT_KEYMGMT_SESIONKEYRING_NAME, 0, 0, 0)); LxtCheckErrnoFailure(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, (void*)0x1, sizeof(KeyBuffer), 0), EFAULT); LxtCheckErrnoFailure(LxtKeyCtl(KEYCTL_DESCRIBE, KEY_INVALID, KeyBuffer, sizeof(KeyBuffer), 0), ENOKEY); _exit(0); } LxtWaitPidPoll(ChildPid, 0); Result = LXT_RESULT_SUCCESS; ErrorExit: if (ChildPid == 0) { _exit(Result); } return Result; } int KeymgmtSetPerm(PLXT_ARGS Args) /*++ --*/ { pid_t ChildPid = -1; int BytesRequired; char KeyBuffer[LXT_KEYMGMT_DESCRIBE_LENGTH]; int32_t KeySerial; int Result; // // This test checks how KEYCTL_SETPERM handles parameters. // // // Check for the default values. // LxtCheckResult(ChildPid = fork()); if (ChildPid == 0) { LxtCheckErrno(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, LXT_KEYMGMT_SESIONKEYRING_NAME, 0, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBuffer, sizeof(KeyBuffer), 0)); LxtCheckStringEqual(KeyBuffer, LXT_KEYMGMT_SESIONKEYRING_DEFAULTPERMS); LxtCheckErrno(LxtKeyCtl(KEYCTL_SETPERM, KeySerial, LXT_KEYMGMT_DEFAULTPERMS, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBuffer, sizeof(KeyBuffer), 0)); LxtCheckStringEqual(KeyBuffer, LXT_KEYMGMT_SESIONKEYRING_DEFAULTPERMS); LxtCheckErrno(LxtKeyCtl(KEYCTL_SETPERM, KeySerial, LXT_KEYMGMT_NEWPERMS, 0, 0)); LxtCheckErrno(LxtKeyCtl(KEYCTL_DESCRIBE, KeySerial, KeyBuffer, sizeof(KeyBuffer), 0)); LxtCheckStringEqual(KeyBuffer, LXT_KEYMGMT_SESIONKEYRING_NEWPERMS); _exit(0); } LxtWaitPidPoll(ChildPid, 0); // // TODO_LX: Add support for NULL name when supported. // // // Invalid parameters. // LxtCheckResult(ChildPid = fork()); if (ChildPid == 0) { LxtCheckErrno(KeySerial = LxtKeyCtl(KEYCTL_JOIN_SESSION_KEYRING, LXT_KEYMGMT_SESIONKEYRING_NAME, 0, 0, 0)); LxtCheckErrnoFailure(LxtKeyCtl(KEYCTL_SETPERM, 0, LXT_KEYMGMT_DEFAULTPERMS, 0, 0), EINVAL); LxtCheckErrnoFailure(LxtKeyCtl(KEYCTL_SETPERM, KeySerial, -1, 0, 0), EINVAL); _exit(0); } LxtWaitPidPoll(ChildPid, 0); Result = LXT_RESULT_SUCCESS; ErrorExit: if (ChildPid == 0) { _exit(Result); } return Result; }