bool copy_from_user(struct mm_struct *mm, void *dst, const void *src, size_t len, bool writable) { if (!user_mem_check(mm, (uintptr_t)src, len, writable)) { return 0; } memcpy(dst, src, len); return 1; }
bool copy_to_user(struct mm_struct *mm, void *dst, const void *src, size_t len) { if (!user_mem_check(mm, (uintptr_t)dst, len, 1)) { return 0; } memcpy(dst, src, len); return 1; }
// // Checks that environment 'env' is allowed to access the range // of memory [va, va+len) with permissions 'perm | PTE_U | PTE_P'. // If it can, then the function simply returns. // If it cannot, 'env' is destroyed and, if env is the current // environment, this function will not return. // void user_mem_assert(struct Env *env, const void *va, size_t len, int perm) { if (user_mem_check(env, va, len, perm | PTE_U) < 0) { cprintf("[%08x] user_mem_check assertion failure for " "va %08x\n", env->env_id, user_mem_check_addr); env_destroy(env); // may not return } }
int sys_get_home_dir(char* buf) { int r; if(curenv->user == -1) return -1; if((r = user_mem_check(curenv, buf, MAX_PATH_LENGTH, PTE_U|PTE_W)) <0) { cprintf("SYS_get_logged_user_name: %08x\n",r); return r; } memmove(buf,"/home/stam",11); return 0; }
int sys_update_current_path(char* buf) { int r; if(curenv->user == -1) return -1; if((r = user_mem_check(curenv, buf, MAX_PATH_LENGTH, PTE_U)) <0) { cprintf("SYS_get_logged_user_name: %08x\n",r); return r; } memmove(users[curenv->user].path,buf,MAX_PATH_LENGTH); return 0; }
int sys_get_logged_user_name(char* buf) { int r; if(curenv->user == -1) return -1; if((r = user_mem_check(curenv, buf, MAX_USER_LENGTH, PTE_U|PTE_W)) <0) { cprintf("SYS_get_logged_user_name: %08x\n",r); return r; } memmove(buf,users[curenv->user].user,MAX_USER_LENGTH); return 0; }
int ipc_event_recv(int *pid_store, int *event_store, unsigned int timeout) { if (event_store == NULL) { return -E_INVAL; } struct mm_struct *mm = current->mm; if (pid_store != NULL) { if (!user_mem_check(mm, (uintptr_t) pid_store, sizeof(int), 1)) { return -E_INVAL; } } if (!user_mem_check(mm, (uintptr_t) event_store, sizeof(int), 1)) { return -E_INVAL; } unsigned long saved_ticks; timer_t __timer, *timer = ipc_timer_init(timeout, &saved_ticks, &__timer); int pid, event, ret; if ((ret = recv_event(&pid, &event, timer)) == 0) { lock_mm(mm); { ret = -E_INVAL; if (pid_store == NULL || copy_to_user(mm, pid_store, &pid, sizeof(int))) { if (copy_to_user (mm, event_store, &event, sizeof(int))) { ret = 0; } } } unlock_mm(mm); return ret; } return ipc_check_timeout(timeout, saved_ticks); }
/** * Read a word from the container process's vm when we are in the main one * This is only used to 'touch' the page as read so the page table will be right. * See 'copy_from_user' in arch/um/mm/vmm.c for details. * @param proc the PCB whose container process will be touched * @param addr the address of the word to be touched (should be valid in the container process) * @param data the data to be read (of no use now) * @return 0 on success, or a negative otherwise */ int host_getvalue (struct proc_struct *proc, uintptr_t addr, uint32_t* data) { if (!user_mem_check(proc->mm, addr, sizeof (uintptr_t), 0)) { return -1; } struct stub_stack *stub_stack = proc->arch.host->stub_stack; struct stub_frame *frame = current_stub_frame (stub_stack); frame->eax = 0; frame->ebx = addr; int ret = host_syscall_in_child (proc); if (data != NULL) *data = ret; return 0; }
// Set envid's trap frame to 'tf'. // tf is modified to make sure that user environments always run at code // protection level 3 (CPL 3) with interrupts enabled. // // Returns 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. static int sys_env_set_trapframe(envid_t envid, struct Trapframe *tf) { // LAB 5: Your code here. // Remember to check whether the user has supplied us with a good // address! struct Env *env; int r; if ((r = envid2env(envid, &env, 1)) < 0) return r; /*-E_BAD_ENV*/ if ((r = user_mem_check(curenv, tf, sizeof(struct Trapframe), PTE_U | PTE_P)) < 0) return r; env->env_tf = *tf; env->env_tf.tf_eflags |= FL_IF; return 0; // panic("sys_env_set_trapframe not implemented"); }
/** * Write a word to the container process's vm when we are in the main one * This is only used to 'touch' the page as written so the page table will be right. * See 'copy_to_user' in arch/um/mm/vmm.c for details. * @param proc the PCB whose container process will be touched * @param addr the address of the word to be touched (should be valid in the container process) * @param data the data to be written (of no use now) * @return 0 on success, or a negative otherwise */ int host_assign (struct proc_struct *proc, uintptr_t addr, uint32_t data) { if (!user_mem_check(proc->mm, addr, sizeof (uintptr_t), 1)) { kprintf ("try assigning invalid address: 0x%x\n", addr); return -1; } /* Use stub call so that the page table will be modified properly */ struct stub_stack *stub_stack = proc->arch.host->stub_stack; struct stub_frame *frame = current_stub_frame (stub_stack); frame->eax = -1; frame->ebx = addr; frame->ecx = data; return host_syscall_in_child (proc); }
/* sysfile_get cwd - get current working directory */ int sysfile_getcwd(char *buf, size_t len) { struct mm_struct *mm = current->mm; if (len == 0) { return -E_INVAL; } int ret = -E_INVAL; lock_mm(mm); { if (user_mem_check(mm, (uintptr_t)buf, len, 1)) { struct iobuf __iob, *iob = iobuf_init(&__iob, buf, len, 0); ret = vfs_getcwd(iob); } } unlock_mm(mm); return ret; }
static int sys_proc_save(envid_t envid, struct proc *ps) { struct Env *e; struct Page *pg; int offset; //save env if (envid2env(envid, &e, 1) <0) return -E_BAD_ENV; if (user_mem_check(curenv, ps, sizeof(struct proc), PTE_U|PTE_W|PTE_P) <0) return -E_FAULT; ps->env = *e; //save stack if ((pg=page_lookup(e->env_pgdir, (void *)(USTACKTOP-PGSIZE), NULL))==NULL) return -E_FAULT; memmove(ps->stack, page2kva(pg), PGSIZE); // cprintf("process %x has been saved\n", envid); return 0; }
int sysfile_pipe(int *fd_store) { struct mm_struct *mm = current->mm; int ret, fd[2]; if (!user_mem_check(mm, (uintptr_t)fd_store, sizeof(fd), 1)) { return -E_INVAL; } if ((ret = file_pipe(fd)) == 0) { lock_mm(mm); { if (!copy_to_user(mm, fd_store, fd, sizeof(fd))) { ret = -E_INVAL; } } unlock_mm(mm); if (ret != 0) { file_close(fd[0]), file_close(fd[1]); } } return ret; }
//restore one process static int sys_proc_resume(envid_t envid, struct proc *ps) { struct Env *e; struct Page *pg; int offset; if (envid2env(envid, &e, 1) <0) return -E_BAD_ENV; if (user_mem_check(curenv, ps, sizeof(struct proc), PTE_U|PTE_P) <0) return -E_FAULT; *e = ps->env; if ((pg=page_lookup(e->env_pgdir, (void *)(USTACKTOP-PGSIZE), NULL))==NULL) return -E_FAULT; memmove(page2kva(pg), ps->stack, PGSIZE); return 0; }
bool copy_string(struct mm_struct *mm, char *dst, const char *src, size_t maxn) { size_t alen, part = ROUNDDOWN((uintptr_t)src + PGSIZE, PGSIZE) - (uintptr_t)src; while (1) { if (part > maxn) { part = maxn; } if (!user_mem_check(mm, (uintptr_t)src, part, 0)) { return 0; } if ((alen = strnlen(src, part)) < part) { memcpy(dst, src, alen + 1); return 1; } if (part == maxn) { return 0; } memcpy(dst, src, part); dst += part, src += part, maxn -= part; part = PGSIZE; } }
// Send packet static int sys_send_packet(void *va, unsigned int size) { int perm; int offset; int r; struct Page *p; perm = PTE_U; if(va + size >= (void *)UTOP) { cprintf("SYS_send_packet: above UTOP\n"); return -E_INVAL; } if((r = user_mem_check(curenv, va, size, perm)) <0) { cprintf("SYS_send_packet: %08x\n",r); return r; } if(size > MAX_ETH_FRAME_SIZE) { //should fix the size ... cprintf("SYS_send_packet: size is too big!"); return -E_INVAL; //better return? } //cprintf("Transmitting.......\n\n\n\n"); return e100_send_packet(va, size); }
// do_wait - wait one OR any children with PROC_ZOMBIE state, and free memory space of kernel stack // - proc struct of this child. // NOTE: only after do_wait function, all resources of the child proces are free. int do_wait(int pid, int *code_store) { struct mm_struct *mm = current->mm; if (code_store != NULL) { if (!user_mem_check(mm, (uintptr_t) code_store, sizeof(int), 1)) { return -E_INVAL; } } struct proc_struct *proc, *cproc; bool intr_flag, haskid; repeat: cproc = current; haskid = 0; if (pid != 0) { proc = find_proc(pid); if (proc != NULL) { do { if (proc->parent == cproc) { haskid = 1; if (proc->state == PROC_ZOMBIE) { goto found; } break; } cproc = next_thread(cproc); } while (cproc != current); } } else { do { proc = cproc->cptr; for (; proc != NULL; proc = proc->optr) { haskid = 1; if (proc->state == PROC_ZOMBIE) { goto found; } } cproc = next_thread(cproc); } while (cproc != current); } if (haskid) { current->state = PROC_SLEEPING; current->wait_state = WT_CHILD; schedule(); may_killed(); goto repeat; } return -E_BAD_PROC; found: if (proc == idleproc || proc == initproc) { panic("wait idleproc or initproc.\n"); } int exit_code = proc->exit_code; spin_lock_irqsave(&proc_lock, intr_flag); { unhash_proc(proc); remove_links(proc); } spin_unlock_irqrestore(&proc_lock, intr_flag); put_kstack(proc); kfree(proc); int ret = 0; if (code_store != NULL) { lock_mm(mm); { if (!copy_to_user (mm, code_store, &exit_code, sizeof(int))) { ret = -E_INVAL; } } unlock_mm(mm); } return ret; }
// debuginfo_eip(addr, info) // // Fill in the 'info' structure with information about the specified // instruction address, 'addr'. Returns 0 if information was found, and // negative if not. But even if it returns negative it has stored some // information into '*info'. // int debuginfo_eip(uintptr_t addr, struct Eipdebuginfo *info) { const struct Stab *stabs, *stab_end; const char *stabstr, *stabstr_end; int lfile, rfile, lfun, rfun, lline, rline; // Initialize *info info->eip_file = "<unknown>"; info->eip_line = 0; info->eip_fn_name = "<unknown>"; info->eip_fn_namelen = 9; info->eip_fn_addr = addr; info->eip_fn_narg = 0; // Find the relevant set of stabs if (addr >= ULIM) { stabs = __STAB_BEGIN__; stab_end = __STAB_END__; stabstr = __STABSTR_BEGIN__; stabstr_end = __STABSTR_END__; } else { // The user-application linker script, user/user.ld, // puts information about the application's stabs (equivalent // to __STAB_BEGIN__, __STAB_END__, __STABSTR_BEGIN__, and // __STABSTR_END__) in a structure located at virtual address // USTABDATA. const struct UserStabData *usd = (const struct UserStabData *) USTABDATA; // Make sure this memory is valid. // Return -1 if it is not. Hint: Call user_mem_check. // LAB 3: Your code here. if(user_mem_check(curenv, usd, sizeof(struct UserStabData), PTE_U) < 0) { return -1; } stabs = usd->stabs; stab_end = usd->stab_end; stabstr = usd->stabstr; stabstr_end = usd->stabstr_end; // Make sure the STABS and string table memory is valid. // LAB 3: Your code here. if(user_mem_check(curenv, stabs, stab_end-stabs, PTE_U) < 0) { return -1; } if(user_mem_check(curenv, stabstr, stabstr_end-stabstr, PTE_U) < 0) { return -1; } } // String table validity checks if (stabstr_end <= stabstr || stabstr_end[-1] != 0) return -1; // Now we find the right stabs that define the function containing // 'eip'. First, we find the basic source file containing 'eip'. // Then, we look in that source file for the function. Then we look // for the line number. // Search the entire set of stabs for the source file (type N_SO). lfile = 0; rfile = (stab_end - stabs) - 1; stab_binsearch(stabs, &lfile, &rfile, N_SO, addr); if (lfile == 0) return -1; // Search within that file's stabs for the function definition // (N_FUN). lfun = lfile; rfun = rfile; stab_binsearch(stabs, &lfun, &rfun, N_FUN, addr); if (lfun <= rfun) { // stabs[lfun] points to the function name // in the string table, but check bounds just in case. if (stabs[lfun].n_strx < stabstr_end - stabstr) info->eip_fn_name = stabstr + stabs[lfun].n_strx; info->eip_fn_addr = stabs[lfun].n_value; addr -= info->eip_fn_addr; // Search within the function definition for the line number. lline = lfun; rline = rfun; } else { // Couldn't find function stab! Maybe we're in an assembly // file. Search the whole file for the line number. info->eip_fn_addr = addr; lline = lfile; rline = rfile; } // Ignore stuff after the colon. info->eip_fn_namelen = strfind(info->eip_fn_name, ':') - info->eip_fn_name; // Search within [lline, rline] for the line number stab. // If found, set info->eip_line to the right line number. // If not found, return -1. // // Hint: // There's a particular stabs type used for line numbers. // Look at the STABS documentation and <inc/stab.h> to find // which one. // Your code here. stab_binsearch(stabs, &lline, &rline, N_SLINE, addr); if (lline <= rline) { info->eip_line = stabs[lline].n_desc; } else { return -1; } // Search backwards from the line number for the relevant filename // stab. // We can't just use the "lfile" stab because inlined functions // can interpolate code from a different file! // Such included source files use the N_SOL stab type. while (lline >= lfile && stabs[lline].n_type != N_SOL && (stabs[lline].n_type != N_SO || !stabs[lline].n_value)) lline--; if (lline >= lfile && stabs[lline].n_strx < stabstr_end - stabstr) info->eip_file = stabstr + stabs[lline].n_strx; // Set eip_fn_narg to the number of arguments taken by the function, // or 0 if there was no containing function. if (lfun < rfun) for (lline = lfun + 1; lline < rfun && stabs[lline].n_type == N_PSYM; lline++) info->eip_fn_narg++; return 0; }
int do_linux_waitpid(int pid, int *code_store) { struct mm_struct *mm = current->mm; if (code_store != NULL) { if (!user_mem_check(mm, (uintptr_t)code_store, sizeof(int), 1)) { return -E_INVAL; } } struct proc_struct *proc, *cproc; bool intr_flag, haskid; repeat: cproc = current; haskid = 0; if (pid > 0) { proc = find_proc(pid); if (proc != NULL) { do { if (proc->parent == cproc) { haskid = 1; if (proc->state == PROC_ZOMBIE) { goto found; } break; } cproc = next_thread(cproc); } while (cproc != current); } } /* we do NOT have group id, so..*/ else if(pid==0 || pid==-1){ /* pid == 0 */ do { proc = cproc->cptr; for (; proc != NULL; proc = proc->optr) { haskid = 1; if (proc->state == PROC_ZOMBIE) { goto found; } } cproc = next_thread(cproc); } while (cproc != current); }else{ //pid<-1 //TODO return -E_INVAL; } if (haskid) { current->state = PROC_SLEEPING; current->wait_state = WT_CHILD; schedule(); may_killed(); goto repeat; } return -E_BAD_PROC; found: if (proc == idleproc || proc == initproc) { panic("wait idleproc or initproc.\n"); } int exit_code = proc->exit_code; int return_pid = proc->pid; local_intr_save(intr_flag); { unhash_proc(proc); remove_links(proc); } local_intr_restore(intr_flag); put_kstack(proc); kfree(proc); int ret = 0; if (code_store != NULL) { lock_mm(mm); { int status = exit_code << 8; if (!copy_to_user(mm, code_store, &status, sizeof(int))) { ret = -E_INVAL; } } unlock_mm(mm); } return (ret == 0) ? return_pid : ret; }