Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 17 May 2001 22:03:39 -0700
From:      Dima Dorfman <dima@unixfreak.org>
To:        hackers@freebsd.org
Subject:   De-setgid-ifying ipcs(1)
Message-ID:  <20010518050339.AB8153E0B@bazooka.unixfreak.org>

next in thread | raw e-mail | index | archive | help
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
					dima@unixfreak.org

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 majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010518050339.AB8153E0B>