Exemple #1
0
int steal_cleanup_child(struct steal_pty_state *steal) {
    if (ptrace_memcpy_to_child(&steal->child,
                               steal->child_scratch,
                               "/dev/null", sizeof("/dev/null"))) {
        return steal->child.error;
    }

    int nullfd = do_syscall(&steal->child, openat, -1, steal->child_scratch, O_RDWR, 0, 0, 0);
    if (nullfd < 0) {
        return steal->child.error;
    }

    int i;
    for (i = 0; i < steal->master_fds.n; ++i) {
        do_dup2(&steal->child, nullfd, steal->master_fds.fds[i]);
    }

    do_syscall(&steal->child, close, nullfd, 0, 0, 0, 0, 0);
    do_syscall(&steal->child, close, steal->child_fd, 0, 0, 0, 0, 0);

    steal->child_fd = 0;

    ptrace_restore_regs(&steal->child);

    ptrace_detach_child(&steal->child);
    ptrace_wait(&steal->child);
    return 0;
}
Exemple #2
0
static int sys_dup2(const dup2_args_t *arg)
{
    dup2_args_t             kern_args;
    int                     err;
    
    if ((err = copy_from_user(&kern_args, arg, sizeof(kern_args))) < 0) {
        curthr->kt_errno = -err;
        return -1;
    }
    
    if ((err = do_dup2(kern_args.ofd, kern_args.nfd)) < 0) {
        curthr->kt_errno = -err;
        return -1;
    } else return err;
}
Exemple #3
0
int attach_child(pid_t pid, const char *pty, int force_stdio) {
    struct ptrace_child child;
    child_addr_t scratch_page = -1;
    int *child_tty_fds = NULL, n_fds, child_fd, statfd = -1;
    int i;
    int err = 0;
    long page_size = sysconf(_SC_PAGE_SIZE);
#ifdef __linux__
    char stat_path[PATH_MAX];
#endif

    if ((err = check_pgroup(pid))) {
        return err;
    }

    if ((err = preflight_check(pid))) {
        return err;
    }

    debug("Using tty: %s", pty);

    if ((err = copy_tty_state(pid, pty))) {
        if (err == ENOTTY && !force_stdio) {
            error("Target is not connected to a terminal.\n"
                  "    Use -s to force attaching anyways.");
            return err;
        }
    }

#ifdef __linux__
    snprintf(stat_path, sizeof stat_path, "/proc/%d/stat", pid);
    statfd = open(stat_path, O_RDONLY);
    if (statfd < 0) {
        error("Unable to open %s: %s", stat_path, strerror(errno));
        return -statfd;
    }
#endif

    kill(pid, SIGTSTP);
    wait_for_stop(pid, statfd);

    if ((err = grab_pid(pid, &child, &scratch_page))) {
        goto out_cont;
    }

    if (force_stdio) {
        child_tty_fds = malloc(3 * sizeof(int));
        if (!child_tty_fds) {
            err = ENOMEM;
            goto out_unmap;
        }
        n_fds = 3;
        child_tty_fds[0] = 0;
        child_tty_fds[1] = 1;
        child_tty_fds[2] = 2;
    } else {
        child_tty_fds = get_child_tty_fds(&child, statfd, &n_fds);
        if (!child_tty_fds) {
            err = child.error;
            goto out_unmap;
        }
    }

    if (ptrace_memcpy_to_child(&child, scratch_page, pty, strlen(pty) + 1)) {
        err = child.error;
        error("Unable to memcpy the pty path to child.");
        goto out_free_fds;
    }

    child_fd = do_syscall(&child, openat,
                          -1, scratch_page, O_RDWR | O_NOCTTY,
                          0, 0, 0);
    if (child_fd < 0) {
        err = child_fd;
        error("Unable to open the tty in the child.");
        goto out_free_fds;
    }

    debug("Opened the new tty in the child: %d", child_fd);

    err = ignore_hup(&child, scratch_page);
    if (err < 0)
        goto out_close;

    err = do_syscall(&child, getsid, 0, 0, 0, 0, 0, 0);
    if (err != child.pid) {
        debug("Target is not a session leader, attempting to setsid.");
        err = do_setsid(&child);
    } else {
        do_syscall(&child, ioctl, child_tty_fds[0], TIOCNOTTY, 0, 0, 0, 0);
    }
    if (err < 0)
        goto out_close;

    err = do_syscall(&child, ioctl, child_fd, TIOCSCTTY, 1, 0, 0, 0);
    if (err != 0) { /* Seems to be returning >0 for error */
        error("Unable to set controlling terminal: %s", strerror(err));
        goto out_close;
    }

    debug("Set the controlling tty");

    for (i = 0; i < n_fds; i++) {
        err = do_dup2(&child, child_fd, child_tty_fds[i]);
        if (err < 0)
            error("Problem moving child fd number %d to new tty: %s", child_tty_fds[i], strerror(errno));
    }


    err = 0;

out_close:
    do_syscall(&child, close, child_fd, 0, 0, 0, 0, 0);
out_free_fds:
    free(child_tty_fds);

out_unmap:
    do_unmap(&child, scratch_page, page_size);

    ptrace_restore_regs(&child);
    ptrace_detach_child(&child);

    if (err == 0) {
        kill(child.pid, SIGSTOP);
        wait_for_stop(child.pid, statfd);
    }
    kill(child.pid, SIGWINCH);
out_cont:
    kill(child.pid, SIGCONT);
#ifdef __linux__
    close(statfd);
#endif

    return err < 0 ? -err : err;
}
Exemple #4
0
int vfs_selftest(kshell_t *kshell, int argc, char **argv)
{
  int fd1,fd2;
  char *y="/ab/fil";
  char x[2];
  int err;
  do_mkdir("/ab");
  do_mknod("/ab/new", S_IFCHR,MKDEVID(1,1));
  fd1=do_open("/ab/new",2);
  fd2=do_dup2(fd1,NFILES+1);
  if(fd2<0)
    {
      dbg(DBG_PRINT,"File not created\n");
    }
  do_mknod("/ab/notmade",4096,MKDEVID(1,1));
  do_mknod("/ab/new/not",S_IFCHR,MKDEVID(1,1));
  do_mknod("/ab/new", S_IFCHR,MKDEVID(1,1));
  do_mknod("", S_IFCHR,MKDEVID(1,1));

  /*do_close(fd1);*/
    for(fd2=1;fd2<35;fd2++)
    {
      sprintf(x,"%d",fd2);
      strcat(y,x);
      do_mknod(y,S_IFCHR,MKDEVID(1,0));
      err=do_open(y,2);
      if(err<0)
	{
	  break;
	}
      if(fd2<10)
	{
	  y[strlen(y)-1]='\0';
	}
      else
	{
	   y[strlen(y)-2]='\0';
	}
      
    }
do_mknod("/ab/new1", S_IFCHR,MKDEVID(1,1));
 err=do_dup(fd1);
  do_unlink("/ab/new/ab");
 do_unlink("/ab/new");
 do_close(fd1);
 for(fd2=NFILES-1;fd2>0;fd2--)
   {
     err=do_close(fd2);
     sprintf(x,"%d",fd2);
      strcat(y,x);
      do_unlink(y);  
      if(err<0)
	{
	  break;
	}
      if(fd2<10)
	{
	  y[strlen(y)-1]='\0';
	}
      else
	{
	   y[strlen(y)-2]='\0';
	}
   }
 do_link("/a","/dev");
 do_link("/dev","/a");
 do_link("/dev","/a");
 do_rmdir("/a");
 /* mkdir("/k");
    do_link("/ab","/k");*/
  do_rmdir("/ab");
  /*do_rmdir("/k");*/

 /*GS: SELF TESTS*/
    dbg(DBG_PRINT,"\n*************************************************************\n");
    dbg(DBG_PRINT,"\n\n\n\n(GRADING2C)(kmain.c)(selftest_proc_run) selftests begin\n");

    int retVal = 0;
    int i = 0;

    /* 1. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_stat)  strlen too long, return -ENAMETOOLONG\n");*/
    char longPath[1024 + 1] = {0};
    for(i = 0; i < 1025; i++)
        longPath[i] = 'a';
    struct stat buf;
    retVal = do_stat(longPath, &buf);
    retVal=do_chdir(longPath);

    /*2. dbg(DBG_PRINT, "(GRADING2B) ENOTDIR or ENOENT\n");*/
    retVal = do_stat("", &buf);

    /*3. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_getdent) Invalid file descriptor fd, return -EBADF\n");*/
    struct dirent dirp;
    retVal = do_getdent(-1, &dirp);

    /*4. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_getdent) Invalid file descriptor fd, return -EBADF\n");*/
    retVal = do_getdent(1, &dirp);

    /*5. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_getdent) File descriptor does not refer to a directory, return -ENOTDIR\n");*/
    do_mknod("/./file", S_IFCHR,MKDEVID(1,1));
    fd1 = do_open("/./file",2);
    retVal = do_getdent(fd1, &dirp);

    do_unlink("/./file");
    do_close(fd1);
    /*6. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_rename) Both are valid names \n");*/
    /* and */
    /*7. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_rename) error do_link, return error\n"); \n");*/
    retVal = do_rename("/./aaa", "/./bbb");


    dbg(DBG_PRINT,"\n\nretVal=%d",retVal);
    dbg(DBG_PRINT,"\n*************************************************************\n");
  return 0;
}
Exemple #5
0
void *extra_self_tests(int arg1, void *arg2)
{
        /* creating /test1/test2/ directories */
   dbg(DBG_ERROR | DBG_VFS,"TEST: Creating directories\n");        
                do_mkdir("dir");
                do_mkdir("dir/dir1");
                do_mkdir("dir/dir2");
                do_mkdir("dir/dir3");             
                do_mkdir("dir/dir4");  
   dbg(DBG_ERROR | DBG_VFS,"TEST: Directories are created\n");
        int fd;
        char *file2buf="File 2 write only test case";
        char *file1buf="Testing file_1 for write operation";
        char readbuf[150];

   dbg(DBG_ERROR | DBG_VFS,"TEST: Change directory to dir/dir1\n");
        do_chdir("dir/dir1");

        /* file1.txt creation with O_CREAT|O_WRONLY  flag*/
   dbg(DBG_ERROR | DBG_VFS,"TEST: Create file1.txt with O_CREAT|O_WRONLY flag in directory dir/dir1\n");
        fd = do_open("file1.txt", O_CREAT|O_WRONLY);
        do_write(fd, file1buf, strlen(file1buf));
        do_close(fd);
        
        /* file2.txt creation with O_CREAT|O_RDONLY  flag*/
   dbg(DBG_ERROR | DBG_VFS,"TEST: Change directory to dir/dir2\n");
        do_chdir("/dir/dir2");
        
   dbg(DBG_ERROR | DBG_VFS,"TEST: Create file2.txt with O_CREAT | O_RDONLY flag  in directory dir/dir2\n");
        fd = do_open("file2.txt", O_CREAT | O_RDONLY);
        do_close(fd);
        
         /* Write into file2.txt using O_WRONLY flag*/
   dbg(DBG_ERROR | DBG_VFS,"TEST: Write into file2.txt with O_WRONLY flag in directory dir/dir2\n");  
        fd = do_open("file2.txt", O_WRONLY);
        do_write(fd, file2buf, strlen(file2buf));
        do_close(fd);
   dbg(DBG_ERROR | DBG_VFS,"TEST: written chars: \"%s\" in file2.txt\n",file2buf);
   
        char *appendbuf=" Appending for O_WRONLY|O_APPEND mode";
      /* Append into file2.txt using  O_WRONLY|O_APPEND  flag*/
   dbg(DBG_ERROR | DBG_VFS,"TEST: Append into file2.txt with O_WRONLY|O_APPEND flag in directory dir/dir2\n");  
        fd = do_open("file2.txt", O_WRONLY|O_APPEND);
        do_write(fd, appendbuf, strlen(appendbuf));
        do_close(fd);
   dbg(DBG_ERROR | DBG_VFS,"TEST: Appending chars: \"%s\" in file2.txt\n",appendbuf);
        fd = do_open("file2.txt", O_RDONLY);
        memset(readbuf,0,sizeof(char)*150);
        do_read(fd,readbuf,strlen(file2buf)+strlen(appendbuf));
   dbg(DBG_ERROR | DBG_VFS,"TEST: After Appending text in file2.txt is: \"%s\" \n",readbuf);

        char *append2buf=" Appending for O_RDWR|O_APPEND mode in file2";
      /* Append into file2.txt using  O_RDWR|O_APPEND  flag*/
   dbg(DBG_ERROR | DBG_VFS,"TEST: Append into file2.txt with O_RDWR|O_APPEND flag in directory dir/dir2\n");  
        fd = do_open("file2.txt", O_RDWR|O_APPEND);
        do_write(fd, append2buf, strlen(append2buf));
        do_close(fd);
   dbg(DBG_ERROR | DBG_VFS,"TEST: Appending chars: \"%s\" in file2.txt\n",append2buf);
        fd = do_open("file2.txt", O_RDONLY);
        memset(readbuf,0,sizeof(char)*150);
        do_read(fd,readbuf,strlen(file2buf)+strlen(append2buf)+strlen(appendbuf));
   dbg(DBG_ERROR | DBG_VFS,"TEST: After Appending text in file2.txt is: \"%s\" \n",readbuf);

   dbg(DBG_ERROR | DBG_VFS,"TEST:Linking Source directory => /dir/dir2, Destination directory => /dir/linkofdir2 \n");
        do_chdir("/");
        do_link("dir/dir2","dir/linkofdir2");

   dbg(DBG_ERROR | DBG_VFS,"TEST:Linking Source file => /dir/dir1/file1.txt, to the Destination => /dir/linkoffile1 \n");
        do_link("dir/dir1/file1.txt","dir/linkoffile1");
        
   dbg(DBG_ERROR | DBG_VFS,"TEST: Renaming directory from dir/dir3 to dir/renamed \n");
        do_rename("dir/dir3","dir/renameddir3");

   dbg(DBG_ERROR | DBG_VFS,"TEST: Renaming file from dir/dir1/file1.txt to dir/dir1/renamedfile1.txt \n");
        do_rename("dir/dir1/file1.txt","dir/dir1/renamedfile1.txt");

   dbg(DBG_ERROR | DBG_VFS,"TEST: Removing directory dir/dir4 \n");
        do_rmdir("dir/dir4");

   dbg(DBG_ERROR | DBG_VFS,"TEST: reading 18 chars from file: /dir/linkoffile2 which is hard link of /dir/dir2/file2.txt \n");
        fd = do_open("dir/linkoffile2", O_RDONLY);
        memset(readbuf,0,sizeof(char)*150);
        do_close(fd);
   dbg(DBG_ERROR | DBG_VFS,"TEST: read 18 chars: \"%s\" from file: /dir/linkoffile1\n",readbuf);
   
   dbg(DBG_ERROR | DBG_VFS,"TEST: reading file using lseek function on  /dir/linkoffile2 which is hard link of /dir/dir2/file2.txt \n");
        memset(readbuf,0,sizeof(char)*150);
        fd = do_open("dir/linkoffile2", O_RDONLY);
        do_lseek(fd,-19,2);
        do_read(fd,readbuf,19);
        do_close(fd);
   dbg(DBG_ERROR | DBG_VFS,"TEST: read chars: \"%s\" using lseek from file: /dir/linkoffile1\n",readbuf);
   
   dbg(DBG_ERROR | DBG_VFS,"TEST: creating a duplicate file descriptor of file: /dir/dir2/file2.txt using do_dup()\n");
        fd = do_open("/dir/dir2/file2.txt", O_RDONLY);
    int fd2= do_dup(fd);
   dbg(DBG_ERROR | DBG_VFS,"TEST: duplicate file descriptor is :\"%d\" of file: /dir/dir2/file2.txt \n",fd2);
             do_close(fd);        do_close(fd2);
                     
   dbg(DBG_ERROR | DBG_VFS,"TEST: creating a duplicate file descriptor of file: /dir/dir2/file2.txt using do_dup2()\n");    
        fd = do_open("/dir/dir2/file2.txt", O_RDONLY);
        fd2= do_dup2(fd,20);
   dbg(DBG_ERROR | DBG_VFS,"TEST: custom file descriptor is :\"%d\" of file: /dir/dir2/file2.txt \n",fd2);
                do_close(fd);        do_close(fd2);

        /*  Testing stat
        struct *statbuf;
   dbg(DBG_ERROR | DBG_VFS,"TEST: Testing the stat system call for directory dir\n");
        do_stat("dir",statbuf);
   dbg(DBG_ERROR | DBG_VFS,"TEST: Output of stat for directory dir is :\"%s\" \n",statbuf);*/

        shellTest(); 

     return NULL;
}
Exemple #6
0
void
impl_exit_start(void)
{
    if( is_exiting == TRUE )
    {
        return;
    }

    /* We are now exiting.
     * After this point, all calls to various sockets,
     * (i.e. accept(), listen(), etc. will result in stalls.
     * We are just waiting until existing connections have 
     * finished and then we will be either exec()'ing a new
     * version or exiting this process. */
    is_exiting = TRUE;

    /* Get ready to restart.
     * We only proceed with actual restart actions
     * if we are the master process, otherwise we will
     * simply prepare to shutdown cleanly once all the
     * current active connections have finished. */
    if( master_pid == getpid() )
    {
        pid_t child;
        DEBUG("Exit started -- this is the master.");

        /* Unlink files (e.g. pidfile). */
        if( to_unlink != NULL && strlen(to_unlink) > 0 )
        {
            DEBUG("Unlinking '%s'...", to_unlink);
            unlink(to_unlink);
        }

        /* Neuter this process. */
        for( int fd = 0; fd < fd_limit(); fd += 1 )
        {
            fdinfo_t* info = fd_lookup(fd);
            if( exit_strategy == FORK &&
                info != NULL && info->type == SAVED )
            {
                /* Close initial files. Since these
                 * are now passed on to the child, we
                 * ensure that the parent won't mess 
                 * with them anymore. Note that we still
                 * have a copy as all SAVED descriptors. */
                if( info->saved.fd == 2 )
                {
                    /* We treat stderr special.
                     * Assuming logging will go here, we
                     * allow the parent process to continue
                     * writing to this file (and hope that
                     * it's open in APPEND mode, etc.). */
                    continue;
                }
                int nullfd = open("/dev/null", O_RDWR);
                do_dup2(nullfd, info->saved.fd);
                libc.close(nullfd);
            }
            if( info != NULL &&
                info->type == BOUND && !info->bound.is_ghost )
            {
                /* Change BOUND sockets to dummy sockets.
                 * This will allow select() and poll() to
                 * operate as you expect, and never give
                 * back new clients. */
                int newfd = do_dup(fd);
                if( newfd >= 0 )
                {
                    int dummy_server = impl_dummy_server();
                    if( dummy_server >= 0 )
                    {
                        /* Remove the descriptor in any epoll FDs. */
                        for( int efd = 0; efd < fd_limit(); efd += 1 )
                        {
                            fdinfo_t* einfo = fd_lookup(efd);
                            if( einfo != NULL && einfo->type == EPOLL )
                            {
                                struct epoll_event no_event;
                                epoll_ctl(efd, EPOLL_CTL_DEL, fd, &no_event);
                            }
                        }

                        info->bound.is_ghost = 1;
                        do_dup2(dummy_server, fd);
                        DEBUG("Replaced FD %d with dummy.", fd);
                    }
                    else
                    {
                        do_close(newfd);
                    }
                }
            }
        }

        switch( exit_strategy )
        {
            case FORK:
                /* Start the child process.
                 * We will exit gracefully when the tracked
                 * connection count reaches zero. */
                DEBUG("Exit strategy is fork.");
                child = libc.fork();
                if( child == 0 )
                {
                    DEBUG("I'm the child.");
                    impl_exec();
                }
                else
                {
                    DEBUG("I'm the parent.");
                }
                break;

            case EXEC:
                /* Nothing necessary beyond the above. */
                DEBUG("Exit strategy is exec.");
                break;
        }
    }
    else
    {
        /* Force our strategy to fork, though we haven't forked.
         * This will basically just have this process exit cleanly
         * once all the current active connections have finished. */
        DEBUG("Exit started -- this is the child.");
        exit_strategy = FORK;
    }
}
Exemple #7
0
static int
do_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
    fdinfo_t *info = NULL;
    int rval = -1;

    if( sockfd < 0 )
    {
        errno = EINVAL;
        return -1;
    }

    /* At this point, we can reasonably assume
     * the program has started up and has installed
     * whatever signal handlers it wants. We check
     * that our own signal handler is installed.
     * If the user doesn't want us to override the
     * built-in signal handlers, they shouldn't use
     * huptime. */
    impl_install_sighandlers();

    DEBUG("do_bind(%d, ...) ...", sockfd);
    L();

    /* See if this socket already exists. */
    for( int fd = 0; fd < fd_limit(); fd += 1 )
    {
        fdinfo_t *info = fd_lookup(fd);
        if( info != NULL && 
            info->type == BOUND &&
            info->bound.addrlen == addrlen &&
            !memcmp(addr, (void*)info->bound.addr, addrlen) )
        {
            DEBUG("Found ghost %d, cloning...", fd);

            /* Give back a duplicate of this one. */
            int rval = do_dup2(fd, sockfd);
            if( rval < 0 )
            {
                /* Dup2 failed? */
                DEBUG("Failed.");
                continue;
            }
            if( info->bound.is_ghost )
            {
                /* Close the original (not needed). */
                info->bound.is_ghost = 0;
                do_close(fd);
            }

            /* Success. */
            U();
            DEBUG("do_bind(%d, ...) => 0 (ghosted)", sockfd);
            return 0;
        }
    }

#ifdef SO_REUSEPORT
    /* Multi mode? Set socket options. */
    if( multi_mode == TRUE )
    {
        int optval = 1;
        if( setsockopt(sockfd,
                       SOL_SOCKET,
                       SO_REUSEPORT,
                       &optval,
                       sizeof(optval)) < 0 )
        {
            U();
            DEBUG("do_bind(%d, ...) => -1 (no multi?)", sockfd);
            return -1;
        }

        DEBUG("Multi mode enabled.");
    }
#endif

    /* Try a real bind. */
    info = alloc_info(BOUND);
    if( info == NULL )
    {
        U();
        DEBUG("do_bind(%d, ...) => -1 (alloc error?)", sockfd);
        return -1;
    }
    rval = libc.bind(sockfd, addr, addrlen);
    if( rval < 0 )
    {
        dec_ref(info);
        U();
        DEBUG("do_bind(%d, ...) => %d (error)", sockfd, rval);
        return rval;
    }

    /* Ensure that this socket is non-blocking,
     * this is because we override the behavior
     * for accept() and we require non-blocking
     * behavior. We deal with the consequences. */
    rval = fcntl(sockfd, F_SETFL, O_NONBLOCK);
    if( rval < 0 )
    {
        dec_ref(info);
        U();
        DEBUG("do_bind(%d, ...) => %d (fcntl error)", sockfd, rval);
        return -1;
    }

    /* Save a refresh bound socket info. */
    info->bound.stub_listened = 0;
    info->bound.real_listened = 0;
    info->bound.addr = (struct sockaddr*)malloc(addrlen);
    info->bound.addrlen = addrlen;
    memcpy((void*)info->bound.addr, (void*)addr, addrlen);
    fd_save(sockfd, info);

    /* Success. */
    U();
    DEBUG("do_bind(%d, ...) => %d", sockfd, rval);
    return rval;
}
int
sys_dup3(struct tcb *tcp)
{
	return do_dup2(tcp, 2);
}
int
sys_dup2(struct tcb *tcp)
{
	return do_dup2(tcp, -1);
}