Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OSX: proc_pidinfo returns 0 for other user's processes

Tags:

c

macos

I need to get some information (PID, UID, GID, process name) about running processes on Mac OSX. I tried proc_pidinfo. For my own processes it works fine. However, for processes owned by other users, 0 is returned. There's no documentation for this function, but according to information found on Internet, it's supposed to return number of bytes written into provided buffer. Calling this function on other user's processes returns 0, which means that no information was provided.

Example:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <libproc.h>


int main(int argc, char *argv[])
{
    pid_t pid;
    struct proc_bsdinfo proc;

    if (argc == 2)
        pid = atoi(argv[1]);
    else
        pid = getpid();

    int st = proc_pidinfo(pid, PROC_PIDTBSDINFO, 0,
                         &proc, PROC_PIDTBSDINFO_SIZE);

    if (st != PROC_PIDTBSDINFO_SIZE) {
        fprintf(stderr, "Cannot get process info");
        return 1;
    }
    printf(" pid: %d\n", (int)proc.pbi_pid);
    printf("ppid: %d\n", (int)proc.pbi_ppid);
    printf("comm: %s\n",      proc.pbi_comm);
    printf("name: %s\n",      proc.pbi_name);
    printf(" uid: %d\n", (int)proc.pbi_uid);
    printf(" gid: %d\n", (int)proc.pbi_gid);

    return 0;
}

Running this program yields:

 $ ./pidinfo
 pid: 30519
ppid: 8434
comm: pidinfo
name: pidinfo
 uid: 501
 gid: 20
 $ ./pidinfo 1
Cannot get process info
 $ sudo ./pidinfo 1
 pid: 1
ppid: 0
comm: launchd
name: launchd
 uid: 0
 gid: 0

That's strange, because I can get all this information from ps(1). But then I checked that both ps and top on OSX are SUID binaries, which would be in line with proc_pidinfo behavior:

 $ ls -l `which ps` `which top`
-rwsr-xr-x  1 root  wheel  51008  5 maj 08:06 /bin/ps
-r-sr-xr-x  1 root  wheel  87952  5 maj 08:05 /usr/bin/top

But then, Activity Monitor works without SUID.

So, my question is, why proc_pidinfo provides information only about my own processes? Can I make it give me information about other processes? If not, how can I get this information without parsing ps(1) output?

like image 532
el.pescado - нет войне Avatar asked May 29 '16 16:05

el.pescado - нет войне


2 Answers

You can use :

int proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize);

combinated to proc_pidinfo to get many others pids informations like :

#include <unistd.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <libproc.h>
#include <mach/mach_time.h>
#include <sys/sysctl.h>
#include <mach-o/ldsyms.h>
#include <stdio.h>

void procpid(pid_t pid)
{ struct proc_bsdinfo proc;
  int st = proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &proc, PROC_PIDTBSDINFO_SIZE);
  printf("name: %s\n", proc.pbi_name);
}

void pidlist(void)
{ int bufsize = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
  pid_t pids[2 * bufsize / sizeof(pid_t)];
  bufsize = proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));
  size_t num_pids = bufsize / sizeof(pid_t);
  int i = 0;
  while (i < num_pids)
  { printf("pid[%d]::%d\n", i, pids[i]);
    procpid(pids[i]);
    printf("\n-------------------------------\n\n");
    i += 1; }}

int main(void)
{ pidlist();
  return(42); }
like image 145
limaconoob Avatar answered Nov 17 '22 09:11

limaconoob


I found that macOS Mojave (version 10.14.4) had struct proc_bsdshortinfo, which is a subset of struct proc_bsdinfo. You can get other user's processes without SUID by using it instead of struct proc_bsdinfo.

Well, I don't know from which version it is available.

edited: It is available since at least macOS 10.10.5 (Yosemite).
edited again: It may be available since Mac OS X 10.7 (Lion) because tmux uses struct proc_bsdshortinfo if __MAC_10_7 is defined. See here.

Example:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <libproc.h>

int main(int argc, char *argv[])
{
    pid_t pid;
    struct proc_bsdshortinfo proc;

    if (argc == 2)
        pid = atoi(argv[1]);
    else
        pid = getpid();

    int st = proc_pidinfo(pid, PROC_PIDT_SHORTBSDINFO, 0,
                         &proc, PROC_PIDT_SHORTBSDINFO_SIZE);

    if (st != PROC_PIDT_SHORTBSDINFO_SIZE) {
        fprintf(stderr, "Cannot get process info\n");
        return 1;
    }
    printf(" pid: %d\n", (int)proc.pbsi_pid);
    printf("ppid: %d\n", (int)proc.pbsi_ppid);
    printf("comm: %s\n",      proc.pbsi_comm);
    //printf("name: %s\n",      proc.pbsi_name);
    printf(" uid: %d\n", (int)proc.pbsi_uid);
    printf(" gid: %d\n", (int)proc.pbsi_gid);

    return 0;
}

This program prints:

$ ./pidinfo 
 pid: 3025
ppid: 250
comm: pidinfo
 uid: 501
 gid: 20
$ ./pidinfo 1
 pid: 1
ppid: 0
comm: launchd
 uid: 0
 gid: 0
like image 24
Kubo Takehiro Avatar answered Nov 17 '22 09:11

Kubo Takehiro