From 13ef7f1f38166f1f61b89adac585fe6300cc532a Mon Sep 17 00:00:00 2001 From: Thomas Veerman Date: Mon, 30 Aug 2010 13:44:07 +0000 Subject: [PATCH] Prepare VFS to support back calls from PFS. For security reasons and to support file descriptor passing, PFS does some back calls to VFS. For example, to verify the validity of a path provided by a process and to tell VFS it must copy file descriptors from one process to another. --- servers/vfs/device.c | 56 ++++++--- servers/vfs/exec.c | 2 +- servers/vfs/filedes.c | 220 ++++++++++++++++++++++++++++++++- servers/vfs/fscall.c | 51 ++++++++ servers/vfs/glo.h | 1 + servers/vfs/link.c | 49 ++++++-- servers/vfs/mount.c | 9 +- servers/vfs/open.c | 68 ++--------- servers/vfs/path.c | 277 ++++++++++++++++++++++++++++++++++++++---- servers/vfs/protect.c | 26 +--- servers/vfs/proto.h | 44 +++++-- servers/vfs/read.c | 2 +- servers/vfs/request.c | 45 ++++--- servers/vfs/stadir.c | 8 +- servers/vfs/table.c | 10 ++ servers/vfs/time.c | 2 +- servers/vfs/utility.c | 17 +++ 17 files changed, 712 insertions(+), 175 deletions(-) diff --git a/servers/vfs/device.c b/servers/vfs/device.c index f9809c17e..c304c30b7 100644 --- a/servers/vfs/device.c +++ b/servers/vfs/device.c @@ -621,30 +621,48 @@ message *mess_ptr; /* pointer to message for task */ int r, proc_e; - if(task_nr == SYSTEM) printf("VFS: sending %d to SYSTEM\n", mess_ptr->m_type); + if(task_nr == SYSTEM) { + printf("VFS: sending %d to SYSTEM\n", mess_ptr->m_type); + } proc_e = mess_ptr->IO_ENDPT; - r = sendrec(task_nr, mess_ptr); - if(r == OK && mess_ptr->REP_STATUS == ERESTART) r = EDEADEPT; - if (r != OK) { - if (r == EDEADSRCDST || r == EDEADEPT) { - printf("fs: dead driver %d\n", task_nr); - dmap_unmap_by_endpt(task_nr); - return(r); + + for (;;) { + + r = sendrec(task_nr, mess_ptr); + if(r == OK && mess_ptr->REP_STATUS == ERESTART) r = EDEADEPT; + if (r != OK) { + if (r == EDEADSRCDST || r == EDEADEPT) { + printf("fs: dead driver %d\n", task_nr); + dmap_unmap_by_endpt(task_nr); + return(r); + } + if (r == ELOCKED) { + printf("fs: ELOCKED talking to %d\n", task_nr); + return(r); + } + panic("call_task: can't send/receive: %d", r); } - if (r == ELOCKED) { - printf("fs: ELOCKED talking to %d\n", task_nr); - return(r); + + /* Did the process we did the sendrec() for get a result? */ + if (mess_ptr->REP_ENDPT != proc_e && VFS_PROC_NR != proc_e) { + + printf("fs: strange device reply from %d, type = %d, " + "proc = %d (not %d) (2) ignored\n", mess_ptr->m_source, + mess_ptr->m_type, proc_e, mess_ptr->REP_ENDPT); + + return(EIO); } - panic("call_task: can't send/receive: %d", r); - } - /* Did the process we did the sendrec() for get a result? */ - if (mess_ptr->REP_ENDPT != proc_e) { - printf("fs: strange device reply from %d, type = %d, proc = %d " - "(not %d) (2) ignored\n", mess_ptr->m_source, mess_ptr->m_type, - proc_e, mess_ptr->REP_ENDPT); - return(EIO); + if (mess_ptr->m_type == TASK_REPLY || + IS_DEV_RS(mess_ptr->m_type) || + mess_ptr->m_type <= 0) { + + break; /* reply */ + } else { + + nested_dev_call(mess_ptr); + } } return(OK); diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index 334f1f097..c6fccecad 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -115,7 +115,7 @@ vir_bytes *pc; progname[PROC_NAME_LEN-1] = '\0'; /* Open executable */ - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); if ((vp->v_mode & I_TYPE) != I_REGULAR) r = ENOEXEC; diff --git a/servers/vfs/filedes.c b/servers/vfs/filedes.c index a6c677969..65da4bcf6 100644 --- a/servers/vfs/filedes.c +++ b/servers/vfs/filedes.c @@ -1,14 +1,22 @@ /* This file contains the procedures that manipulate file descriptors. * * The entry points into this file are - * get_fd: look for free file descriptor and free filp slots - * get_filp: look up the filp entry for a given file descriptor - * find_filp: find a filp slot that points to a given vnode - * inval_filp: invalidate a filp and associated fd's, only let close() - * happen on it + * get_fd: look for free file descriptor and free filp slots + * get_filp: look up the filp entry for a given file descriptor + * find_filp: find a filp slot that points to a given vnode + * inval_filp: invalidate a filp and associated fd's, only let close() + * happen on it + * do_verify_fd: verify whether the given file descriptor is valid for + * the given endpoint. + * do_set_filp: marks a filp as in-flight. + * do_copy_filp: copies a filp to another endpoint. + * do_put_filp: marks a filp as not in-flight anymore. + * do_cancel_fd: cancel the transaction when something goes wrong for + * the receiver. */ #include +#include #include #include #include "fs.h" @@ -139,3 +147,205 @@ PUBLIC int invalidate(struct filp *fp) return(n); /* Report back how often this filp has been invalidated. */ } + +/*===========================================================================* + * verify_fd * + *===========================================================================*/ +PUBLIC filp_id_t verify_fd(ep, fd) +endpoint_t ep; +int fd; +{ + /* + * verify whether the given file descriptor 'fd' is valid for the + * endpoint 'ep'. When the file descriptor is valid verify_fd returns a + * pointer to that filp, else it returns NULL. + */ + int proc; + + if (isokendpt(ep, &proc) != OK) { + return NULL; + } + + return get_filp2(&fproc[proc], fd); +} + +/*===========================================================================* + * do_verify_fd * + *===========================================================================*/ +PUBLIC int do_verify_fd(void) +{ + m_out.ADDRESS = (void *) verify_fd(m_in.IO_ENDPT, m_in.COUNT); + return (m_out.ADDRESS != NULL) ? OK : EINVAL; +} + +/*===========================================================================* + * set_filp * + *===========================================================================*/ +PUBLIC int set_filp(sfilp) +filp_id_t sfilp; +{ + if (sfilp == NULL) { + return EINVAL; + } else { + sfilp->filp_count++; + return OK; + } +} + +/*===========================================================================* + * do_set_filp * + *===========================================================================*/ +PUBLIC int do_set_filp(void) +{ + return set_filp((filp_id_t) m_in.ADDRESS);; +} + +/*===========================================================================* + * copy_filp * + *===========================================================================*/ +PUBLIC int copy_filp(to_ep, cfilp) +endpoint_t to_ep; +filp_id_t cfilp; +{ + int j; + int proc; + + if (isokendpt(to_ep, &proc) != OK) { + return EINVAL; + } + + /* Find an open slot in fp_filp */ + for (j = 0; j < OPEN_MAX; j++) { + if (fproc[proc].fp_filp[j] == NULL && + !FD_ISSET(j, &fproc[proc].fp_filp_inuse)) { + + /* Found a free slot, add descriptor */ + FD_SET(j, &fproc[proc].fp_filp_inuse); + fproc[proc].fp_filp[j] = cfilp; + fproc[proc].fp_filp[j]->filp_count++; + return j; + } + } + + /* File Descriptor Table is Full */ + return EMFILE; +} + +/*===========================================================================* + * do_copy_filp * + *===========================================================================*/ +PUBLIC int do_copy_filp(void) +{ + return copy_filp(m_in.IO_ENDPT, (filp_id_t) m_in.ADDRESS); +} + +/*===========================================================================* + * put_filp * + *===========================================================================*/ +PUBLIC int put_filp(pfilp) +filp_id_t pfilp; +{ + if (pfilp == NULL) { + return EINVAL; + } else { + close_filp(pfilp); + return OK; + } +} + +/*===========================================================================* + * do_put_filp * + *===========================================================================*/ +PUBLIC int do_put_filp(void) +{ + return put_filp((filp_id_t) m_in.ADDRESS); +} + +/*===========================================================================* + * cancel_fd * + *===========================================================================*/ +PUBLIC int cancel_fd(ep, fd) +endpoint_t ep; +int fd; +{ + int j; + int proc; + + if (isokendpt(ep, &proc) != OK) { + return EINVAL; + } + + /* Check that the input 'fd' is valid */ + if (verify_fd(ep, fd) != NULL) { + + /* Found a valid descriptor, remove it */ + FD_CLR(fd, &fproc[proc].fp_filp_inuse); + fproc[proc].fp_filp[fd]->filp_count--; + fproc[proc].fp_filp[fd] = NULL; + + return fd; + } + + /* File descriptor is not valid for the endpoint. */ + return EINVAL; +} + +/*===========================================================================* + * do_cancel_fd * + *===========================================================================*/ +PUBLIC int do_cancel_fd(void) +{ + return cancel_fd(m_in.IO_ENDPT, m_in.COUNT); +} + +/*===========================================================================* + * close_filp * + *===========================================================================*/ +PUBLIC void close_filp(fp) +struct filp *fp; +{ + int mode_word, rw; + dev_t dev; + struct vnode *vp; + + vp = fp->filp_vno; + if (fp->filp_count - 1 == 0 && fp->filp_mode != FILP_CLOSED) { + /* Check to see if the file is special. */ + mode_word = vp->v_mode & I_TYPE; + if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) { + dev = (dev_t) vp->v_sdev; + if (mode_word == I_BLOCK_SPECIAL) { + if (vp->v_bfs_e == ROOT_FS_E) { + /* Invalidate the cache unless the special is + * mounted. Assume that the root filesystem's + * is open only for fsck. + */ + req_flush(vp->v_bfs_e, dev); + } + } + /* Do any special processing on device close. */ + (void) dev_close(dev, fp-filp); + /* Ignore any errors, even SUSPEND. */ + + fp->filp_mode = FILP_CLOSED; + } + } + + /* If the inode being closed is a pipe, release everyone hanging on it. */ + if (vp->v_pipe == I_PIPE) { + rw = (fp->filp_mode & R_BIT ? WRITE : READ); + release(vp, rw, NR_PROCS); + } + + /* If a write has been done, the inode is already marked as DIRTY. */ + if (--fp->filp_count == 0) { + if (vp->v_pipe == I_PIPE) { + /* Last reader or writer is going. Tell PFS about latest + * pipe size. + */ + truncate_vnode(vp, vp->v_size); + } + + put_vnode(fp->filp_vno); + } +} diff --git a/servers/vfs/fscall.c b/servers/vfs/fscall.c index 9ba3fe7ec..c6026ef4a 100644 --- a/servers/vfs/fscall.c +++ b/servers/vfs/fscall.c @@ -3,6 +3,8 @@ * * The entry points into this file are * nested_fs_call perform a nested call from a file system server + * nested_dev_call perform a nested call from a device driver server + * */ #include "fs.h" @@ -11,6 +13,7 @@ #include #include #include +#include /* maximum nested call stack depth */ #define MAX_DEPTH 1 @@ -149,3 +152,51 @@ message *m; /* request/reply message pointer */ m->m_type = r; } + +/*===========================================================================* + * nested_dev_call * + *===========================================================================*/ +PUBLIC void nested_dev_call(m) +message *m; /* request/reply message pointer */ +{ +/* Handle a nested call from a device driver server. + */ + int r; + + /* Save global variables of the current call */ + if ((r = push_globals()) != OK) { + printf("VFS: error saving globals in call %d from driver %d\n", + m->m_type, m->m_source); + } else { + /* Initialize global variables for the nested call */ + set_globals(m); + + if (call_nr >= PFS_BASE) { + call_nr -= PFS_BASE; + } + + /* Perform the nested call */ + if (call_nr < 0 || call_nr >= PFS_NREQS) { + + printf("VFS: invalid nested call %d from driver %d\n", + call_nr, who_e); + + r = ENOSYS; + } else if (who_e == PFS_PROC_NR) { + + r = (*pfs_call_vec[call_nr])(); + } else { + + printf("VFS: only the PFS device can make nested VFS calls\n"); + + r = ENOSYS; + } + + /* Store the result, and restore original global variables */ + *m = m_out; + + pop_globals(); + } + + m->m_type = r; +} diff --git a/servers/vfs/glo.h b/servers/vfs/glo.h index 737f1c938..f6f54b1ca 100644 --- a/servers/vfs/glo.h +++ b/servers/vfs/glo.h @@ -34,5 +34,6 @@ EXTERN int err_code; /* temporary storage for error number */ /* Data initialized elsewhere. */ extern _PROTOTYPE (int (*call_vec[]), (void) ); /* sys call table */ +extern _PROTOTYPE (int (*pfs_call_vec[]), (void) ); /* pfs callback table */ extern char dot1[2]; /* dot1 (&dot1[0]) and dot2 (&dot2[0]) have a special */ extern char dot2[3]; /* meaning to search_dir: no access permission check. */ diff --git a/servers/vfs/link.c b/servers/vfs/link.c index 3b8a6171f..bb0c148e1 100644 --- a/servers/vfs/link.c +++ b/servers/vfs/link.c @@ -34,12 +34,12 @@ PUBLIC int do_link() /* See if 'name1' (file to be linked to) exists. */ if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); /* Does the final directory of 'name2' exist? */ if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code; - else if ((vp_d = last_dir()) == NULL) + else if ((vp_d = last_dir(fp)) == NULL) r = err_code; if (r != OK) { put_vnode(vp); @@ -76,7 +76,7 @@ PUBLIC int do_unlink() /* Get the last directory in the path. */ if(fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ((vldirp = last_dir()) == NULL) return(err_code); + if ((vldirp = last_dir(fp)) == NULL) return(err_code); /* Make sure that the object is a directory */ if((vldirp->v_mode & I_TYPE) != I_DIRECTORY) { @@ -94,7 +94,7 @@ PUBLIC int do_unlink() user is allowed to unlink */ if ((vldirp->v_mode & S_ISVTX) == S_ISVTX) { /* Look up inode of file to unlink to retrieve owner */ - vp = advance(vldirp, PATH_RET_SYMLINK); + vp = advance(vldirp, PATH_RET_SYMLINK, fp); if (vp != NULL) { if(vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM; @@ -129,13 +129,13 @@ PUBLIC int do_rename() /* See if 'name1' (existing file) exists. Get dir and file inodes. */ if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((old_dirp = last_dir()) == NULL) return(err_code); + if ((old_dirp = last_dir(fp)) == NULL) return(err_code); /* If the sticky bit is set, only the owner of the file or a privileged user is allowed to rename */ if((old_dirp->v_mode & S_ISVTX) == S_ISVTX) { /* Look up inode of file to unlink to retrieve owner */ - vp = advance(old_dirp, PATH_RET_SYMLINK); + vp = advance(old_dirp, PATH_RET_SYMLINK, fp); if (vp != NULL) { if(vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM; @@ -158,7 +158,7 @@ PUBLIC int do_rename() /* See if 'name2' (new name) exists. Get dir inode */ if(fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code; - else if ((new_dirp = last_dir()) == NULL) + else if ((new_dirp = last_dir(fp)) == NULL) r = err_code; if (r != OK) { put_vnode(old_dirp); @@ -198,7 +198,7 @@ PUBLIC int do_truncate() /* Temporarily open file */ if (fetch_name(m_in.m2_p1, m_in.m2_i1, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); /* Ask FS to truncate the file */ if ((r = forbidden(vp, W_BIT)) == OK) @@ -259,7 +259,7 @@ PUBLIC int do_slink() /* Get dir inode of 'name2' */ if(fetch_name(m_in.name2, m_in.name2_length, M1) != OK) return(err_code); - if ((vp = last_dir()) == NULL) return(err_code); + if ((vp = last_dir(fp)) == NULL) return(err_code); if ((r = forbidden(vp, W_BIT|X_BIT)) == OK) { r = req_slink(vp->v_fs_e, vp->v_inode_nr, user_fullpath, who_e, @@ -271,6 +271,32 @@ PUBLIC int do_slink() return(r); } +/*===========================================================================* + * rdlink_direct * + *===========================================================================*/ +PUBLIC int rdlink_direct(orig_path, link_path, rfp) +char *orig_path; +char *link_path; /* should have length PATH_MAX+1 */ +struct fproc *rfp; +{ +/* Perform a readlink()-like call from within the VFS */ + int r; + struct vnode *vp; + + /* Temporarily open the file containing the symbolic link */ + strncpy(user_fullpath, orig_path, PATH_MAX); + if ((vp = eat_path(PATH_RET_SYMLINK, rfp)) == NULL) return(err_code); + + /* Make sure this is a symbolic link */ + if((vp->v_mode & I_TYPE) != I_SYMBOLIC_LINK) + r = EINVAL; + else + r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, (endpoint_t) 0, + link_path, PATH_MAX+1, 1); + + put_vnode(vp); + return r; +} /*===========================================================================* * do_rdlink * @@ -286,13 +312,14 @@ PUBLIC int do_rdlink() /* Temporarily open the file containing the symbolic link */ if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_RET_SYMLINK)) == NULL) return(err_code); + if ((vp = eat_path(PATH_RET_SYMLINK, fp)) == NULL) return(err_code); /* Make sure this is a symbolic link */ if((vp->v_mode & I_TYPE) != I_SYMBOLIC_LINK) r = EINVAL; else - r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, copylen); + r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, + copylen, 0); put_vnode(vp); return(r); diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index 6a731a5cc..5064be82f 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -213,7 +213,7 @@ PRIVATE int mount_fs(endpoint_t fs_e) /* Now get the inode of the file to be mounted on. */ if (fetch_name(m_in.name2, m_in.name2_length, M1)!=OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); if (vp->v_ref_count != 1) { put_vnode(vp); return(EBUSY); @@ -254,7 +254,7 @@ PRIVATE int mount_fs(endpoint_t fs_e) if(!replace_root) { /* Get vnode of mountpoint */ - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); if (vp->v_ref_count != 1) { put_vnode(vp); @@ -451,7 +451,8 @@ PUBLIC int unmount( panic("unmount: strange fs endpoint: %d", vmp->m_fs_e); if ((r = req_unmount(vmp->m_fs_e)) != OK) /* Not recoverable. */ - printf("VFS: ignoring failed umount attempt (%d)\n", r); + printf("VFS: ignoring failed umount attempt (%d) fs pid: %d\n", r, + _ENDPOINT_P(vmp->m_fs_e)); if (is_nonedev(vmp->m_dev)) free_nonedev(vmp->m_dev); @@ -507,7 +508,7 @@ PRIVATE dev_t name_to_dev(int allow_mountpt) struct vnode *vp; /* Request lookup */ - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) { + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) { return(NO_DEV); } diff --git a/servers/vfs/open.c b/servers/vfs/open.c index 1ef32ca35..ae116b252 100644 --- a/servers/vfs/open.c +++ b/servers/vfs/open.c @@ -104,7 +104,7 @@ PRIVATE int common_open(register int oflags, mode_t omode) flag is set this is an error */ } else { /* Scan path name */ - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); } /* Claim the file descriptor and filp slot and fill them in. */ @@ -254,10 +254,10 @@ PRIVATE struct vnode *new_node(int oflags, mode_t bits) if (oflags & O_EXCL) flags |= PATH_RET_SYMLINK; /* See if the path can be opened down to the last directory. */ - if ((dirp = last_dir()) == NULL) return(NULL); + if ((dirp = last_dir(fp)) == NULL) return(NULL); /* The final directory is accessible. Get final component of the path. */ - vp = advance(dirp, flags); + vp = advance(dirp, flags, fp); /* The combination of a symlink with absolute path followed by a danglink * symlink results in a new path that needs to be re-resolved entirely. */ @@ -280,7 +280,7 @@ PRIVATE struct vnode *new_node(int oflags, mode_t bits) struct vnode *slp, *old_wd; /* Resolve path up to symlink */ - slp = advance(dirp, PATH_RET_SYMLINK); + slp = advance(dirp, PATH_RET_SYMLINK, fp); if (slp != NULL) { if (S_ISLNK(slp->v_mode)) { /* Get contents of link */ @@ -291,7 +291,7 @@ PRIVATE struct vnode *new_node(int oflags, mode_t bits) slp->v_inode_nr, VFS_PROC_NR, user_fullpath, - max_linklen); + max_linklen, 0); if (r < 0) { /* Failed to read link */ put_vnode(slp); @@ -406,7 +406,7 @@ PUBLIC int do_mknod() /* Open directory that's going to hold the new node. */ if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if((vp = last_dir()) == NULL) return(err_code); + if((vp = last_dir(fp)) == NULL) return(err_code); /* Make sure that the object is a directory */ if((vp->v_mode & I_TYPE) != I_DIRECTORY) { @@ -439,7 +439,7 @@ PUBLIC int do_mkdir() bits = I_DIRECTORY | (m_in.mode & RWX_MODES & fp->fp_umask); /* Request lookup */ - if((vp = last_dir()) == NULL) return(err_code); + if((vp = last_dir(fp)) == NULL) return(err_code); /* Make sure that the object is a directory */ if ((vp->v_mode & I_TYPE) != I_DIRECTORY) { @@ -596,60 +596,6 @@ int fd_nr; return(OK); } - -/*===========================================================================* - * close_filp * - *===========================================================================*/ -PUBLIC void close_filp(fp) -struct filp *fp; -{ - int mode_word, rw; - dev_t dev; - struct vnode *vp; - - vp = fp->filp_vno; - if (fp->filp_count - 1 == 0 && fp->filp_mode != FILP_CLOSED) { - /* Check to see if the file is special. */ - mode_word = vp->v_mode & I_TYPE; - if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) { - dev = (dev_t) vp->v_sdev; - if (mode_word == I_BLOCK_SPECIAL) { - if (vp->v_bfs_e == ROOT_FS_E) { - /* Invalidate the cache unless the special is - * mounted. Assume that the root filesystem's - * is open only for fsck. - */ - req_flush(vp->v_bfs_e, dev); - } - } - /* Do any special processing on device close. */ - (void) dev_close(dev, fp-filp); - /* Ignore any errors, even SUSPEND. */ - - fp->filp_mode = FILP_CLOSED; - } - } - - /* If the inode being closed is a pipe, release everyone hanging on it. */ - if (vp->v_pipe == I_PIPE) { - rw = (fp->filp_mode & R_BIT ? WRITE : READ); - release(vp, rw, NR_PROCS); - } - - /* If a write has been done, the inode is already marked as DIRTY. */ - if (--fp->filp_count == 0) { - if (vp->v_pipe == I_PIPE) { - /* Last reader or writer is going. Tell PFS about latest - * pipe size. - */ - truncate_vnode(vp, vp->v_size); - } - - put_vnode(fp->filp_vno); - } -} - - /*===========================================================================* * close_reply * *===========================================================================*/ diff --git a/servers/vfs/path.c b/servers/vfs/path.c index c85af71f7..3bd7f6019 100644 --- a/servers/vfs/path.c +++ b/servers/vfs/path.c @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include #include "fproc.h" #include "vmnt.h" #include "vnode.h" @@ -29,14 +32,15 @@ #define DO_POSIX_PATHNAME_RES 0 FORWARD _PROTOTYPE( int lookup, (struct vnode *dirp, int flags, - node_details_t *node) ); + node_details_t *node, struct fproc *rfp)); /*===========================================================================* * advance * *===========================================================================*/ -PUBLIC struct vnode *advance(dirp, flags) +PUBLIC struct vnode *advance(dirp, flags, rfp) struct vnode *dirp; int flags; +struct fproc *rfp; { /* Resolve a pathname (in user_fullpath) starting at dirp to a vnode. */ int r; @@ -50,7 +54,7 @@ int flags; if((new_vp = get_free_vnode()) == NULL) return(NULL); /* Lookup vnode belonging to the file. */ - if ((r = lookup(dirp, flags, &res)) != OK) { + if ((r = lookup(dirp, flags, &res, rfp)) != OK) { err_code = r; return(NULL); } @@ -86,21 +90,23 @@ int flags; /*===========================================================================* * eat_path * *===========================================================================*/ -PUBLIC struct vnode *eat_path(flags) +PUBLIC struct vnode *eat_path(flags, rfp) int flags; +struct fproc *rfp; { /* Resolve 'user_fullpath' to a vnode. advance does the actual work. */ struct vnode *vp; - vp = (user_fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd); - return advance(vp, flags); + vp = (user_fullpath[0] == '/' ? rfp->fp_rd : rfp->fp_wd); + return advance(vp, flags, rfp); } /*===========================================================================* - * last_dir * + * last_dir * *===========================================================================*/ -PUBLIC struct vnode *last_dir(void) +PUBLIC struct vnode *last_dir(rfp) +struct fproc *rfp; { /* Parse a path, 'user_fullpath', as far as the last directory, fetch the vnode * for the last directory into the vnode table, and return a pointer to the @@ -117,7 +123,7 @@ PUBLIC struct vnode *last_dir(void) struct vnode *vp, *res; /* Is the path absolute or relative? Initialize 'vp' accordingly. */ - vp = (user_fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd); + vp = (user_fullpath[0] == '/' ? rfp->fp_rd : rfp->fp_wd); len = strlen(user_fullpath); @@ -155,7 +161,7 @@ PUBLIC struct vnode *last_dir(void) cp--; } - res = advance(vp, PATH_NOFLAGS); + res = advance(vp, PATH_NOFLAGS, rfp); if (res == NULL) return(NULL); /* Copy the directory entry back to user_fullpath */ @@ -168,10 +174,11 @@ PUBLIC struct vnode *last_dir(void) /*===========================================================================* * lookup * *===========================================================================*/ -PRIVATE int lookup(start_node, flags, node) +PRIVATE int lookup(start_node, flags, node, rfp) struct vnode *start_node; int flags; node_details_t *node; +struct fproc *rfp; { /* Resolve a pathname (in user_fullpath) relative to start_node. */ @@ -191,8 +198,8 @@ node_details_t *node; return(ENOENT); } - if(!fp->fp_rd || !fp->fp_wd) { - printf("VFS: lookup_rel %d: no rd/wd\n", fp->fp_endpoint); + if(!rfp->fp_rd || !rfp->fp_wd) { + printf("VFS: lookup_rel %d: no rd/wd\n", rfp->fp_endpoint); return(ENOENT); } @@ -201,19 +208,19 @@ node_details_t *node; /* Is the process' root directory on the same partition?, * if so, set the chroot directory too. */ - if (fp->fp_rd->v_dev == fp->fp_wd->v_dev) - root_ino = fp->fp_rd->v_inode_nr; + if (rfp->fp_rd->v_dev == rfp->fp_wd->v_dev) + root_ino = rfp->fp_rd->v_inode_nr; else root_ino = 0; /* Set user and group ids according to the system call */ - uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid); - gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid); + uid = (call_nr == ACCESS ? rfp->fp_realuid : rfp->fp_effuid); + gid = (call_nr == ACCESS ? rfp->fp_realgid : rfp->fp_effgid); symloop = 0; /* Number of symlinks seen so far */ /* Issue the request */ - r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res); + r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res, rfp); if (r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) return(r); /* i.e., an error occured */ @@ -234,7 +241,7 @@ node_details_t *node; /* Symlink encountered with absolute path */ if (r == ESYMLINK) { - dir_vp = fp->fp_rd; + dir_vp = rfp->fp_rd; } else if (r == EENTERMOUNT) { /* Entering a new partition */ dir_vp = 0; @@ -278,12 +285,12 @@ node_details_t *node; /* Is the process' root directory on the same partition?, * if so, set the chroot directory too. */ - if(dir_vp->v_dev == fp->fp_rd->v_dev) - root_ino = fp->fp_rd->v_inode_nr; + if(dir_vp->v_dev == rfp->fp_rd->v_dev) + root_ino = rfp->fp_rd->v_inode_nr; else root_ino = 0; - r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res); + r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res, rfp); if(r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) return(r); @@ -300,3 +307,229 @@ node_details_t *node; return(r); } + +/*===========================================================================* + * get_name * + *===========================================================================*/ +PUBLIC int get_name(dirp, entry, ename) +struct vnode *dirp; +struct vnode *entry; +char ename[NAME_MAX + 1]; +{ + u64_t pos = {0, 0}, new_pos; + int r, consumed, totalbytes; + char buf[(sizeof(struct dirent) + NAME_MAX) * 8]; + struct dirent *cur; + + if ((dirp->v_mode & I_TYPE) != I_DIRECTORY) { + return(EBADF); + } + + do { + r = req_getdents(dirp->v_fs_e, dirp->v_inode_nr, pos, + buf, sizeof(buf), &new_pos, 1); + + if (r == 0) { + return(ENOENT); /* end of entries -- matching inode !found */ + } else if (r < 0) { + return(r); /* error */ + } + + consumed = 0; /* bytes consumed */ + totalbytes = r; /* number of bytes to consume */ + + do { + cur = (struct dirent *) (buf + consumed); + if (entry->v_inode_nr == cur->d_ino) { + /* found the entry we were looking for */ + strncpy(ename, cur->d_name, NAME_MAX); + ename[NAME_MAX] = '\0'; + return(OK); + } + + /* not a match -- move on to the next dirent */ + consumed += cur->d_reclen; + } while (consumed < totalbytes); + + pos = new_pos; + } while (1); +} + +/*===========================================================================* + * canonical_path * + *===========================================================================*/ +PUBLIC int canonical_path(orig_path, canon_path, rfp) +char *orig_path; +char *canon_path; /* should have length PATH_MAX+1 */ +struct fproc *rfp; +{ + int len = 0; + int r, symloop = 0; + struct vnode *dir_vp, *parent_dir; + char component[NAME_MAX+1]; + char link_path[PATH_MAX+1]; + + dir_vp = NULL; + strncpy(user_fullpath, orig_path, PATH_MAX); + + do { + if (dir_vp) put_vnode(dir_vp); + + /* Resolve to the last directory holding the socket file */ + if ((dir_vp = last_dir(rfp)) == NULL) { + return(err_code); + } + + /* dir_vp points to dir and user_fullpath now contains only the + * filename. + */ + strcpy(canon_path, user_fullpath); /* Store file name */ + + /* check if the file is a symlink, if so resolve it */ + r = rdlink_direct(canon_path, link_path, rfp); + if (r <= 0) { + strcpy(user_fullpath, canon_path); + break; + } + + /* encountered a symlink -- loop again */ + strcpy(user_fullpath, link_path); + + symloop++; + } while (symloop < SYMLOOP_MAX); + + if (symloop >= SYMLOOP_MAX) { + if (dir_vp) put_vnode(dir_vp); + return ELOOP; + } + + while(dir_vp != rfp->fp_rd) { + + strcpy(user_fullpath, ".."); + + /* check if we're at the root node of the file system */ + if (dir_vp->v_vmnt->m_root_node == dir_vp) { + put_vnode(dir_vp); + dir_vp = dir_vp->v_vmnt->m_mounted_on; + dup_vnode(dir_vp); + } + + if ((parent_dir = advance(dir_vp, PATH_NOFLAGS, rfp)) == NULL) { + put_vnode(dir_vp); + return(err_code); + } + + /* now we have to retrieve the name of the parent directory */ + if (get_name(parent_dir, dir_vp, component) != OK) { + put_vnode(dir_vp); + put_vnode(parent_dir); + return(ENOENT); + } + + len += strlen(component) + 1; + if (len > PATH_MAX) { + /* adding the component to canon_path would exceed PATH_MAX */ + put_vnode(dir_vp); + put_vnode(parent_dir); + return(ENOMEM); + } + + /* store result of component in canon_path */ + + /* first make space by moving the contents of canon_path to + * the right. Move strlen + 1 bytes to include the terminating '\0'. + */ + memmove(canon_path+strlen(component)+1, canon_path, + strlen(canon_path) + 1); + + /* Copy component into canon_path */ + memmove(canon_path, component, strlen(component)); + + /* Put slash into place */ + canon_path[strlen(component)] = '/'; + + /* Store parent_dir result, and continue the loop once more */ + put_vnode(dir_vp); + dir_vp = parent_dir; + } + + put_vnode(dir_vp); + + /* add the leading slash */ + if (strlen(canon_path) >= PATH_MAX) return(ENAMETOOLONG); + memmove(canon_path+1, canon_path, strlen(canon_path)); + canon_path[0] = '/'; + + return(OK); +} + +/*===========================================================================* + * check_perms * + *===========================================================================*/ +PUBLIC int check_perms(ep, io_gr, pathlen) +endpoint_t ep; +cp_grant_id_t io_gr; +int pathlen; +{ + int r, i; + struct vnode *vp; + struct fproc *rfp; + char orig_path[PATH_MAX+1]; + char canon_path[PATH_MAX+1]; + + i = _ENDPOINT_P(ep); + if (pathlen < UNIX_PATH_MAX || pathlen > PATH_MAX || i < 0 || i >= NR_PROCS) { + return EINVAL; + } + rfp = &(fproc[i]); + + memset(canon_path, '\0', PATH_MAX+1); + + r = sys_safecopyfrom(PFS_PROC_NR, io_gr, (vir_bytes) 0, + (vir_bytes) &user_fullpath, pathlen, D); + if (r != OK) { + return r; + } + user_fullpath[pathlen] = '\0'; + + /* save path from pfs before permissions checking modifies it */ + memcpy(orig_path, user_fullpath, PATH_MAX+1); + + /* get the canonical path to the socket file */ + r = canonical_path(orig_path, canon_path, rfp); + if (r != OK) { + return r; + } + + if (strlen(canon_path) >= pathlen) { + return ENAMETOOLONG; + } + + /* copy canon_path back to PFS */ + r = sys_safecopyto(PFS_PROC_NR, (cp_grant_id_t) io_gr, (vir_bytes) 0, + (vir_bytes) canon_path, strlen(canon_path)+1, + D); + if (r != OK) { + return r; + } + + /* reload user_fullpath for permissions checking */ + memcpy(user_fullpath, orig_path, PATH_MAX+1); + if ((vp = eat_path(PATH_NOFLAGS, rfp)) == NULL) { + return(err_code); + } + + /* check permissions */ + r = forbidden(vp, (R_BIT | W_BIT)); + + put_vnode(vp); + return(r); +} + +/*===========================================================================* + * do_check_perms * + *===========================================================================*/ +PUBLIC int do_check_perms(void) +{ + return check_perms(m_in.IO_ENDPT, (cp_grant_id_t) m_in.IO_GRANT, m_in.COUNT); +} diff --git a/servers/vfs/protect.c b/servers/vfs/protect.c index 83b116944..558cf4f90 100644 --- a/servers/vfs/protect.c +++ b/servers/vfs/protect.c @@ -18,8 +18,6 @@ #include "vnode.h" #include "vmnt.h" -FORWARD _PROTOTYPE( int in_group, (gid_t grp) ); - /*===========================================================================* * do_chmod * *===========================================================================*/ @@ -35,7 +33,7 @@ PUBLIC int do_chmod() if (call_nr == CHMOD) { /* Temporarily open the file */ if(fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); } else { /* call_nr == FCHMOD */ /* File is already opened; get a pointer to vnode from filp. */ if (!(flp = get_filp(m_in.fd))) return(err_code); @@ -85,7 +83,7 @@ PUBLIC int do_chown() if (call_nr == CHOWN) { /* Temporarily open the file. */ if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); } else { /* call_nr == FCHOWN */ /* File is already opened; get a pointer to the vnode from filp. */ if (!(flp = get_filp(m_in.fd))) return(err_code); @@ -152,7 +150,7 @@ PUBLIC int do_access() /* Temporarily open the file. */ if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); r = forbidden(vp, m_in.mode); put_vnode(vp); @@ -196,7 +194,7 @@ PUBLIC int forbidden(struct vnode *vp, mode_t access_desired) } else { if (uid == vp->v_uid) shift = 6; /* owner */ else if (gid == vp->v_gid) shift = 3; /* group */ - else if (in_group(vp->v_gid) == OK) shift = 3; /* suppl. groups */ + else if (in_group(fp, vp->v_gid) == OK) shift = 3; /* suppl. groups */ else shift = 0; /* other */ perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT); } @@ -215,22 +213,6 @@ PUBLIC int forbidden(struct vnode *vp, mode_t access_desired) return(r); } - -/*===========================================================================* - * in_group * - *===========================================================================*/ -PRIVATE int in_group(gid_t grp) -{ - int i; - - for (i = 0; i < fp->fp_ngroups; i++) - if (fp->fp_sgroups[i] == grp) - return(OK); - - return(EINVAL); -} - - /*===========================================================================* * read_only * *===========================================================================*/ diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 10fd86194..1cb17b9ca 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -10,6 +10,8 @@ struct fproc; struct vmnt; struct vnode; +typedef struct filp * filp_id_t; + /* device.c */ _PROTOTYPE( int dev_open, (dev_t dev, int proc, int flags) ); _PROTOTYPE( int dev_reopen, (dev_t dev, int filp_no, int flags) ); @@ -54,9 +56,21 @@ _PROTOTYPE( int get_fd, (int start, mode_t bits, int *k, _PROTOTYPE( struct filp *get_filp, (int fild) ); _PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild) ); _PROTOTYPE( int invalidate, (struct filp *) ); +_PROTOTYPE( filp_id_t verify_fd, (endpoint_t ep, int fd) ); +_PROTOTYPE( int do_verify_fd, (void) ); +_PROTOTYPE( int set_filp, (filp_id_t sfilp) ); +_PROTOTYPE( int do_set_filp, (void) ); +_PROTOTYPE( int copy_filp, (endpoint_t to_ep, filp_id_t cfilp) ); +_PROTOTYPE( int do_copy_filp, (void) ); +_PROTOTYPE( int put_filp, (filp_id_t pfilp) ); +_PROTOTYPE( int do_put_filp, (void) ); +_PROTOTYPE( int cancel_fd, (endpoint_t ep, int fd) ); +_PROTOTYPE( int do_cancel_fd, (void) ); +_PROTOTYPE( void close_filp, (struct filp *fp) ); /* fscall.c */ _PROTOTYPE( void nested_fs_call, (message *m) ); +_PROTOTYPE( void nested_dev_call, (message *m) ); /* link.c */ _PROTOTYPE( int do_link, (void) ); @@ -64,7 +78,9 @@ _PROTOTYPE( int do_unlink, (void) ); _PROTOTYPE( int do_rename, (void) ); _PROTOTYPE( int do_truncate, (void) ); _PROTOTYPE( int do_ftruncate, (void) ); -_PROTOTYPE( int truncate_vnode, (struct vnode *vp, off_t newsize) ); +_PROTOTYPE( int truncate_vnode, (struct vnode *vp, off_t newsize) ); +_PROTOTYPE( int rdlink_direct, (char *orig_path, char *link_path, + struct fproc *rfp) ); /* lock.c */ _PROTOTYPE( int lock_op, (struct filp *f, int req) ); @@ -99,7 +115,6 @@ _PROTOTYPE( int unmount, (dev_t dev, char *label) ); /* open.c */ _PROTOTYPE( int do_close, (void) ); _PROTOTYPE( int close_fd, (struct fproc *rfp, int fd_nr) ); -_PROTOTYPE( void close_filp, (struct filp *fp) ); _PROTOTYPE( void close_reply, (void) ); _PROTOTYPE( int do_creat, (void) ); _PROTOTYPE( int do_lseek, (void) ); @@ -112,9 +127,17 @@ _PROTOTYPE( int do_vm_open, (void) ); _PROTOTYPE( int do_vm_close, (void) ); /* path.c */ -_PROTOTYPE( struct vnode *advance, (struct vnode *dirp, int flags) ); -_PROTOTYPE( struct vnode *eat_path, (int flags) ); -_PROTOTYPE( struct vnode *last_dir, (void) ); +_PROTOTYPE( struct vnode *advance, (struct vnode *dirp, int flags, + struct fproc *rfp) ); +_PROTOTYPE( struct vnode *eat_path, (int flags, struct fproc *rfp) ); +_PROTOTYPE( struct vnode *last_dir, (struct fproc *rfp) ); +_PROTOTYPE( int get_name, (struct vnode *dirp, struct vnode *entry, + char *_name) ); +_PROTOTYPE( int canonical_path, (char *orig_path, char *canon_path, + struct fproc *rfp) ); +_PROTOTYPE( int check_perms, (endpoint_t ep, cp_grant_id_t gid, + int strlen) ); +_PROTOTYPE( int do_check_perms, (void) ); /* pipe.c */ _PROTOTYPE( int do_pipe, (void) ); @@ -168,14 +191,15 @@ _PROTOTYPE( int req_fstatfs, (int fs_e, int who_e, char *buf) ); _PROTOTYPE( int req_statvfs, (int fs_e, int who_e, char *buf) ); _PROTOTYPE( int req_ftrunc, (endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end) ); -_PROTOTYPE( int req_getdents, (endpoint_t fs_e, ino_t inode_nr, u64_t pos, - char *buf, size_t size, u64_t *new_pos) ); +_PROTOTYPE( int req_getdents, (endpoint_t fs_e, ino_t inode_nr, + u64_t pos, char *buf, size_t size, + u64_t *new_pos, int direct) ); _PROTOTYPE( int req_inhibread, (endpoint_t fs_e, ino_t inode_nr) ); _PROTOTYPE( int req_link, (endpoint_t fs_e, ino_t link_parent, char *lastc, ino_t linked_file) ); _PROTOTYPE( int req_lookup, (endpoint_t fs_e, ino_t dir_ino, ino_t root_ino, uid_t uid, gid_t gid, int flags, - lookup_res_t *res) ); + lookup_res_t *res, struct fproc *rfp) ); _PROTOTYPE( int req_mkdir, (endpoint_t fs_e, ino_t inode_nr, char *lastc, uid_t uid, gid_t gid, mode_t dmode) ); _PROTOTYPE( int req_mknod, (endpoint_t fs_e, ino_t inode_nr, @@ -187,7 +211,8 @@ _PROTOTYPE( int req_newnode, (endpoint_t fs_e, uid_t uid, dev_t dev, struct node_details *res) ); _PROTOTYPE( int req_putnode, (int fs_e, ino_t inode_nr, int count) ); _PROTOTYPE( int req_rdlink, (endpoint_t fs_e, ino_t inode_nr, - endpoint_t who_e, char *buf, size_t len) ); + endpoint_t who_e, char *buf, size_t len, + int direct) ); _PROTOTYPE( int req_readsuper, (endpoint_t fs_e, char *driver_name, dev_t dev, int readonly, int isroot, struct node_details *res_nodep) ); @@ -236,6 +261,7 @@ _PROTOTYPE( long conv4, (int norm, long x) ); _PROTOTYPE( int fetch_name, (char *path, int len, int flag) ); _PROTOTYPE( int no_sys, (void) ); _PROTOTYPE( int isokendpt_f, (char *f, int l, endpoint_t e, int *p, int ft)); +_PROTOTYPE( int in_group, (struct fproc *rfp, gid_t grp) ); #define okendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 1) #define isokendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 0) diff --git a/servers/vfs/read.c b/servers/vfs/read.c index 9b6853ac3..06bf6dcf2 100644 --- a/servers/vfs/read.c +++ b/servers/vfs/read.c @@ -168,7 +168,7 @@ PUBLIC int do_getdents() panic("do_getdents: should handle large offsets"); r = req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr, - rfilp->filp_pos, m_in.buffer, m_in.nbytes, &new_pos); + rfilp->filp_pos, m_in.buffer, m_in.nbytes, &new_pos, 0); if (r > 0) rfilp->filp_pos = new_pos; diff --git a/servers/vfs/request.c b/servers/vfs/request.c index cdd208da4..ecc01ee89 100644 --- a/servers/vfs/request.c +++ b/servers/vfs/request.c @@ -283,16 +283,25 @@ PUBLIC int req_getdents( u64_t pos, char *buf, size_t size, - u64_t *new_pos + u64_t *new_pos, + int direct ) { int r; message m; cp_grant_id_t grant_id; - - grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, size, CPF_WRITE); + + if (direct) { + grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, size, + CPF_WRITE); + } else { + grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, size, + CPF_WRITE); + } + if (grant_id < 0) - panic("req_getdents: cpf_grant_magic failed: %d", grant_id); + panic("req_getdents: cpf_grant_direct/cpf_grant_magic failed: %d", + grant_id); m.m_type = REQ_GETDENTS; m.REQ_INODE_NR = inode_nr; @@ -312,7 +321,6 @@ PUBLIC int req_getdents( return(r); } - /*===========================================================================* * req_inhibread * *===========================================================================*/ @@ -373,7 +381,8 @@ PUBLIC int req_lookup( uid_t uid, gid_t gid, int flags, - lookup_res_t *res + lookup_res_t *res, + struct fproc *rfp ) { int r; @@ -396,16 +405,16 @@ PUBLIC int req_lookup( m.REQ_DIR_INO = dir_ino; m.REQ_ROOT_INO = root_ino; - if(fp->fp_ngroups > 0) { /* Is the process member of multiple groups? */ + if(rfp->fp_ngroups > 0) { /* Is the process member of multiple groups? */ /* In that case the FS has to copy the uid/gid credentials */ int i; /* Set credentials */ - credentials.vu_uid = fp->fp_effuid; - credentials.vu_gid = fp->fp_effgid; - credentials.vu_ngroups = fp->fp_ngroups; - for (i = 0; i < fp->fp_ngroups; i++) - credentials.vu_sgroups[i] = fp->fp_sgroups[i]; + credentials.vu_uid = rfp->fp_effuid; + credentials.vu_gid = rfp->fp_effgid; + credentials.vu_ngroups = rfp->fp_ngroups; + for (i = 0; i < rfp->fp_ngroups; i++) + credentials.vu_sgroups[i] = rfp->fp_sgroups[i]; grant_id2 = cpf_grant_direct(fs_e, (vir_bytes) &credentials, sizeof(credentials), CPF_READ); @@ -427,7 +436,7 @@ PUBLIC int req_lookup( /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); - if(fp->fp_ngroups > 0) cpf_revoke(grant_id2); + if(rfp->fp_ngroups > 0) cpf_revoke(grant_id2); /* Fill in response according to the return value */ res->fs_e = m.m_source; @@ -653,18 +662,24 @@ int count; /*===========================================================================* * req_rdlink * *===========================================================================*/ -PUBLIC int req_rdlink(fs_e, inode_nr, who_e, buf, len) +PUBLIC int req_rdlink(fs_e, inode_nr, who_e, buf, len, direct) endpoint_t fs_e; ino_t inode_nr; endpoint_t who_e; char *buf; size_t len; +int direct; /* set to 1 to use direct grants instead of magic grants */ { message m; int r; cp_grant_id_t grant_id; - grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, len, CPF_WRITE); + if (direct) { + grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, len, CPF_WRITE); + } else { + grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, len, + CPF_WRITE); + } if(grant_id == -1) panic("req_rdlink: cpf_grant_magic failed"); diff --git a/servers/vfs/stadir.c b/servers/vfs/stadir.c index 3805f63db..55d80c290 100644 --- a/servers/vfs/stadir.c +++ b/servers/vfs/stadir.c @@ -80,7 +80,7 @@ int len; /* length of the directory name string */ /* Try to open the directory */ if (fetch_name(name_ptr, len, M3) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); return change_into(iip, vp); } @@ -123,7 +123,7 @@ PUBLIC int do_stat() struct vnode *vp; if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); r = req_stat(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, 0); put_vnode(vp); @@ -181,7 +181,7 @@ PUBLIC int do_statvfs() struct vnode *vp; if (fetch_name(m_in.STATVFS_NAME, m_in.STATVFS_LEN, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); r = req_statvfs(vp->v_fs_e, who_e, m_in.STATVFS_BUF); put_vnode(vp); @@ -214,7 +214,7 @@ PUBLIC int do_lstat() int r; if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_RET_SYMLINK)) == NULL) return(err_code); + if ((vp = eat_path(PATH_RET_SYMLINK, fp)) == NULL) return(err_code); r = req_stat(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, 0); put_vnode(vp); diff --git a/servers/vfs/table.c b/servers/vfs/table.c index 2c7c3e413..c46a04cca 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -133,3 +133,13 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = { /* This should not fail with "array size is negative": */ extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1]; +PUBLIC _PROTOTYPE (int (*pfs_call_vec[]), (void) ) = { + + no_sys, /* 0 */ + do_check_perms, /* 1 */ + do_verify_fd, /* 2 */ + do_set_filp, /* 3 */ + do_copy_filp, /* 4 */ + do_put_filp, /* 5 */ + do_cancel_fd /* 6 */ +}; diff --git a/servers/vfs/time.c b/servers/vfs/time.c index cf279ddac..749581cba 100644 --- a/servers/vfs/time.c +++ b/servers/vfs/time.c @@ -32,7 +32,7 @@ PUBLIC int do_utime() /* Temporarily open the file */ if (fetch_name(m_in.utime_file, len, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); /* Only the owner of a file or the super user can change its name. */ r = OK; diff --git a/servers/vfs/utility.c b/servers/vfs/utility.c index 296fe1bee..0c99b8ef0 100644 --- a/servers/vfs/utility.c +++ b/servers/vfs/utility.c @@ -8,6 +8,7 @@ * panic: something awful has occurred; MINIX cannot continue * conv2: do byte swapping on a 16-bit int * conv4: do byte swapping on a 32-bit long + * in_group: determines if group 'grp' is in rfp->fp_sgroups[] */ #include "fs.h" @@ -140,3 +141,19 @@ PUBLIC time_t clock_time() return( (time_t) (boottime + (uptime/system_hz))); } +/*===========================================================================* + * in_group * + *===========================================================================*/ +PUBLIC int in_group(struct fproc *rfp, gid_t grp) +{ + int i; + + for (i = 0; i < rfp->fp_ngroups; i++) { + if (rfp->fp_sgroups[i] == grp) { + return(OK); + } + } + + return(EINVAL); +} + -- 2.44.0