static void continue_or_step(struct context* ctx, int stepi) { pid_t tid = ctx->child_tid; if (stepi) { sys_ptrace_singlestep(tid); } else { /* We continue with PTRACE_SYSCALL for error checking: * since the next event is supposed to be a signal, * entering a syscall here means divergence. There * shouldn't be any straight-line execution overhead * for SYSCALL vs. CONT, so the difference in cost * should be neglible. */ sys_ptrace_syscall(tid); } sys_waitpid(tid, &ctx->status); ctx->child_sig = signal_pending(ctx->status); if (0 == ctx->child_sig) { struct user_regs_struct regs; read_child_registers(ctx->child_tid, ®s); log_err("Replaying `%s' (line %d): expecting tracee signal or trap, but instead at `%s' (rcb: %llu)", strevent(ctx->trace.stop_reason), get_trace_file_lines_counter(), strevent(regs.orig_eax), read_rbc(ctx->hpc)); emergency_debug(ctx); } }
/** * Continue until reaching either the "entry" of an emulated syscall, * or the entry or exit of an executed syscall. |emu| is nonzero when * we're emulating the syscall. Return 0 when the next syscall * boundary is reached, or nonzero if advancing to the boundary was * interrupted by an unknown trap. */ static int cont_syscall_boundary(struct context* ctx, int emu, int stepi) { pid_t tid = ctx->child_tid; if (emu && stepi) { sys_ptrace_sysemu_singlestep(tid); } else if (emu) { sys_ptrace_sysemu(tid); } else if (stepi) { sys_ptrace_singlestep(tid); } else { sys_ptrace_syscall(tid); } sys_waitpid(tid, &ctx->status); switch ((ctx->child_sig = signal_pending(ctx->status))) { case 0: break; case SIGCHLD: /* SIGCHLD is pending, do not deliver it, wait for it * to appear in the trace SIGCHLD is the only signal * that should ever be generated as all other signals * are emulated! */ return cont_syscall_boundary(ctx, emu, stepi); case SIGTRAP: return 1; default: log_err("Replay got unrecorded signal %d", ctx->child_sig); emergency_debug(ctx); } assert(ctx->child_sig == 0); return 0; }
/* * Common code for cmd_prog and cmd_shell. * * Note that this does not wait for the subprogram to finish, but * returns immediately to the menu. This is usually not what you want, * so you should have it call your system-calls-assignment waitpid * code after forking. * * Also note that because the subprogram's thread uses the "args" * array and strings, until you do this a race condition exists * between that code and the menu input code. */ static int common_prog(int nargs, char **args) { int result; #if OPT_SYNCHPROBS kprintf("Warning: this probably won't work with a " "synchronization-problems kernel.\n"); #endif struct thread *thread_runs; result = thread_fork(args[0] /* thread name */, cmd_progthread /* thread function */, args /* thread arg */, nargs /* thread arg */, &thread_runs); int status = S_ZOMBIE; int wait_return; sys_waitpid(thread_runs->pid,&status,0,&wait_return); if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); return result; } return 0; }
/* * Common code for cmd_prog and cmd_shell. * * Note that this does not wait for the subprogram to finish, but * returns immediately to the menu. This is usually not what you want, * so you should have it call your system-calls-assignment waitpid * code after forking. * * Also note that because the subprogram's thread uses the "args" * array and strings, until you do this a race condition exists * between that code and the menu input code. */ static int common_prog(int nargs, char **args) { int result; int x; pid_t retval; struct thread *curthread; curthread = kmalloc(sizeof(struct thread*)); #if OPT_SYNCHPROBS kprintf("Warning: this probably won't work with a " "synchronization-problems kernel.\n"); #endif result = thread_fork(args[0] /* thread name */, cmd_progthread /* thread function */, args /* thread arg */, nargs /* thread arg */, &curthread ); if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); return result; } //call wait pid code - need to change // curthread->t_sem = sem_create("curthread",0); //P(curthread->t_sem); if(sys_waitpid(curthread->t_pid,&x,0,&retval)){ return 0; } return 0; }
static void smbd_sig_chld_handler(struct tevent_context *ev, struct tevent_signal *se, int signum, int count, void *siginfo, void *private_data) { pid_t pid; int status; while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) { bool unclean_shutdown = False; /* If the child terminated normally, assume it was an unclean shutdown unless the status is 0 */ if (WIFEXITED(status)) { unclean_shutdown = WEXITSTATUS(status); } /* If the child terminated due to a signal we always assume it was unclean. */ if (WIFSIGNALED(status)) { unclean_shutdown = True; } remove_child_pid(ev, pid, unclean_shutdown); } }
static void prefork_cleanup_loop(struct prefork_pool *pfp) { int status; pid_t pid; int i; /* TODO: should we use a process group id wait instead of looping ? */ for (i = 0; i < pfp->pool_size; i++) { if (pfp->pool[i].status == PF_WORKER_NONE || pfp->pool[i].pid == 0) { continue; } pid = sys_waitpid(pfp->pool[i].pid, &status, WNOHANG); if (pid > 0) { if (pfp->pool[i].status != PF_WORKER_EXITING) { DEBUG(3, ("Child (%d) terminated abnormally:" " %d\n", (int)pid, status)); } else { DEBUG(10, ("Child (%d) terminated with status:" " %d\n", (int)pid, status)); } /* reset all fields, * this makes status = PF_WORK_NONE */ memset(&pfp->pool[i], 0, sizeof(struct pf_worker_data)); } } }
int kt_kernel_idle_task(void) { tm_thread_raise_flag(current_thread, THREAD_KERNEL); kthread_create(&kthread_pager, "[kpager]", 0, __KT_pager, 0); strncpy((char *)current_process->command, "[kernel]", 128); /* wait until init has successfully executed, and then remap. */ while(!(kernel_state_flags & KSF_HAVEEXECED)) { tm_schedule(); } printk(1, "[kernel]: remapping lower memory with protection flags...\n"); cpu_interrupt_set(0); for(addr_t addr = MEMMAP_KERNEL_START; addr < MEMMAP_KERNEL_END; addr += PAGE_SIZE) { mm_virtual_changeattr(addr, PAGE_PRESENT | PAGE_WRITE, PAGE_SIZE); } cpu_interrupt_set(1); /* Now enter the main idle loop, waiting to do periodic cleanup */ printk(0, "[idle]: entering background loop\n"); for(;;) { assert(!current_thread->held_locks); int r=1; if(__current_cpu->work.count > 0) r=workqueue_dowork(&__current_cpu->work); else tm_schedule(); int status; int pid = sys_waitpid(-1, &status, WNOHANG); if(WIFSTOPPED(status)) { sys_kill(pid, SIGKILL); } } }
static void singlestep(struct context *ctx, int sig, int expected_val) { sys_ptrace_singlestep(ctx->child_tid, sig); sys_waitpid(ctx->child_tid, &ctx->status); /* we get a simple SIGTRAP in this case */ if (ctx->status != expected_val) { printf("status %x expected %x\n", ctx->status, expected_val); } assert(ctx->status == expected_val); ctx->status = 0; ctx->child_sig = 0; }
static void winbindd_sig_chld_handler(struct tevent_context *ev, struct tevent_signal *se, int signum, int count, void *siginfo, void *private_data) { pid_t pid; while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) { winbind_child_died(pid); } }
/** * Step over the system call instruction to "exit" the emulated * syscall. */ static void step_exit_syscall_emu(struct context *ctx) { pid_t tid = ctx->child_tid; struct user_regs_struct regs; read_child_registers(tid, ®s); sys_ptrace_sysemu_singlestep(tid); sys_waitpid(tid, &ctx->status); write_child_registers(tid, ®s); ctx->status = 0; }
static void sig_cld(int signum) { while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0) ; /* * Turns out it's *really* important not to * restore the signal handler here if we have real POSIX * signal handling. If we do, then we get the signal re-delivered * immediately - hey presto - instant loop ! JRA. */ #if !defined(HAVE_SIGACTION) CatchSignal(SIGCLD, sig_cld); #endif }
void goto_next_event(struct context *ctx) { if (ctx->child_sig != 0) { printf("sending signal: %d\n",ctx->child_sig); } sys_ptrace(PTRACE_SYSCALL, ctx->child_tid, 0, (void*) ctx->child_sig); sys_waitpid(ctx->child_tid, &ctx->status); ctx->child_sig = signal_pending(ctx->status); if (ctx->child_sig == SIGTRAP) { log_err("Caught unexpected SIGTRAP while going to next event"); emergency_debug(ctx); } ctx->event = read_child_orig_eax(ctx->child_tid); }
/* * Common code for cmd_prog and cmd_shell. * * Note that this does not wait for the subprogram to finish, but * returns immediately to the menu. This is usually not what you want, * so you should have it call your system-calls-assignment waitpid * code after forking. * * Also note that because the subprogram's thread uses the "args" * array and strings, until you do this a race condition exists * between that code and the menu input code. */ static int common_prog(int nargs, char **args) { struct proc *proc; int result; int status; int retval; unsigned tc; /* Create a process for the new program to run in. */ proc = proc_create_runprogram(args[0] /* name */); if (proc == NULL) { return ENOMEM; } tc = thread_count; result = thread_fork(args[0] /* thread name */, proc /* new process */, cmd_progthread /* thread function */, args /* thread arg */, nargs /* thread arg */); if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); proc_destroy(proc); return result; } result = sys_waitpid(proc->pid, &status, 0 , &retval); if (result ) { kprintf_n("sys_waitpid done with result %d for pid %d \n",result,proc->pid ); //return 0; } /* * The new process will be destroyed when the program exits... * once you write the code for handling that. */ // Wait for all threads to finish cleanup, otherwise khu be a bit behind, // especially once swapping is enabled. thread_wait_for_count(tc); return 0; }
static void bq_sig_chld_handler(struct tevent_context *ev_ctx, struct tevent_signal *se, int signum, int count, void *siginfo, void *pvt) { int status; pid_t pid; pid = sys_waitpid(-1, &status, WNOHANG); if (WIFEXITED(status)) { DEBUG(6, ("Bq child process %d terminated with %d\n", (int)pid, WEXITSTATUS(status))); } else { DEBUG(3, ("Bq child process %d terminated abnormally\n", (int)pid)); } }
static void interpret_pipe(struct interpreter_context *context, struct ast_node *node) { struct gsh_command *cmd1 = node->n_children; struct gsh_command *cmd2 = node->n_children->next; int in = sys_fcntl(0, 0, 0, 0); int out = sys_fcntl(1, 0, 0, 0); int err = sys_fcntl(2, 0, 0, 0); int pipe_des[2]; sys_pipe(pipe_des); close(0); sys_fcntl(pipe_des[0], 0, 0, 0); int pid = interpret_cmd(context, cmd2, P_NOWAIT); close(0); close(1); close(2); sys_fcntl(in, 0, 0, 0); sys_fcntl(pipe_des[1], 0, 1, 0); sys_fcntl(pipe_des[1], 0, 2, 0); interpret_cmd(context, cmd1, P_WAIT); close(1); close(2); sys_fcntl(out, 0, 1, 0); sys_fcntl(err, 0, 2, 0); close(pipe_des[0]); close(pipe_des[1]); int status; sys_waitpid(pid, &status); close(out); close(err); }
static int common_prog(int nargs, char **args) { struct proc *proc; int result; #if OPT_SYNCHPROBS kprintf("Warning: this probably won't work with a " "synchronization-problems kernel.\n"); #endif /* Create a process for the new program to run in. */ proc = proc_create_runprogram(args[0] /* name */); if (proc == NULL) { return ENOMEM; } result = thread_fork(args[0] /* thread name */, proc /* new process */, cmd_progthread /* thread function */, args /* thread arg */, nargs /* thread arg */); if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); proc_destroy(proc); return result; } /* * The new process will be destroyed when the program exits... * once you write the code for handling that. */ int *status = kmalloc(sizeof(int)); sys_waitpid(proc->p_pid, status, 0); return 0; }
int signal_handle(struct task *current, struct irq_frame *iframe) { while (current->sig_pending & (~current->sig_blocked)) { int signum = bit32_find_first_set((current->sig_pending & (~current->sig_blocked))) + 1; struct sigaction *action = current->sig_actions + signum - 1; kp(KP_TRACE, "signal: Handling %d on %d\n", signum, current->pid); kp(KP_TRACE, "signal: Handler: %p\n", action->sa_handler); SIGSET_UNSET(¤t->sig_pending, signum); if (action->sa_handler == SIG_IGN) { if (signum == SIGCHLD) { while (sys_waitpid(-1, NULL, WNOHANG) > 0) /* Reap chlidren */; } continue; } else if (action->sa_handler == SIG_DFL) { signal_default(current, signum); } else { signal_jump(current, signum, iframe); return 1; } } if (current->context.prev_syscall) { switch (iframe->eax) { case -ERESTARTSYS: case -ERESTARTNOINTR: case -ERESTARTNOHAND: signal_syscall_restart(iframe, current->context.prev_syscall); break; } } return 0; }
int sys_pclose(int fd) { int wstatus; popen_list **ptr = &popen_chain; popen_list *entry = NULL; pid_t wait_pid; int status = -1; /* Unlink from popen_chain. */ for ( ; *ptr != NULL; ptr = &(*ptr)->next) { if ((*ptr)->fd == fd) { entry = *ptr; *ptr = (*ptr)->next; status = 0; break; } } if (status < 0 || close(entry->fd) < 0) return -1; /* * As Samba is catching and eating child process * exits we don't really care about the child exit * code, a -1 with errno = ECHILD will do fine for us. */ do { wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0); } while (wait_pid == -1 && errno == EINTR); SAFE_FREE(entry); if (wait_pid == -1) return -1; return wstatus; }
/* Note: it is necessary to treat pid and options as unsigned ints, * with the corresponding cast to a signed int to insure that the * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ asmlinkage long compat_sys_waitpid(u32 pid, unsigned int __user * stat_addr, u32 options) { return sys_waitpid((int)pid, stat_addr, (int)options); }
static int syscall_dispatch(uint32_t sysnum, uint32_t args, regs_t *regs) { switch (sysnum) { case SYS_waitpid: return sys_waitpid((waitpid_args_t *)args); case SYS_exit: do_exit((int)args); panic("exit failed!\n"); return 0; case SYS_thr_exit: kthread_exit((void *)args); panic("thr_exit failed!\n"); return 0; case SYS_thr_yield: sched_make_runnable(curthr); sched_switch(); return 0; case SYS_fork: return sys_fork(regs); case SYS_getpid: return curproc->p_pid; case SYS_sync: sys_sync(); return 0; #ifdef __MOUNTING__ case SYS_mount: return sys_mount((mount_args_t *) args); case SYS_umount: return sys_umount((argstr_t *) args); #endif case SYS_mmap: return (int) sys_mmap((mmap_args_t *) args); case SYS_munmap: return sys_munmap((munmap_args_t *) args); case SYS_open: return sys_open((open_args_t *) args); case SYS_close: return sys_close((int)args); case SYS_read: return sys_read((read_args_t *)args); case SYS_write: return sys_write((write_args_t *)args); case SYS_dup: return sys_dup((int)args); case SYS_dup2: return sys_dup2((dup2_args_t *)args); case SYS_mkdir: return sys_mkdir((mkdir_args_t *)args); case SYS_rmdir: return sys_rmdir((argstr_t *)args); case SYS_unlink: return sys_unlink((argstr_t *)args); case SYS_link: return sys_link((link_args_t *)args); case SYS_rename: return sys_rename((rename_args_t *)args); case SYS_chdir: return sys_chdir((argstr_t *)args); case SYS_getdents: return sys_getdents((getdents_args_t *)args); case SYS_brk: return (int) sys_brk((void *)args); case SYS_lseek: return sys_lseek((lseek_args_t *)args); case SYS_halt: sys_halt(); return -1; case SYS_set_errno: curthr->kt_errno = (int)args; return 0; case SYS_errno: return curthr->kt_errno; case SYS_execve: return sys_execve((execve_args_t *)args, regs); case SYS_stat: return sys_stat((stat_args_t *)args); case SYS_uname: return sys_uname((struct utsname *)args); case SYS_debug: return sys_debug((argstr_t *)args); case SYS_kshell: return sys_kshell((int)args); default: dbg(DBG_ERROR, "ERROR: unknown system call: %d (args: %#08x)\n", sysnum, args); curthr->kt_errno = ENOSYS; return -1; } }
/** * main replayer method */ static void start(int option, int argc, char* argv[], char** envp) { pid_t pid; int status, fake_argc; if (option == RECORD) { copy_executable(argv[2]); if (access(__executable, X_OK)) { printf("The specified file '%s' does not exist or is not executable\n", __executable); return; } /* create directory for trace files */ setup_trace_dir(0); /* initialize trace files */ open_trace_files(); init_trace_files(); copy_argv(argc, argv); copy_envp(envp); record_argv_envp(argc, __argv, __envp); close_trace_files(); pid = sys_fork(); /* child process */ if (pid == 0) { sys_start_trace(__executable, __argv, __envp); /* parent process */ } else { child = pid; /* make sure that the child process dies when the master process gets interrupted */ install_signal_handler(); /* sync with the child process */ sys_waitpid(pid, &status); /* configure the child process to get a message upon a thread start, fork(), etc. */ sys_ptrace_setup(pid); /* initialize stuff */ init_libpfm(); /* initialize the trace file here -- we need to record argc and envp */ open_trace_files(); /* register thread at the scheduler and start the HPC */ rec_sched_register_thread(0, pid); /* perform the action recording */ fprintf(stderr, "start recording...\n"); start_recording(); fprintf(stderr, "done recording -- cleaning up\n"); /* cleanup all initialized data-structures */ close_trace_files(); close_libpfm(); } /* replayer code comes here */ } else if (option == REPLAY) { init_environment(argv[2], &fake_argc, __argv, __envp); copy_executable(__argv[0]); if (access(__executable, X_OK)) { printf("The specified file '%s' does not exist or is not executable\n", __executable); return; } pid = sys_fork(); //child process if (pid == 0) { sys_start_trace(__executable, __argv, __envp); /* parent process */ } else { child = pid; /* make sure that the child process dies when the master process gets interrupted */ install_signal_handler(); sys_waitpid(pid, &status); sys_ptrace_setup(pid); /* initialize stuff */ init_libpfm(); rep_sched_init(); /* sets the file pointer to the first trace entry */ read_trace_init(argv[2]); pid_t rec_main_thread = get_recorded_main_thread(); rep_sched_register_thread(pid, rec_main_thread); /* main loop */ replay(); /* thread wants to exit*/ close_libpfm(); read_trace_close(); rep_sched_close(); } } }
static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence, BOOL as_root) { char *slavedev; int master; pid_t pid, wpid; int wstat; BOOL chstat = False; /* allocate a pseudo-terminal device */ if ((master = findpty (&slavedev)) < 0) { DEBUG(3,("Cannot Allocate pty for password change: %s\n",name)); return(False); } /* * We need to temporarily stop CatchChild from eating * SIGCLD signals as it also eats the exit status code. JRA. */ CatchChildLeaveStatus(); if ((pid = fork()) < 0) { DEBUG(3,("Cannot fork() child for password change: %s\n",name)); close(master); CatchChild(); return(False); } /* we now have a pty */ if (pid > 0){ /* This is the parent process */ if ((chstat = talktochild(master, chatsequence)) == False) { DEBUG(3,("Child failed to change password: %s\n",name)); kill(pid, SIGKILL); /* be sure to end this process */ } while((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { if(errno == EINTR) { errno = 0; continue; } break; } if (wpid < 0) { DEBUG(3,("The process is no longer waiting!\n\n")); close(master); CatchChild(); return(False); } /* * Go back to ignoring children. */ CatchChild(); close(master); if (pid != wpid) { DEBUG(3,("We were waiting for the wrong process ID\n")); return(False); } if (WIFEXITED(wstat) == 0) { DEBUG(3,("The process exited while we were waiting\n")); return(False); } if (WEXITSTATUS(wstat) != 0) { DEBUG(3,("The status of the process exiting was %d\n", wstat)); return(False); } } else { /* CHILD */ /* * Lose any oplock capabilities. */ set_process_capability(KERNEL_OPLOCK_CAPABILITY, False); set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False); /* make sure it doesn't freeze */ alarm(20); if (as_root) become_root(False); DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,(int)getuid(),(int)getgid())); chstat = dochild(master, slavedev, name, passwordprogram, as_root); /* * The child should never return from dochild() .... */ DEBUG(0,("chat_with_program: Error: dochild() returned %d\n", chstat )); exit(1); } if (chstat) DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name)); return (chstat); }
void mips_syscall(struct trapframe *tf) { int callno; int32_t retval; int err; assert(curspl==0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. */ retval = 0; switch (callno) { case SYS_reboot: err = sys_reboot(tf->tf_a0); break; case SYS_getpid: retval = ((int32_t)sys_getpid()); err=retval; break; case SYS_waitpid: //just passing the the first arg from users waitpid err = (sys_waitpid(tf->tf_a0,&retval,0)); break; case SYS__exit: retval = ((int32_t)sys__exit()); err=retval; break; case SYS_fork: //http://jhshi.me/2012/03/21/os161-how-to-add-a-system-call/ err = ((int32_t)sys_fork(tf)); break; case SYS_execv: break; case SYS_read: //err = ((int32_t)sys_read(tf->tf_a0,(userptr_t)tf->tf_a1,tf->tf_a2)); //original err = ((int32_t)sys_read(tf->tf_a0,(char*)tf->tf_a1,tf->tf_a2)); break; case SYS_write: err = ((int32_t)sys_write(tf->tf_a0,(char*)tf->tf_a1,tf->tf_a2)); break; default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; } if (err) { /* * Return the error code. This gets converted at * userlevel to a return value of -1 and the error * code in errno. */ tf->tf_v0 = err; tf->tf_a3 = 1; /* signal an error */ } else { /* Success. */ tf->tf_v0 = retval; tf->tf_a3 = 0; /* signal no error */ } /* * Now, advance the program counter, to avoid restarting * the syscall over and over again. */ tf->tf_epc += 4; /* Make sure the syscall code didn't forget to lower spl */ assert(curspl==0); }
/* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. * * Note that we go through the signals twice: once to check the signals * that the kernel can handle, and then we build all the user-level signal * handling stack-frames in one go after that. */ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs) { unsigned long mask = ~current->blocked; unsigned long signr; struct sigaction * sa; current->tss.esp0 = (unsigned long) regs; /* If the process is traced, all signals are passed to the debugger. */ if (current->flags & PF_PTRACED) mask = ~0UL; while ((signr = current->signal & mask) != 0) { signr = ffz(~signr); clear_bit(signr, ¤t->signal); sa = current->sig->action + signr; signr++; #ifdef DEBUG printk("Signal %d: ", sa->sa_handler); #endif if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; /* Did we come from a system call? */ if (regs->orig_d0 >= 0) { /* Restart the system call */ if (regs->d0 == -ERESTARTNOHAND || regs->d0 == -ERESTARTSYS || regs->d0 == -ERESTARTNOINTR) { regs->d0 = regs->orig_d0; regs->pc -= 2; } } notify_parent(current, SIGCHLD); schedule(); if (!(signr = current->exit_code)) { discard_frame: continue; } current->exit_code = 0; if (signr == SIGSTOP) goto discard_frame; if (_S(signr) & current->blocked) { current->signal |= _S(signr); mask &= ~_S(signr); continue; } sa = current->sig->action + signr - 1; } if (sa->sa_handler == SIG_IGN) { #ifdef DEBUG printk("Ignoring.\n"); #endif if (signr != SIGCHLD) continue; /* check for SIGCHLD: it's special */ while (sys_waitpid(-1,NULL,WNOHANG) > 0) /* nothing */; continue; } if (sa->sa_handler == SIG_DFL) { #ifdef DEBUG printk("Default.\n"); #endif if (current->pid == 1) continue; switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; case SIGSTOP: if (current->flags & PF_PTRACED) continue; current->state = TASK_STOPPED; current->exit_code = signr; if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: if (current->binfmt && current->binfmt->core_dump) { if (current->binfmt->core_dump(signr, regs)) signr |= 0x80; } /* fall through */ default: current->signal |= _S(signr & 0x7f); current->flags |= PF_SIGNALED; do_exit(signr); } } handle_signal(signr, sa, oldmask, regs); return 1; } /* Did we come from a system call? */ if (regs->orig_d0 >= 0) { /* Restart the system call - no handlers present */ if (regs->d0 == -ERESTARTNOHAND || regs->d0 == -ERESTARTSYS || regs->d0 == -ERESTARTNOINTR) { regs->d0 = regs->orig_d0; regs->pc -= 2; } } /* If we are about to discard some frame stuff we must copy over the remaining frame. */ if (regs->stkadj) { struct pt_regs *tregs = (struct pt_regs *) ((ulong) regs + regs->stkadj); #if defined(DEBUG) || 1 printk("!!!!!!!!!!!!!! stkadj !!!\n"); #endif /* This must be copied with decreasing addresses to handle overlaps. */ tregs->pc = regs->pc; tregs->sr = regs->sr; } return 0; }
/**************************************************************************** run a command being careful about uid/gid handling and putting the output in outfile (or discard it if outfile is NULL). if shared is True then ensure the file will be writeable by all users but created such that its owned by root. This overcomes a security hole. if shared is not set then open the file with O_EXCL set ****************************************************************************/ int smbrun(char *cmd,char *outfile,BOOL shared) { int fd; pid_t pid; uid_t uid = current_user.uid; gid_t gid = current_user.gid; /* * Lose any kernel oplock capabilities we may have. */ set_process_capability(KERNEL_OPLOCK_CAPABILITY, False); set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False); #ifndef HAVE_EXECL int ret; pstring syscmd; char *path = lp_smbrun(); /* in the old method we use system() to execute smbrun which then executes the command (using system() again!). This involves lots of shell launches and is very slow. It also suffers from a potential security hole */ if (!file_exist(path,NULL)) { DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",path)); return(1); } slprintf(syscmd,sizeof(syscmd)-1,"%s %d %d \"(%s 2>&1) > %s\"", path,(int)uid,(int)gid,cmd, outfile?outfile:"/dev/null"); DEBUG(5,("smbrun - running %s ",syscmd)); ret = system(syscmd); DEBUG(5,("gave %d\n",ret)); return(ret); #else /* in this newer method we will exec /bin/sh with the correct arguments, after first setting stdout to point at the file */ /* * We need to temporarily stop CatchChild from eating * SIGCLD signals as it also eats the exit status code. JRA. */ CatchChildLeaveStatus(); if ((pid=fork()) < 0) { DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) )); CatchChild(); return errno; } if (pid) { /* * Parent. */ int status=0; pid_t wpid; /* the parent just waits for the child to exit */ while((wpid = sys_waitpid(pid,&status,0)) < 0) { if(errno == EINTR) { errno = 0; continue; } break; } CatchChild(); if (wpid != pid) { DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno))); return -1; } #if defined(WIFEXITED) && defined(WEXITSTATUS) if (WIFEXITED(status)) { return WEXITSTATUS(status); } #endif return status; } CatchChild(); /* we are in the child. we exec /bin/sh to do the work for us. we don't directly exec the command we want because it may be a pipeline or anything else the config file specifies */ /* point our stdout at the file we want output to go into */ if (outfile && !setup_stdout_file(outfile,shared)) { exit(80); } /* now completely lose our privileges. This is a fairly paranoid way of doing it, but it does work on all systems that I know of */ become_user_permanently(uid, gid); if (getuid() != uid || geteuid() != uid || getgid() != gid || getegid() != gid) { /* we failed to lose our privileges - do not execute the command */ exit(81); /* we can't print stuff at this stage, instead use exit codes for debugging */ } /* close all other file descriptors, leaving only 0, 1 and 2. 0 and 2 point to /dev/null from the startup code */ for (fd=3;fd<256;fd++) close(fd); execl("/bin/sh","sh","-c",cmd,NULL); /* not reached */ exit(82); #endif return 1; }
/* * System call dispatcher. * * A pointer to the trapframe created during exception entry (in * exception.S) is passed in. * * The calling conventions for syscalls are as follows: Like ordinary * function calls, the first 4 32-bit arguments are passed in the 4 * argument registers a0-a3. 64-bit arguments are passed in *aligned* * pairs of registers, that is, either a0/a1 or a2/a3. This means that * if the first argument is 32-bit and the second is 64-bit, a1 is * unused. * * This much is the same as the calling conventions for ordinary * function calls. In addition, the system call number is passed in * the v0 register. * * On successful return, the return value is passed back in the v0 * register, or v0 and v1 if 64-bit. This is also like an ordinary * function call, and additionally the a3 register is also set to 0 to * indicate success. * * On an error return, the error code is passed back in the v0 * register, and the a3 register is set to 1 to indicate failure. * (Userlevel code takes care of storing the error code in errno and * returning the value -1 from the actual userlevel syscall function. * See src/user/lib/libc/arch/mips/syscalls-mips.S and related files.) * * Upon syscall return the program counter stored in the trapframe * must be incremented by one instruction; otherwise the exception * return code will restart the "syscall" instruction and the system * call will repeat forever. * * If you run out of registers (which happens quickly with 64-bit * values) further arguments must be fetched from the user-level * stack, starting at sp+16 to skip over the slots for the * registerized values, with copyin(). */ void syscall(struct trapframe *tf) { //kprintf("Starting syscall\n"); int callno; int32_t retval; int err; KASSERT(curthread != NULL); KASSERT(curthread->t_curspl == 0); KASSERT(curthread->t_iplhigh_count == 0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. */ retval = 0; switch (callno) { case SYS_reboot: err = sys_reboot(tf->tf_a0); break; case SYS___time: err = sys___time((userptr_t)tf->tf_a0, (userptr_t)tf->tf_a1); break; #ifdef UW case SYS_write: err = sys_write((int)tf->tf_a0, (userptr_t)tf->tf_a1, (int)tf->tf_a2, (int *)(&retval)); break; case SYS__exit: sys__exit((int)tf->tf_a0); /* sys__exit does not return, execution should not get here */ panic("unexpected return from sys__exit"); break; case SYS_getpid: err = sys_getpid((pid_t *)&retval); break; case SYS_waitpid: err = sys_waitpid((pid_t)tf->tf_a0, (userptr_t)tf->tf_a1, (int)tf->tf_a2, (pid_t *)&retval); break; case SYS_fork: err = sys_fork(tf, (pid_t *)&retval); break; case SYS_execv: err=sys_execv((char *)tf->tf_a0, (char **) tf->tf_a1); break; #endif // UW /* Add stuff here */ default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; } if (err) { /* * Return the error code. This gets converted at * userlevel to a return value of -1 and the error * code in errno. */ tf->tf_v0 = err; tf->tf_a3 = 1; /* signal an error */ } else { /* Success. */ tf->tf_v0 = retval; tf->tf_a3 = 0; /* signal no error */ } /* * Now, advance the program counter, to avoid restarting * the syscall over and over again. */ tf->tf_epc += 4; /* Make sure the syscall code didn't forget to lower spl */ KASSERT(curthread->t_curspl == 0); /* ...or leak any spinlocks */ KASSERT(curthread->t_iplhigh_count == 0); }
/* * System call dispatcher. * * A pointer to the trapframe created during exception entry (in * exception-*.S) is passed in. * * The calling conventions for syscalls are as follows: Like ordinary * function calls, the first 4 32-bit arguments are passed in the 4 * argument registers a0-a3. 64-bit arguments are passed in *aligned* * pairs of registers, that is, either a0/a1 or a2/a3. This means that * if the first argument is 32-bit and the second is 64-bit, a1 is * unused. * * This much is the same as the calling conventions for ordinary * function calls. In addition, the system call number is passed in * the v0 register. * * On successful return, the return value is passed back in the v0 * register, or v0 and v1 if 64-bit. This is also like an ordinary * function call, and additionally the a3 register is also set to 0 to * indicate success. * * On an error return, the error code is passed back in the v0 * register, and the a3 register is set to 1 to indicate failure. * (Userlevel code takes care of storing the error code in errno and * returning the value -1 from the actual userlevel syscall function. * See src/user/lib/libc/arch/mips/syscalls-mips.S and related files.) * * Upon syscall return the program counter stored in the trapframe * must be incremented by one instruction; otherwise the exception * return code will restart the "syscall" instruction and the system * call will repeat forever. * * If you run out of registers (which happens quickly with 64-bit * values) further arguments must be fetched from the user-level * stack, starting at sp+16 to skip over the slots for the * registerized values, with copyin(). */ void syscall(struct trapframe *tf) { int callno; int32_t retval; int err; KASSERT(curthread != NULL); KASSERT(curthread->t_curspl == 0); KASSERT(curthread->t_iplhigh_count == 0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. */ retval = 0; off_t pos, new_pos; switch (callno) { case SYS_reboot: err = sys_reboot(tf->tf_a0); break; case SYS___time: err = sys___time((userptr_t) tf->tf_a0, (userptr_t) tf->tf_a1); break; case SYS_open: err = sys_open((userptr_t) tf->tf_a0, (int) tf->tf_a1, (int) tf->tf_a2, &retval); break; case SYS_read: err = sys_read((int) tf->tf_a0, (userptr_t) tf->tf_a1, (int) tf->tf_a2, &retval); break; case SYS_write: err = sys_write((int) tf->tf_a0, (userptr_t) tf->tf_a1, (int) tf->tf_a2, &retval); break; case SYS_lseek: pos = (((off_t)tf->tf_a2 << 32) | tf->tf_a3); err = sys_lseek((userptr_t) tf->tf_a0, pos, (userptr_t)(tf->tf_sp+16), &new_pos); if (err == 0) { retval = (int32_t)(new_pos >> 32); tf->tf_v1 = (int32_t)(new_pos & 0xFFFFFFFF); } break; case SYS_close: err = sys_close((userptr_t) tf->tf_a0, &retval); break; case SYS_dup2: err = sys_dup2((userptr_t) tf->tf_a0, (userptr_t) tf->tf_a1, &retval); break; case SYS_getpid: err = sys_getpid(&retval); break; case SYS_sbrk: err = sys_sbrk((userptr_t)tf->tf_a0, &retval); break; case SYS_fork: err = sys_fork(tf, &retval); break; case SYS_execv: err = sys_execv((userptr_t) tf->tf_a0, (userptr_t) tf->tf_a1, &retval); retval = 0; break; case SYS_waitpid: err = sys_waitpid((userptr_t) tf->tf_a0, (userptr_t) tf->tf_a1, (userptr_t) tf->tf_a2, &retval); break; case SYS__exit: //kprintf("TEMPPPP:Exit has been called! \n"); err = sys__exit((int) tf->tf_a0); break; /* Add stuff here */ default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; }
/* lock a byte range in a open file */ int main(int argc, char *argv[]) { struct flock lock; int fd, ret, status=1; pid_t pid; char *testdir = NULL; testdir = getenv("TESTDIR"); if (testdir) chdir(testdir); alarm(10); if (!(pid=fork())) { sleep(2); fd = open(DATA, O_RDONLY); if (fd == -1) { fprintf(stderr,"ERROR: failed to open %s (errno=%d)\n", DATA, (int)errno); exit(1); } lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0x100000000LL; lock.l_len = 4; lock.l_pid = getpid(); lock.l_type = F_WRLCK; /* check if a lock applies */ ret = fcntl(fd,F_GETLK,&lock); if ((ret == -1) || (lock.l_type == F_UNLCK)) { fprintf(stderr,"ERROR: lock test failed (ret=%d errno=%d)\n", ret, (int)errno); exit(1); } else { exit(0); } } unlink(DATA); fd = open(DATA, O_RDWR|O_CREAT|O_EXCL, 0600); if (fd == -1) { fprintf(stderr,"ERROR: failed to open %s (errno=%d)\n", DATA, (int)errno); exit(1); } lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0x100000004LL; lock.l_pid = getpid(); /* set a 100000004 byte write lock, should conflict with the above */ ret = fcntl(fd,F_SETLK,&lock); sys_waitpid(pid, &status, 0); unlink(DATA); if (ret != 0) { fprintf(stderr,"ERROR: failed to lock %s (errno=%d)\n", DATA, (int)errno); exit(1); } if (lock.l_len < 0x100000004LL) { fprintf(stderr,"ERROR: settign lock overflowed\n"); exit(1); } #if defined(WIFEXITED) && defined(WEXITSTATUS) if(WIFEXITED(status)) { status = WEXITSTATUS(status); } else { status = 1; } #else /* defined(WIFEXITED) && defined(WEXITSTATUS) */ status = (status == 0) ? 0 : 1; #endif /* defined(WIFEXITED) && defined(WEXITSTATUS) */ if (status) { fprintf(stderr,"ERROR: lock test failed with status=%d\n", status); } exit(status); }
static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence, BOOL as_root) { char *slavedev; int master; pid_t pid, wpid; int wstat; BOOL chstat = False; /* allocate a pseudo-terminal device */ if ((master = findpty (&slavedev)) < 0) { DEBUG(3,("Cannot Allocate pty for password change: %s\n",name)); return(False); } /* * We need to temporarily stop CatchChild from eating * SIGCLD signals as it also eats the exit status code. JRA. */ CatchChildLeaveStatus(); #ifdef __uClinux__ /* Hmmm, need to check this one further... */ DEBUG(0,("%s(%d): vfork()ing\n",__FILE__,__LINE__)); if ((pid = vfork()) < 0) { #else if ((pid = fork()) < 0) { #endif DEBUG(3,("Cannot fork() child for password change: %s\n",name)); close(master); CatchChild(); return(False); } /* we now have a pty */ if (pid > 0){ /* This is the parent process */ if ((chstat = talktochild(master, chatsequence)) == False) { DEBUG(3,("Child failed to change password: %s\n",name)); kill(pid, SIGKILL); /* be sure to end this process */ } while((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { if(errno == EINTR) { errno = 0; continue; } break; } if (wpid < 0) { DEBUG(3,("The process is no longer waiting!\n\n")); close(master); CatchChild(); return(False); } /* * Go back to ignoring children. */ CatchChild(); close(master); if (pid != wpid) { DEBUG(3,("We were waiting for the wrong process ID\n")); return(False); } if (WIFEXITED(wstat) == 0) { DEBUG(3,("The process exited while we were waiting\n")); return(False); } if (WEXITSTATUS(wstat) != 0) { DEBUG(3,("The status of the process exiting was %d\n", wstat)); return(False); } } else { /* CHILD */ /* * Lose any oplock capabilities. */ set_process_capability(KERNEL_OPLOCK_CAPABILITY, False); set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False); /* make sure it doesn't freeze */ alarm(20); if (as_root) become_root(False); DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,(int)getuid(),(int)getgid())); chstat = dochild(master, slavedev, name, passwordprogram, as_root); /* * The child should never return from dochild() .... */ DEBUG(0,("chat_with_program: Error: dochild() returned %d\n", chstat )); exit(1); } if (chstat) DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name)); return (chstat); } BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root) { pstring passwordprogram; pstring chatsequence; size_t i; size_t len; strlower(name); DEBUG(3,("Password change for user: %s\n",name)); #if DEBUG_PASSWORD DEBUG(100,("Passwords: old=%s new=%s\n",oldpass,newpass)); #endif /* Take the passed information and test it for minimum criteria */ /* Minimum password length */ if (strlen(newpass) < lp_min_passwd_length()) /* too short, must be at least MINPASSWDLENGTH */ { DEBUG(0,("Password Change: user %s, New password is shorter than minimum password length = %d\n", name, lp_min_passwd_length())); return (False); /* inform the user */ } /* Password is same as old password */ if (strcmp(oldpass,newpass) == 0) /* don't allow same password */ { DEBUG(2,("Password Change: %s, New password is same as old\n",name)); /* log the attempt */ return (False); /* inform the user */ } pstrcpy(passwordprogram,lp_passwd_program()); pstrcpy(chatsequence,lp_passwd_chat()); if (!*chatsequence) { DEBUG(2,("Null chat sequence - no password changing\n")); return(False); } if (!*passwordprogram) { DEBUG(2,("Null password program - no password changing\n")); return(False); } /* * Check the old and new passwords don't contain any control * characters. */ len = strlen(oldpass); for(i = 0; i < len; i++) { if (iscntrl((int)oldpass[i])) { DEBUG(0,("chat_with_program: oldpass contains control characters (disallowed).\n")); return False; } } len = strlen(newpass); for(i = 0; i < len; i++) { if (iscntrl((int)newpass[i])) { DEBUG(0,("chat_with_program: newpass contains control characters (disallowed).\n")); return False; } } pstring_sub(passwordprogram,"%u",name); /* note that we do NOT substitute the %o and %n in the password program as this would open up a security hole where the user could use a new password containing shell escape characters */ pstring_sub(chatsequence,"%u",name); all_string_sub(chatsequence,"%o",oldpass,sizeof(pstring)); all_string_sub(chatsequence,"%n",newpass,sizeof(pstring)); return(chat_with_program(passwordprogram,name,chatsequence, as_root)); }
/* * System call dispatcher. * * A pointer to the trapframe created during exception entry (in * exception.S) is passed in. * * The calling conventions for syscalls are as follows: Like ordinary * function calls, the first 4 32-bit arguments are passed in the 4 * argument registers a0-a3. 64-bit arguments are passed in *aligned* * pairs of registers, that is, either a0/a1 or a2/a3. This means that * if the first argument is 32-bit and the second is 64-bit, a1 is * unused. * * This much is the same as the calling conventions for ordinary * function calls. In addition, the system call number is passed in * the v0 register. * * On successful return, the return value is passed back in the v0 * register, or v0 and v1 if 64-bit. This is also like an ordinary * function call, and additionally the a3 register is also set to 0 to * indicate success. * * On an error return, the error code is passed back in the v0 * register, and the a3 register is set to 1 to indicate failure. * (Userlevel code takes care of storing the error code in errno and * returning the value -1 from the actual userlevel syscall function. * See src/user/lib/libc/arch/mips/syscalls-mips.S and related files.) * * Upon syscall return the program counter stored in the trapframe * must be incremented by one instruction; otherwise the exception * return code will restart the "syscall" instruction and the system * call will repeat forever. * * If you run out of registers (which happens quickly with 64-bit * values) further arguments must be fetched from the user-level * stack, starting at sp+16 to skip over the slots for the * registerized values, with copyin(). */ void syscall(struct trapframe *tf) { int callno; int32_t retval; int err; KASSERT(curthread != NULL); KASSERT(curthread->t_curspl == 0); KASSERT(curthread->t_iplhigh_count == 0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. */ retval = 0; switch (callno) { case SYS_reboot: err = sys_reboot(tf->tf_a0); break; case SYS___time: err = sys___time((userptr_t)tf->tf_a0, (userptr_t)tf->tf_a1); break; /* ASST2: These implementations of read and write only work for * console I/O (stdin, stdout and stderr file descriptors) */ case SYS_read: err = sys_read(tf->tf_a0, (userptr_t)tf->tf_a1, tf->tf_a2, &retval); break; case SYS_write: err = sys_write(tf->tf_a0, (userptr_t)tf->tf_a1, tf->tf_a2, &retval); break; /* process calls */ case SYS__exit: thread_exit(_MKWAIT_EXIT(tf->tf_a0)); panic("Returning from exit\n"); case SYS_fork: err = sys_fork(tf, &retval); break; /* ASST2 - You need to fill in the code for each of these cases */ case SYS_getpid: err = sys_getpid(&retval); break; case SYS_waitpid: if(sys_waitpid(tf->tf_a0, \ (userptr_t)tf->tf_a1, tf->tf_a2, &retval) == -1) { err=retval; } else{ err=0; } break; case SYS_kill: err = sys_kill(tf->tf_a0, tf->tf_a1); break; /* Even more system calls will go here */ default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; } if (err) { /* * Return the error code. This gets converted at * userlevel to a return value of -1 and the error * code in errno. */ tf->tf_v0 = err; tf->tf_a3 = 1; /* signal an error */ } else { /* Success. */ tf->tf_v0 = retval; tf->tf_a3 = 0; /* signal no error */ } /* * Now, advance the program counter, to avoid restarting * the syscall over and over again. */ tf->tf_epc += 4; /* Make sure the syscall code didn't forget to lower spl */ KASSERT(curthread->t_curspl == 0); /* ...or leak any spinlocks */ KASSERT(curthread->t_iplhigh_count == 0); }