Hi folks,

ipcs(1) is currently installed as setgid kmem.  This isn't good for
obvious reasons.  Moreover, the information it needs is easily
exported via sysctl.  Below is a patch which adds the necessary sysctl
oids and changes ipcs(1) to use them.  I had to export msgids,
msginfo, sema, seminfo, shmsegs, and shminfo.  The *info variables
were exported via SYSCTL_STRUCT, and the rest via SYSCTL_PROC.  All
read-only by anyone.  I'm not particuarly sure it's appropriate to
export the *info variables like that--at least one of them has most
(all?) of its members already exported via SYSCTL_INT, but that would
be a pain to use in this case.  The patch preserves ipcs(1)'s ability
to operate on a saved kernel and core.  In addition, I also added a -y
command line flag that will cause it to use kvm(3) instead of
sysctl(3), even on a running system.

Comments?  Particuarly, I'd like comments on whether I exported
everything correctly.

Thanks in advance,

                                        Dima Dorfman
                                        [EMAIL PROTECTED]

Index: sys/kern/sysv_msg.c
===================================================================
RCS file: /st/src/FreeBSD/src/sys/kern/sysv_msg.c,v
retrieving revision 1.30
diff -u -r1.30 sysv_msg.c
--- sys/kern/sysv_msg.c 2001/02/21 06:39:54     1.30
+++ sys/kern/sysv_msg.c 2001/05/18 04:41:24
@@ -1166,3 +1166,17 @@
        p->p_retval[0] = msgsz;
        return(0);
 }
+
+static int
+sysctl_msqids(SYSCTL_HANDLER_ARGS)
+{
+
+       return (SYSCTL_OUT(req, msqids,
+           sizeof(struct msqid_ds) * msginfo.msgmni));
+}
+
+SYSCTL_DECL(_kern_ipc);
+SYSCTL_STRUCT(_kern_ipc, OID_AUTO, msginfo, CTLFLAG_RD, &msginfo, msginfo,
+    "System V message info");
+SYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLFLAG_ANYBODY | CTLFLAG_RD,
+    NULL, 0, sysctl_msqids, "", "Message queue IDs");
Index: sys/kern/sysv_sem.c
===================================================================
RCS file: /st/src/FreeBSD/src/sys/kern/sysv_sem.c,v
retrieving revision 1.32
diff -u -r1.32 sysv_sem.c
--- sys/kern/sysv_sem.c 2001/02/21 06:39:54     1.32
+++ sys/kern/sysv_sem.c 2001/05/18 04:41:24
@@ -28,6 +28,7 @@
 static int sysvsem_modload __P((struct module *, int, void *));
 static int semunload __P((void));
 static void semexit_myhook __P((struct proc *p));
+static int sysctl_sema __P((SYSCTL_HANDLER_ARGS));
 
 #ifndef _SYS_SYSPROTO_H_
 struct __semctl_args;
@@ -148,6 +149,9 @@
 SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RD, &seminfo.semusz, 0, "");
 SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, "");
 SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, "");
+SYSCTL_STRUCT(_kern_ipc, OID_AUTO, seminfo, CTLFLAG_RD, &seminfo, seminfo, "");
+SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD | CTLFLAG_ANYBODY,
+    NULL, 0, sysctl_sema, "", "");
 
 #if 0
 RO seminfo.semmap      /* SEMMAP unused */
@@ -1065,4 +1069,12 @@
 #endif
        suptr->un_proc = NULL;
        *supptr = suptr->un_next;
+}
+
+static int
+sysctl_sema(SYSCTL_HANDLER_ARGS)
+{
+
+       return (SYSCTL_OUT(req, sema,
+           sizeof(struct semid_ds) * seminfo.semmni));
 }
Index: sys/kern/sysv_shm.c
===================================================================
RCS file: /st/src/FreeBSD/src/sys/kern/sysv_shm.c,v
retrieving revision 1.55
diff -u -r1.55 sysv_shm.c
--- sys/kern/sysv_shm.c 2001/05/04 18:43:19     1.55
+++ sys/kern/sysv_shm.c 2001/05/18 04:41:24
@@ -101,6 +101,7 @@
 static int shmunload __P((void));
 static void shmexit_myhook __P((struct proc *p));
 static void shmfork_myhook __P((struct proc *p1, struct proc *p2));
+static int sysctl_shmsegs __P((SYSCTL_HANDLER_ARGS));
 
 /*
  * Tuneable values
@@ -141,6 +142,9 @@
 SYSCTL_INT(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RD, &shminfo.shmseg, 0, "");
 SYSCTL_INT(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &shminfo.shmall, 0, "");
 SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW, &shm_use_phys, 0, "");
+SYSCTL_STRUCT(_kern_ipc, OID_AUTO, shminfo, CTLFLAG_RD, &shminfo, shminfo, "");
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLFLAG_ANYBODY | CTLFLAG_RD,
+    NULL, 0, sysctl_shmsegs, "", "");
 
 static int
 shm_find_segment_by_key(key)
@@ -702,6 +706,13 @@
        shm_committed = 0;
        shmexit_hook = &shmexit_myhook;
        shmfork_hook = &shmfork_myhook;
+}
+
+static int
+sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
+{
+
+       return (SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0])));
 }
 
 static int
Index: usr.bin/ipcs/ipcs.1
===================================================================
RCS file: /st/src/FreeBSD/src/usr.bin/ipcs/ipcs.1,v
retrieving revision 1.11
diff -u -r1.11 ipcs.1
--- usr.bin/ipcs/ipcs.1 2000/12/14 11:49:46     1.11
+++ usr.bin/ipcs/ipcs.1 2001/05/18 04:41:24
@@ -37,7 +37,7 @@
 .Nd report System V interprocess communication facilities status
 .Sh SYNOPSIS
 .Nm
-.Op Fl abcmopqstMQST
+.Op Fl abcmopqstMQSTy
 .Op Fl C Ar system
 .Op Fl N Ar core
 .Sh DESCRIPTION
@@ -101,12 +101,16 @@
 Extract the name list from the specified system instead of the
 default
 .Dq Pa /kernel .
+Implies
+.Fl y .
 .It Fl M
 Display system information about shared memory.
 .It Fl N Ar core
 Extract values associated with the name list from the specified
 core instead of the default
 .Dq Pa /dev/kmem .
+Implies
+.Fl y .
 .It Fl Q
 Display system information about messages queues.
 .It Fl S
@@ -114,6 +118,19 @@
 .It Fl T
 Display system information about shared memory, message queues
 and semaphores.
+.It Fl y
+Use the
+.Xr kvm 3
+interface instead of the
+.Xr sysctl 3
+interface to extract the required information.
+If
+.Nm
+is to operate on the running system,
+using
+.Xr kvm 3
+will require read privileges to
+.Pa /dev/kmem .
 .El
 .Pp
 If none of the
Index: usr.bin/ipcs/ipcs.c
===================================================================
RCS file: /st/src/FreeBSD/src/usr.bin/ipcs/ipcs.c,v
retrieving revision 1.14
diff -u -r1.14 ipcs.c
--- usr.bin/ipcs/ipcs.c 2000/05/01 10:49:41     1.14
+++ usr.bin/ipcs/ipcs.c 2001/05/18 04:41:24
@@ -30,6 +30,7 @@
   "$FreeBSD: src/usr.bin/ipcs/ipcs.c,v 1.14 2000/05/01 10:49:41 peter Exp $";
 #endif /* not lint */
 
+#include <assert.h>
 #include <err.h>
 #include <fcntl.h>
 #include <kvm.h>
@@ -43,12 +44,14 @@
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/proc.h>
+#include <sys/sysctl.h>
 #define _KERNEL
 #include <sys/ipc.h>
 #include <sys/sem.h>
 #include <sys/shm.h>
 #include <sys/msg.h>
 
+int    use_sysctl;
 struct semid_ds        *sema;
 struct seminfo seminfo;
 struct msginfo msginfo;
@@ -56,6 +59,7 @@
 struct shminfo shminfo;
 struct shmid_ds        *shmsegs;
 
+void   kget __P((int idx, void *addr, size_t size));
 void   usage __P((void));
 
 static struct nlist symbols[] = {
@@ -63,16 +67,14 @@
 #define X_SEMA         0
        {"_seminfo"},
 #define X_SEMINFO      1
-       {"_semu"},
-#define X_SEMU         2
        {"_msginfo"},
-#define X_MSGINFO      3
+#define X_MSGINFO      2
        {"_msqids"},
-#define X_MSQIDS       4
+#define X_MSQIDS       3
        {"_shminfo"},
-#define X_SHMINFO      5
+#define X_SHMINFO      4
        {"_shmsegs"},
-#define X_SHMSEGS      6
+#define X_SHMSEGS      5
        {NULL}
 };
 
@@ -137,7 +139,8 @@
        char   *core = NULL, *namelist = NULL;
        int     i;
 
-       while ((i = getopt(argc, argv, "MmQqSsabC:cN:optT")) != -1)
+       use_sysctl = 1;
+       while ((i = getopt(argc, argv, "MmQqSsabC:cN:optTy")) != -1)
                switch (i) {
                case 'M':
                        display = SHMTOTAL;
@@ -184,39 +187,45 @@
                case 't':
                        option |= TIME;
                        break;
+               case 'y':
+                       use_sysctl = !use_sysctl;
+                       break;
                default:
                        usage();
                }
 
        /*
-        * Discard setgid privileges if not the running kernel so that bad
-        * guys can't print interesting stuff from kernel memory.
+        * If paths to the exec file or core file were specified, we
+        * aren't operating on the running kernel, so we can't use
+        * sysctl.
         */
        if (namelist != NULL || core != NULL)
-               setgid(getgid());
+               use_sysctl = 0;
 
-       if ((kd = kvm_open(namelist, core, NULL, O_RDONLY, "ipcs")) == NULL)
-               exit(1);
+       if (!use_sysctl) {
+               if ((kd = kvm_open(namelist, core, NULL, O_RDONLY, "ipcs"))
+                   == NULL)
+                       exit(1);
 
-       switch (kvm_nlist(kd, symbols)) {
-       case 0:
-               break;
-       case -1:
-               errx(1, "unable to read kernel symbol table");
-       default:
+               switch (kvm_nlist(kd, symbols)) {
+               case 0:
+                       break;
+               case -1:
+                       errx(1, "unable to read kernel symbol table");
+               default:
 #ifdef notdef          /* they'll be told more civilly later */
-               warnx("nlist failed");
-               for (i = 0; symbols[i].n_name != NULL; i++)
-                       if (symbols[i].n_value == 0)
-                               warnx("symbol %s not found",
-                                   symbols[i].n_name);
-               break;
+                       warnx("nlist failed");
+                       for (i = 0; symbols[i].n_name != NULL; i++)
+                               if (symbols[i].n_value == 0)
+                                       warnx("symbol %s not found",
+                                           symbols[i].n_name);
+                       break;
 #endif
+               }
        }
 
-       if ((display & (MSGINFO | MSGTOTAL)) &&
-           kvm_read(kd, symbols[X_MSGINFO].n_value, &msginfo, sizeof(msginfo))== 
sizeof(msginfo)) {
-
+       kget(X_MSGINFO, &msginfo, sizeof(msginfo));
+       if ((display & (MSGINFO | MSGTOTAL))) {
                if (display & MSGTOTAL) {
                        printf("msginfo:\n");
                        printf("\tmsgmax: %6d\t(max characters in a message)\n",
@@ -234,10 +243,12 @@
                }
                if (display & MSGINFO) {
                        struct msqid_ds *xmsqids;
+                       size_t xmsqids_len;
+
 
-                       kvm_read(kd, symbols[X_MSQIDS].n_value, &msqids, 
sizeof(msqids));
-                       xmsqids = malloc(sizeof(struct msqid_ds) * msginfo.msgmni);
-                       kvm_read(kd, (u_long) msqids, xmsqids, sizeof(struct msqid_ds) 
* msginfo.msgmni);
+                       xmsqids_len = sizeof(struct msqid_ds) * msginfo.msgmni;
+                       xmsqids = malloc(xmsqids_len);
+                       kget(X_MSQIDS, xmsqids, xmsqids_len);
 
                        printf("Message Queues:\n");
                        printf("T     ID     KEY        MODE       OWNER    GROUP");
@@ -304,8 +315,9 @@
                        fprintf(stderr,
                            "SVID messages facility not configured in the system\n");
                }
-       if ((display & (SHMINFO | SHMTOTAL)) &&
-           kvm_read(kd, symbols[X_SHMINFO].n_value, &shminfo, sizeof(shminfo))) {
+
+       kget(X_SHMINFO, &shminfo, sizeof(shminfo));
+       if ((display & (SHMINFO | SHMTOTAL))) {
                if (display & SHMTOTAL) {
                        printf("shminfo:\n");
                        printf("\tshmmax: %7d\t(max shared memory segment size)\n",
@@ -321,11 +333,11 @@
                }
                if (display & SHMINFO) {
                        struct shmid_ds *xshmids;
+                       size_t xshmids_len;
 
-                       kvm_read(kd, symbols[X_SHMSEGS].n_value, &shmsegs, 
sizeof(shmsegs));
-                       xshmids = malloc(sizeof(struct shmid_ds) * shminfo.shmmni);
-                       kvm_read(kd, (u_long) shmsegs, xshmids, sizeof(struct 
shmid_ds) *
-                           shminfo.shmmni);
+                       xshmids_len = sizeof(struct shmid_ds) * shminfo.shmmni;
+                       xshmids = malloc(xshmids_len);
+                       kget(X_SHMSEGS, xshmids, xshmids_len);
 
                        printf("Shared Memory:\n");
                        printf("T     ID     KEY        MODE       OWNER    GROUP");
@@ -391,9 +403,11 @@
                        fprintf(stderr,
                            "SVID shared memory facility not configured in the 
system\n");
                }
-       if ((display & (SEMINFO | SEMTOTAL)) &&
-           kvm_read(kd, symbols[X_SEMINFO].n_value, &seminfo, sizeof(seminfo))) {
+
+       kget(X_SEMINFO, &seminfo, sizeof(seminfo));
+       if ((display & (SEMINFO | SEMTOTAL))) {
                struct semid_ds *xsema;
+               size_t xsema_len;
 
                if (display & SEMTOTAL) {
                        printf("seminfo:\n");
@@ -419,9 +433,9 @@
                            seminfo.semaem);
                }
                if (display & SEMINFO) {
-                       kvm_read(kd, symbols[X_SEMA].n_value, &sema, sizeof(sema));
-                       xsema = malloc(sizeof(struct semid_ds) * seminfo.semmni);
-                       kvm_read(kd, (u_long) sema, xsema, sizeof(struct semid_ds) * 
seminfo.semmni);
+                       xsema_len = sizeof(struct semid_ds) * seminfo.semmni;
+                       xsema = malloc(xsema_len);
+                       kget(X_SEMA, xsema, xsema_len);
 
                        printf("Semaphores:\n");
                        printf("T     ID     KEY        MODE       OWNER    GROUP");
@@ -471,16 +485,82 @@
                if (display & (SEMINFO | SEMTOTAL)) {
                        fprintf(stderr, "SVID semaphores facility not configured in 
the system\n");
                }
-       kvm_close(kd);
+       if (!use_sysctl)
+               kvm_close(kd);
 
        exit(0);
 }
 
 void
+kget(idx, addr, size)
+       int idx;
+       void *addr;
+       size_t size;
+{
+       char *symn;                     /* symbol name */
+       int rv, tsiz;
+       unsigned long kaddr;
+       char *sym2sysctl[] = {          /* symbol to sysctl name table */
+               "kern.ipc.sema",
+               "kern.ipc.seminfo",
+               "kern.ipc.msginfo",
+               "kern.ipc.msqids",
+               "kern.ipc.shminfo",
+               "kern.ipc.shmsegs" };
+
+       assert(idx <= sizeof(sym2sysctl) / sizeof(*sym2sysctl));
+       if (!use_sysctl) {
+               symn = symbols[idx].n_name;
+               if (*symn == '_')
+                       symn++;
+               if (symbols[idx].n_type == 0 || symbols[idx].n_value == 0)
+                       errx(1, "symbol %s undefined", symn);
+               /*
+                * For some symbols, the value we retreieve is
+                * actually a pointer; since we want the actual value,
+                * we have to manually dereference it.
+                */
+               switch (idx) {
+               case X_MSQIDS:
+                       tsiz = sizeof(msqids);
+                       rv = kvm_read(kd, symbols[idx].n_value,
+                           &msqids, tsiz);
+                       kaddr = (u_long)msqids;
+                       break;
+               case X_SHMSEGS:
+                       tsiz = sizeof(shmsegs);
+                       rv = kvm_read(kd, symbols[idx].n_value,
+                           &shmsegs, tsiz);
+                       kaddr = (u_long)shmsegs;
+                       break;
+               case X_SEMA:
+                       tsiz = sizeof(sema);
+                       rv = kvm_read(kd, symbols[idx].n_value,
+                           &sema, tsiz);
+                       kaddr = (u_long)sema;
+                       break;
+               default:
+                       rv = tsiz = 0;
+                       kaddr = symbols[idx].n_value;
+                       break;
+               }
+               if (rv != tsiz)
+                       errx(1, "%s: %s", symn, kvm_geterr(kd));
+               if (kvm_read(kd, kaddr, addr, size) != size)
+                       errx(1, "%s: %s", symn, kvm_geterr(kd));
+       } else {
+               tsiz = size;
+               if (sysctlbyname(sym2sysctl[idx], addr, &tsiz, NULL, 0)
+                   == -1)
+                       err(1, "sysctlbyname: %s", sym2sysctl[idx]);
+       }
+}
+
+void
 usage()
 {
 
        fprintf(stderr,
-           "usage: ipcs [-abcmopqst] [-C corefile] [-N namelist]\n");
+           "usage: ipcs [-abcmopqsty] [-C corefile] [-N namelist]\n");
        exit(1);
 }

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message

Reply via email to