1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright 2015, Joyent, Inc.
  27  */
  28 
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <unistd.h>
  32 #include <fcntl.h>
  33 #include <string.h>
  34 #include <limits.h>
  35 #include <sys/secflags.h>
  36 
  37 #include "Pcontrol.h"
  38 
  39 /*
  40  * These several routines simply get the indicated /proc structures
  41  * for a process identified by process ID.  They are convenience
  42  * functions for one-time operations.  They do the mechanics of
  43  * open() / read() / close() of the necessary /proc files so the
  44  * caller's code can look relatively less cluttered.
  45  */
  46 
  47 /*
  48  * 'ngroups' is the number of supplementary group entries allocated in
  49  * the caller's cred structure.  It should equal zero or one unless extra
  50  * space has been allocated for the group list by the caller, like this:
  51  *    credp = malloc(sizeof (prcred_t) + (ngroups - 1) * sizeof (gid_t));
  52  */
  53 int
  54 proc_get_cred(pid_t pid, prcred_t *credp, int ngroups)
  55 {
  56         char fname[PATH_MAX];
  57         int fd;
  58         int rv = -1;
  59         ssize_t minsize = sizeof (*credp) - sizeof (gid_t);
  60         size_t size = minsize + ngroups * sizeof (gid_t);
  61 
  62         (void) snprintf(fname, sizeof (fname), "%s/%d/cred",
  63             procfs_path, (int)pid);
  64         if ((fd = open(fname, O_RDONLY)) >= 0) {
  65                 if (read(fd, credp, size) >= minsize)
  66                         rv = 0;
  67                 (void) close(fd);
  68         }
  69         return (rv);
  70 }
  71 
  72 int
  73 proc_get_secflags(pid_t pid, prsecflags_t **psf)
  74 {
  75         char fname[PATH_MAX];
  76         int fd;
  77         int rv = -1;
  78 
  79         if ((*psf = calloc(1, sizeof (prsecflags_t))) == NULL)
  80                 return (-1);
  81 
  82         (void) snprintf(fname, sizeof (fname), "%s/%d/secflags",
  83             procfs_path, (int)pid);
  84         if ((fd = open(fname, O_RDONLY)) >= 0) {
  85                 if (read(fd, *psf, sizeof (prsecflags_t)) ==
  86                     sizeof (prsecflags_t))
  87                         rv = 0;
  88                 (void) close(fd);
  89         }
  90         return (rv);
  91 }
  92 
  93 void
  94 proc_free_priv(prpriv_t *prv)
  95 {
  96         free(prv);
  97 }
  98 
  99 /*
 100  * Malloc and return a properly sized structure.
 101  */
 102 prpriv_t *
 103 proc_get_priv(pid_t pid)
 104 {
 105         char fname[PATH_MAX];
 106         int fd;
 107         struct stat statb;
 108         prpriv_t *rv = NULL;
 109 
 110         (void) snprintf(fname, sizeof (fname), "%s/%d/priv",
 111             procfs_path, (int)pid);
 112         if ((fd = open(fname, O_RDONLY)) >= 0) {
 113                 if (fstat(fd, &statb) != 0 ||
 114                     (rv = malloc(statb.st_size)) == NULL ||
 115                     read(fd, rv, statb.st_size) != statb.st_size) {
 116                         free(rv);
 117                         rv = NULL;
 118                 }
 119                 (void) close(fd);
 120         }
 121         return (rv);
 122 }
 123 
 124 #if defined(__i386) || defined(__amd64)
 125 /*
 126  * Fill in a pointer to a process LDT structure.
 127  * The caller provides a buffer of size 'nldt * sizeof (struct ssd)';
 128  * If pldt == NULL or nldt == 0, we return the number of existing LDT entries.
 129  * Otherwise we return the actual number of LDT entries fetched (<= nldt).
 130  */
 131 int
 132 proc_get_ldt(pid_t pid, struct ssd *pldt, int nldt)
 133 {
 134         char fname[PATH_MAX];
 135         int fd;
 136         struct stat statb;
 137         size_t size;
 138         ssize_t ssize;
 139 
 140         (void) snprintf(fname, sizeof (fname), "%s/%d/ldt",
 141             procfs_path, (int)pid);
 142         if ((fd = open(fname, O_RDONLY)) < 0)
 143                 return (-1);
 144 
 145         if (pldt == NULL || nldt == 0) {
 146                 nldt = 0;
 147                 if (fstat(fd, &statb) == 0)
 148                         nldt = statb.st_size / sizeof (struct ssd);
 149                 (void) close(fd);
 150                 return (nldt);
 151         }
 152 
 153         size = nldt * sizeof (struct ssd);
 154         if ((ssize = read(fd, pldt, size)) < 0)
 155                 nldt = -1;
 156         else
 157                 nldt = ssize / sizeof (struct ssd);
 158 
 159         (void) close(fd);
 160         return (nldt);
 161 }
 162 #endif  /* __i386 || __amd64 */
 163 
 164 int
 165 proc_get_psinfo(pid_t pid, psinfo_t *psp)
 166 {
 167         char fname[PATH_MAX];
 168         int fd;
 169         int rv = -1;
 170 
 171         (void) snprintf(fname, sizeof (fname), "%s/%d/psinfo",
 172             procfs_path, (int)pid);
 173         if ((fd = open(fname, O_RDONLY)) >= 0) {
 174                 if (read(fd, psp, sizeof (*psp)) == sizeof (*psp))
 175                         rv = 0;
 176                 (void) close(fd);
 177         }
 178         return (rv);
 179 }
 180 
 181 int
 182 proc_get_status(pid_t pid, pstatus_t *psp)
 183 {
 184         char fname[PATH_MAX];
 185         int fd;
 186         int rv = -1;
 187 
 188         (void) snprintf(fname, sizeof (fname), "%s/%d/status",
 189             procfs_path, (int)pid);
 190         if ((fd = open(fname, O_RDONLY)) >= 0) {
 191                 if (read(fd, psp, sizeof (*psp)) == sizeof (*psp))
 192                         rv = 0;
 193                 (void) close(fd);
 194         }
 195         return (rv);
 196 }
 197 
 198 /*
 199  * Get the process's aux vector.
 200  * 'naux' is the number of aux entries in the caller's buffer.
 201  * We return the number of aux entries actually fetched from
 202  * the process (less than or equal to 'naux') or -1 on failure.
 203  */
 204 int
 205 proc_get_auxv(pid_t pid, auxv_t *pauxv, int naux)
 206 {
 207         char fname[PATH_MAX];
 208         int fd;
 209         int rv = -1;
 210 
 211         (void) snprintf(fname, sizeof (fname), "%s/%d/auxv",
 212             procfs_path, (int)pid);
 213         if ((fd = open(fname, O_RDONLY)) >= 0) {
 214                 if ((rv = read(fd, pauxv, naux * sizeof (auxv_t))) >= 0)
 215                         rv /= sizeof (auxv_t);
 216                 (void) close(fd);
 217         }
 218         return (rv);
 219 }