"Fossies" - the Fresh Open Source Software Archive

Member "reptyr-reptyr-0.8.0/platform/freebsd/freebsd.c" (29 Sep 2020, 9113 Bytes) of package /linux/privat/reptyr-reptyr-0.8.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "freebsd.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.7.0_vs_0.8.0.

    1 /*
    2  * Copyright (C) 2014 Christian Heckendorf <heckendorfc@gmail.com>
    3  *
    4  * Permission is hereby granted, free of charge, to any person obtaining a copy
    5  * of this software and associated documentation files (the "Software"), to deal
    6  * in the Software without restriction, including without limitation the rights
    7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    8  * copies of the Software, and to permit persons to whom the Software is
    9  * furnished to do so, subject to the following conditions:
   10  *
   11  * The above copyright notice and this permission notice shall be included in
   12  * all copies or substantial portions of the Software.
   13  *
   14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   20  * THE SOFTWARE.
   21  */
   22 
   23 #ifdef __FreeBSD__
   24 
   25 #include "freebsd.h"
   26 #include "../platform.h"
   27 #include "../../reptyr.h"
   28 #include "../../ptrace.h"
   29 
   30 void check_ptrace_scope(void) {
   31 }
   32 
   33 int check_pgroup(pid_t target) {
   34     struct procstat *procstat;
   35     struct kinfo_proc *kp;
   36     pid_t pg;
   37     unsigned int cnt;
   38 
   39     pg = getpgid(target);
   40 
   41     procstat = procstat_open_sysctl();
   42     cnt = 0;
   43     kp = procstat_getprocs(procstat, KERN_PROC_PGRP, pg, &cnt);
   44     procstat_freeprocs(procstat, kp);
   45     procstat_close(procstat);
   46 
   47     if (cnt > 1) {
   48         error("Process %d shares a process group with %d other processes. Unable to attach.\n", target, cnt - 1);
   49         return EINVAL;
   50     }
   51 
   52     return 0;
   53 }
   54 
   55 int check_proc_stopped(pid_t pid, int fd) {
   56     struct procstat *procstat;
   57     struct kinfo_proc *kp;
   58     int state = 0;
   59     unsigned int cnt;
   60 
   61     procstat = procstat_open_sysctl();
   62     cnt = 0;
   63     kp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt);
   64 
   65     if (cnt > 0)
   66         state = kp->ki_stat;
   67 
   68     procstat_freeprocs(procstat, kp);
   69     procstat_close(procstat);
   70 
   71     if (cnt < 1)
   72         return 1;
   73 
   74 
   75     if (state == SSTOP)
   76         return 1;
   77 
   78     return 0;
   79 }
   80 
   81 struct filestat_list* get_procfiles(pid_t pid, struct kinfo_proc **kp, struct procstat **procstat, unsigned int *cnt) {
   82     int mflg = 0; // include mmapped files
   83     (*procstat) = procstat_open_sysctl();
   84     *cnt = 0;
   85     (*kp) = procstat_getprocs(*procstat, KERN_PROC_PID, pid, cnt);
   86     if ((*kp) == NULL || *cnt < 1)
   87         return NULL;
   88 
   89     return procstat_getfiles(*procstat, *kp, mflg);
   90 }
   91 
   92 int *get_child_tty_fds(struct ptrace_child *child, int statfd, int *count) {
   93     struct filestat *fst;
   94     struct filestat_list *head;
   95     struct procstat *procstat;
   96     struct kinfo_proc *kp;
   97     unsigned int cnt;
   98     struct fd_array fds = {};
   99     struct vnstat vn;
  100     int er;
  101     char errbuf[_POSIX2_LINE_MAX];
  102 
  103     head = get_procfiles(child->pid, &kp, &procstat, &cnt);
  104 
  105     STAILQ_FOREACH(fst, head, next) {
  106         if (fst->fs_type == PS_FST_TYPE_VNODE) {
  107             er = procstat_get_vnode_info(procstat, fst, &vn, errbuf);
  108             if (er != 0) {
  109                 error("%s", errbuf);
  110                 goto out;
  111             }
  112 
  113             if (vn.vn_dev == kp->ki_tdev && fst->fs_fd >= 0) {
  114                 if (fd_array_push(&fds, fst->fs_fd) != 0) {
  115                     error("Unable to allocate memory for fd array.");
  116                     goto out;
  117                 }
  118             }
  119         }
  120     }
  121 
  122 out:
  123     procstat_freefiles(procstat, head);
  124     procstat_freeprocs(procstat, kp);
  125     procstat_close(procstat);
  126     *count = fds.n;
  127     debug("Found %d tty fds in child %d.", fds.n, child->pid);
  128     return fds.fds;
  129 }
  130 
  131 // Find the PID of the terminal emulator for `target's terminal.
  132 //
  133 // We assume that the terminal emulator is the parent of the session
  134 // leader. This is true in most cases, although in principle you can
  135 // construct situations where it is false. We should fail safe later
  136 // on if this turns out to be wrong, however.
  137 int find_terminal_emulator(struct steal_pty_state *steal) {
  138     struct procstat *procstat;
  139     struct kinfo_proc *kp;
  140     unsigned int cnt;
  141 
  142     procstat = procstat_open_sysctl();
  143     cnt = 0;
  144     kp = procstat_getprocs(procstat, KERN_PROC_PID, steal->target_stat.sid, &cnt);
  145 
  146     if (kp && cnt > 0)
  147         steal->emulator_pid = kp->ki_ppid;
  148 
  149     procstat_freeprocs(procstat, kp);
  150     procstat_close(procstat);
  151 
  152     return (cnt != 0 ? 0 : 1);
  153 }
  154 
  155 int fill_proc_stat(struct steal_pty_state *steal, struct kinfo_proc *kp) {
  156     struct proc_stat *ps = &steal->target_stat;
  157 
  158     if (strlcpy(ps->comm, kp->ki_comm, sizeof(ps->comm)) >= sizeof(ps->comm))
  159       return ENOMEM;
  160     ps->pid = kp->ki_pid;
  161     ps->ppid = kp->ki_ppid;
  162     ps->sid = kp->ki_sid;
  163     ps->pgid = kp->ki_pgid;
  164     ps->ctty = kp->ki_tdev;
  165 
  166     return 0;
  167 }
  168 
  169 int grab_uid(pid_t pid, uid_t *out) {
  170     struct procstat *procstat;
  171     struct kinfo_proc *kp;
  172     unsigned int cnt;
  173 
  174     procstat = procstat_open_sysctl();
  175     cnt = 0;
  176     kp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt);
  177 
  178     if (kp && cnt > 0)
  179         *out = kp->ki_uid;
  180     else
  181         return ESRCH;
  182     procstat_freeprocs(procstat, kp);
  183     procstat_close(procstat);
  184 
  185     return 0;
  186 }
  187 
  188 int get_terminal_state(struct steal_pty_state *steal, pid_t target) {
  189     struct procstat *procstat;
  190     struct kinfo_proc *kp;
  191     unsigned int cnt;
  192     int err = 0;
  193 
  194     procstat = procstat_open_sysctl();
  195     cnt = 0;
  196     kp = procstat_getprocs(procstat, KERN_PROC_PID, target, &cnt);
  197     if (kp == NULL || cnt < 1)
  198         goto done;
  199 
  200     if (kp->ki_tdev == NODEV) {
  201         error("Child is not connected to a pseudo-TTY. Unable to steal TTY.");
  202         err = EINVAL;
  203         goto done;
  204     }
  205 
  206     if ((err = fill_proc_stat(steal, kp)))
  207         return err;
  208 
  209     if ((err = find_terminal_emulator(steal)))
  210         return err;
  211 
  212     if ((err = grab_uid(steal->emulator_pid, &steal->emulator_uid)))
  213         return err;
  214 done:
  215     procstat_freeprocs(procstat, kp);
  216     procstat_close(procstat);
  217     return err;
  218 }
  219 
  220 int find_master_fd(struct steal_pty_state *steal) {
  221     char errbuf[_POSIX2_LINE_MAX];
  222     struct filestat *fst;
  223     struct filestat_list *head;
  224     struct procstat *procstat;
  225     struct kinfo_proc *kp;
  226     struct ptsstat pts;
  227     unsigned int cnt;
  228     int err;
  229 
  230     head = get_procfiles(steal->child.pid, &kp, &procstat, &cnt);
  231 
  232     STAILQ_FOREACH(fst, head, next) {
  233         if (fst->fs_type != PS_FST_TYPE_PTS)
  234             continue;
  235 
  236         err = procstat_get_pts_info(procstat, fst, &pts, errbuf);
  237         if (err != 0) {
  238             error("error discovering fd=%d", fst->fs_fd);
  239             continue;
  240         }
  241 
  242         if (pts.dev != steal->target_stat.ctty)
  243             continue;
  244 
  245         if (fd_array_push(&steal->master_fds, fst->fs_fd) != 0) {
  246             error("unable to allocate memory for fd array");
  247             return ENOMEM;
  248         }
  249     }
  250 
  251     procstat_freefiles(procstat, head);
  252     procstat_freeprocs(procstat, kp);
  253     procstat_close(procstat);
  254     debug("Found %d master tty fds in child %d.", steal->master_fds.n, steal->child.pid);
  255     if (steal->master_fds.n == 0)
  256         return ESRCH;
  257     return 0;
  258 }
  259 
  260 int get_pt() {
  261     return posix_openpt(O_RDWR | O_NOCTTY);
  262 }
  263 
  264 int get_process_tty_termios(pid_t pid, struct termios *tio) {
  265     int err = EINVAL;
  266     struct kinfo_proc *kp;
  267     unsigned int cnt;
  268     struct filestat_list *head;
  269     struct filestat *fst;
  270     struct procstat *procstat;
  271     int fd = -1;
  272 
  273     head = get_procfiles(pid, &kp, &procstat, &cnt);
  274 
  275     STAILQ_FOREACH(fst, head, next) {
  276         if (fst->fs_type == PS_FST_TYPE_VNODE) {
  277             if (fst->fs_path) {
  278                 fd = open(fst->fs_path, O_RDONLY);
  279                 if (fd >= 0 && isatty(fd)) {
  280                     if (tcgetattr(fd, tio) < 0) {
  281                         err = -assert_nonzero(errno);
  282                     }
  283                     else {
  284                         close(fd);
  285                         err = 0;
  286                         goto done;
  287                     }
  288                 }
  289                 close(fd);
  290             }
  291         }
  292     }
  293 
  294 done:
  295     procstat_freefiles(procstat, head);
  296     procstat_freeprocs(procstat, kp);
  297     procstat_close(procstat);
  298     return err;
  299 }
  300 
  301 void move_process_group(struct ptrace_child *child, pid_t from, pid_t to) {
  302     struct procstat *procstat;
  303     struct kinfo_proc *kp;
  304     unsigned int cnt;
  305     int i;
  306     int err;
  307 
  308     procstat = procstat_open_sysctl();
  309     cnt = 0;
  310     kp = procstat_getprocs(procstat, KERN_PROC_PGRP, from, &cnt);
  311 
  312     for (i = 0; i < cnt; i++) {
  313         debug("Change pgid for pid %d to %d", kp[i].ki_pid, to);
  314         err = do_syscall(child, setpgid, kp[i].ki_pid, to, 0, 0, 0, 0);
  315         if (err < 0)
  316             error(" failed: %s", strerror(-err));
  317     }
  318     procstat_freeprocs(procstat, kp);
  319     procstat_close(procstat);
  320 }
  321 
  322 void copy_user(struct ptrace_child *d, struct ptrace_child *s) {
  323     memcpy(&d->regs, &s->regs, sizeof(s->regs));
  324 }
  325 
  326 #endif