/* * Enact a scenario by looping through the four test cases for the scenario, * spawning off pairs of processes with the desired credentials, and * reporting results to stdout. */ static int enact_scenario(int scenario) { pid_t pid1, pid2; char *name, *tracefile; int error, desirederror, loop; for (loop = 0; loop < LOOP_MAX+1; loop++) { /* * Spawn the first child, target of the operation. */ pid1 = fork(); switch (pid1) { case -1: return (-1); case 0: /* child */ error = cred_set(scenarios[scenario].sc_cred2); if (error) { perror("cred_set"); return (error); } /* 200 seconds should be plenty of time. */ sleep(200); exit(0); default: /* parent */ break; } /* * XXX * This really isn't ideal -- give proc 1 a chance to set * its credentials, or we may get spurious errors. Really, * some for of IPC should be used to allow the parent to * wait for the first child to be ready before spawning * the second child. */ sleep(1); /* * Spawn the second child, source of the operation. */ pid2 = fork(); switch (pid2) { case -1: return (-1); case 0: /* child */ error = cred_set(scenarios[scenario].sc_cred1); if (error) { perror("cred_set"); return (error); } /* * Initialize errno to zero so as to catch any * generated errors. In each case, perform the * operation. Preserve the error number for later * use so it doesn't get stomped on by any I/O. * Determine the desired error for the given case * by extracting it from the scenario table. * Initialize a function name string for output * prettiness. */ errno = 0; switch (loop) { case LOOP_PTRACE: error = ptrace(PT_ATTACH, pid1, NULL, 0); error = errno; name = "ptrace"; desirederror = scenarios[scenario].sc_canptrace_errno; break; case LOOP_KTRACE: tracefile = mktemp("/tmp/testuid_ktrace.XXXXXX"); if (tracefile == NULL) { error = errno; perror("mktemp"); break; } error = ktrace(tracefile, KTROP_SET, KTRFAC_SYSCALL, pid1); error = errno; name = "ktrace"; desirederror = scenarios[scenario].sc_canktrace_errno; unlink(tracefile); break; case LOOP_SIGHUP: error = kill(pid1, SIGHUP); error = errno; name = "sighup"; desirederror = scenarios[scenario].sc_cansighup_errno; break; case LOOP_SIGSEGV: error = kill(pid1, SIGSEGV); error = errno; name = "sigsegv"; desirederror = scenarios[scenario].sc_cansigsegv_errno; break; case LOOP_SEE: getpriority(PRIO_PROCESS, pid1); error = errno; name = "see"; desirederror = scenarios[scenario].sc_cansee_errno; break; case LOOP_SCHED: error = setpriority(PRIO_PROCESS, pid1, 0); error = errno; name = "sched"; desirederror = scenarios[scenario].sc_cansched_errno; break; default: name = "broken"; } if (error != desirederror) { fprintf(stdout, "[%s].%s: expected %s, got %s\n ", scenarios[scenario].sc_name, name, errno_to_string(desirederror), errno_to_string(error)); cred_print(stdout, scenarios[scenario].sc_cred1); cred_print(stdout, scenarios[scenario].sc_cred2); fprintf(stdout, "\n"); } exit(0); default: /* parent */ break; } error = waitpid(pid2, NULL, 0); /* * Once pid2 has died, it's safe to kill pid1, if it's still * alive. Mask signal failure in case the test actually * killed pid1 (not unlikely: can occur in both signal and * ptrace cases). */ kill(pid1, SIGKILL); error = waitpid(pid2, NULL, 0); } return (0); }
void KernelStartup::ProcessCommandLine(LPSTR lpCmdLine) { ktrace("Processing arguments\n"); //some yucky code to process the command line list<string> args; ParseCommandLine(lpCmdLine, args); //default init is /bin/init s_InitArguments[0] = "/bin/init"; for(int i=1; i<s_InitMaxArgs; ++i) { s_InitArguments[i] = NULL; } s_InitCurrentArgs = 1; //process the found args list<string>::iterator it; for(it=args.begin(); it!=args.end(); ++it) { string a = *it; string name,val; ktrace("processing: %s\n", a.c_str()); //split name=value? int eq = a.find('='); if(eq<0) { name = a; val = a; } else { name = a.substr(0,eq); val = a.substr(eq+1); } //find handler for arg int h=0; bool handled=false; for(; s_ArgumentHandlers[h].arg_name!=NULL; ++h) { if(name == s_ArgumentHandlers[h].arg_name) { (*s_ArgumentHandlers[h].handler)(val.c_str()); handled=true; break; } } if(!handled) { //Unknown arguments are passed as arguments to init (same as linux kernel does) if(s_InitCurrentArgs < s_InitMaxArgs) { s_InitArguments[s_InitCurrentArgs] = _strdup(val.c_str()); s_InitCurrentArgs++; } } } ktrace("Finished argument processing\n"); //we started with debug on //turn off now unless a log file was specified if(g_pKernelTable->m_hLogFile==NULL) g_pKernelTable->m_DebugLevel=0; }
/* * open a mutex object, creating if non-existent */ NTSTATUS SERVICECALL NtCreateMutant(OUT PHANDLE MutantHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN BOOLEAN InitialOwner) { HANDLE hMutant; struct kmutant* Mutant; NTSTATUS Status = STATUS_SUCCESS; POBJECT_ATTRIBUTES obj_attr = NULL; ktrace("\n"); if (ObjectAttributes) { if ((ULONG)ObjectAttributes < TASK_SIZE) { if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) return STATUS_NO_MEMORY; } else { obj_attr = ObjectAttributes; } } if (obj_attr) { if (obj_attr->RootDirectory) obj_attr->RootDirectory = base_dir_handle; } Status = create_object(KernelMode, mutant_object_type, obj_attr, KernelMode, NULL, sizeof(struct kmutant), 0, 0, (PVOID *)&Mutant); if (ObjectAttributes && (ULONG)ObjectAttributes < TASK_SIZE) kfree(obj_attr); if (!NT_SUCCESS(Status)) return Status; mutant_init(Mutant, InitialOwner); Status = insert_object((PVOID)Mutant, NULL, DesiredAccess, 0, NULL, &hMutant); if (Status == STATUS_OBJECT_NAME_EXISTS) { goto mutant_exists; } if (!NT_SUCCESS(Status)) return Status; mutant_exists: deref_object(Mutant); if (MutantHandle) { if ((ULONG)MutantHandle < TASK_SIZE) { if (copy_to_user(MutantHandle, &hMutant, sizeof(HANDLE))) Status = STATUS_NO_MEMORY; } else *MutantHandle = hMutant; } return Status; } /* end NtCreateMutant() */
void KernelStartup::arg_automount(const char *arg) { s_pszAutoMount = _strdup(arg); ktrace("AutoMount: %s\n", s_pszAutoMount); }
void KernelStartup::arg_log(const char *arg) { g_pKernelTable->m_hLogFile = CreateFile(arg, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0); ktrace("Log File: %s\n", arg); }
void KernelStartup::arg_debug(const char *arg) { g_pKernelTable->m_DebugLevel = atoi(arg); ktrace("Kernel Debug Level: %d\n", g_pKernelTable->m_DebugLevel); }
void KernelStartup::arg_init(const char *arg) { s_InitArguments[0] = _strdup(arg); ktrace("Using %s as 'init'\n", arg); }
//AutoMount windows drive letters //make mounts and generate initial /etc/mtab void KernelStartup::AutoMountDrives() { if(s_pszAutoMount==0) s_pszAutoMount = "CDEFGHIJKLMNOPRSTUVWXYZ"; Path p; //files may no exist, if so don't create them FILE * fMtab = NULL; p.SetUnixPath("/etc/mtab"); if(GetFileAttributes(p.GetWin32Path())!=INVALID_FILE_ATTRIBUTES) fMtab = fopen(p.GetWin32Path(), "wb"); char drive[] = "X:\\"; char mnt[] = "/mnt/X"; char *pMntLetter = &mnt[5]; //the 'X' const char *letter = s_pszAutoMount; while(*letter) { drive[0] = *pMntLetter = toupper(*letter); //is the drive valid to mount? if(GetFileAttributes(drive)!=INVALID_FILE_ATTRIBUTES) { //try to make the mount directory /mnt/X p.SetUnixPath(mnt); CreateDirectory(p.GetWin32Path(), NULL); if(GetFileAttributes(p.GetWin32Path())&FILE_ATTRIBUTE_DIRECTORY) { ktrace("automatic drive mount: %s on /mnt/%c\n", drive, *pMntLetter); //record the mount MountPoint * pMp = MountPoint::Mount(p, drive, new FilesystemKeow(), 0, NULL, 0); //update /etc/mtab (because we're not using unix 'mount' which normally does it) if(fMtab!=NULL) { //eg: c:/ /mnt/c keow rw 0 0 fprintf(fMtab, "%c:\\ /mnt/%c keow rw 0 0 \x0a", *pMntLetter, *pMntLetter); } } } ++letter; } //also want /proc and /dev mounted p.SetUnixPath("/proc"); CreateDirectory(p.GetWin32Path(), NULL); if(GetFileAttributes(p.GetWin32Path())&FILE_ATTRIBUTE_DIRECTORY) { //record the mount MountPoint * pMp = MountPoint::Mount(p, "", new FilesystemProc(), 0, NULL, 0); //update /etc/mtab if(fMtab) fprintf(fMtab, "/proc /proc proc rw 0 0 \x0a"); } p.SetUnixPath("/dev"); CreateDirectory(p.GetWin32Path(), NULL); if(GetFileAttributes(p.GetWin32Path())&FILE_ATTRIBUTE_DIRECTORY) { //record the mount MountPoint * pMp = MountPoint::Mount(p, "", new FilesystemDev(), 0, NULL, 0); //update /etc/mtab if(fMtab) fprintf(fMtab, "/dev /dev dev rw 0 0 \x0a"); } //close mtab if(fMtab) fclose(fMtab); }
NTSTATUS SERVICECALL NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal, IN HANDLE WaitableObjectHandle, IN BOOLEAN Alertable, IN PLARGE_INTEGER TimeOut OPTIONAL) { PVOID signal_obj, wait_obj; struct dispatcher_header *signal_header; LARGE_INTEGER _timeout; MODE previous_mode; NTSTATUS status; ktrace("ObjectHandleToSignal %p, WaitableObjectHandle %p, Alertable %d\n", ObjectHandleToSignal, WaitableObjectHandle, Alertable); previous_mode = (unsigned long)TimeOut > TASK_SIZE ? KernelMode : UserMode; if(TimeOut){ if (previous_mode == UserMode) { if (copy_from_user(&_timeout, TimeOut, sizeof(_timeout))) return STATUS_NO_MEMORY; } else _timeout = *TimeOut; } status = ref_object_by_handle(ObjectHandleToSignal, 0, NULL, KernelMode, &signal_obj, NULL); if (!NT_SUCCESS(status)) return status; status = ref_object_by_handle(WaitableObjectHandle, SYNCHRONIZE, NULL, KernelMode, &wait_obj, NULL); if (!NT_SUCCESS(status)) { deref_object(signal_obj); return status; } signal_header = (struct dispatcher_header *)signal_obj; if (is_wine_object(signal_header->type)) { struct object *obj = (struct object*)signal_obj; unsigned int access = get_handle_access(process2eprocess(current_thread->process), WaitableObjectHandle); if (BODY_TO_HEADER(obj)->ops->signal) BODY_TO_HEADER(obj)->ops->signal(obj, access); } else switch (signal_header->type) { case EventNotificationObject: case EventSynchronizationObject: set_event(signal_obj, EVENT_INCREMENT, TRUE); break; case MutantObject: release_mutant(signal_obj, IO_NO_INCREMENT, FALSE, TRUE); break; case SemaphoreObject: release_semaphore(signal_obj, SEMAPHORE_INCREMENT, 1, TRUE); break; default: deref_object(signal_obj); deref_object(wait_obj); return STATUS_OBJECT_TYPE_MISMATCH; } if(TimeOut){ status = wait_for_single_object(wait_obj, UserRequest, KernelMode, Alertable, &_timeout); } else { status = wait_for_single_object(wait_obj, UserRequest, KernelMode, Alertable, NULL); } if (!NT_SUCCESS(status)) goto out; if (TimeOut) { if (previous_mode == UserMode) { if (copy_to_user(TimeOut, &_timeout, sizeof(_timeout))) { status = STATUS_NO_MEMORY; goto out; } } else *TimeOut = _timeout; } out: deref_object(signal_obj); deref_object(wait_obj); return status; } /* end NtSignalAndWaitForSingleObject */
NTSTATUS SERVICECALL NtWaitForMultipleObjects(IN ULONG ObjectCount, IN PHANDLE ObjectsArray, IN WAIT_TYPE WaitType, IN BOOLEAN Alertable, IN PLARGE_INTEGER TimeOut OPTIONAL) { int i; struct kwait_block *wait_block; LARGE_INTEGER _timeout; NTSTATUS status; PVOID object[ObjectCount]; HANDLE hobj[ObjectCount]; MODE previous_mode; ktrace("%d, %p\n", ObjectCount, *ObjectsArray); previous_mode = (unsigned long)ObjectsArray > TASK_SIZE ? KernelMode : UserMode; if(TimeOut){ if (previous_mode == UserMode) { if (copy_from_user(&_timeout, TimeOut, sizeof(_timeout))) return STATUS_NO_MEMORY; } else _timeout = *TimeOut; } if(previous_mode == UserMode) { if(copy_from_user(hobj, ObjectsArray, sizeof(HANDLE)*ObjectCount)) return STATUS_NO_MEMORY; } else { memcpy(ObjectsArray, hobj, sizeof(HANDLE)*ObjectCount); } if (ObjectCount == 0) { wait_block = (struct kwait_block *)kmalloc(MAXIMUM_WAIT_OBJECTS * sizeof(struct kwait_block), GFP_KERNEL); if (!wait_block) { status = STATUS_NO_MEMORY; goto out; } status = wait_for_multi_objs(0, NULL, WaitType, UserRequest, KernelMode, Alertable, TimeOut ? &_timeout : NULL, wait_block); kfree(wait_block); return status; } for (i = 0; i < ObjectCount; i++) { status = ref_object_by_handle(hobj[i], SYNCHRONIZE, NULL, KernelMode, &object[i], NULL); if (!NT_SUCCESS(status)) { ObjectCount = i; goto out; } if (BODY_TO_HEADER(object[i])->Type == thread_object_type && object[i] == get_current_ethread()) { status = STATUS_INVALID_PARAMETER; ObjectCount = i + 1; goto out; } } wait_block = (struct kwait_block *)kmalloc(MAXIMUM_WAIT_OBJECTS * sizeof(struct kwait_block), GFP_KERNEL); if (!wait_block) { status = STATUS_NO_MEMORY; goto out; } status = wait_for_multi_objs(ObjectCount, object, WaitType, UserRequest, KernelMode, Alertable, TimeOut ? &_timeout : NULL, wait_block); kfree(wait_block); out: for (i = 0; i < ObjectCount; i++) deref_object(object[i]); ktrace("%x\n", status); return status; } /* end NtWaitForMultipleObjects */