MIB: add support for System V IPC information node
The kernel.ipc.sysvipc_info node is the gateway from NetBSD ipcs(1) and ipcrm(1) to the IPC server, and thus necessary for a clean import of these two utilities. The MIB service implementation uses the preexisting (Linux-specific) information calls on the IPC server to obtain the information. Change-Id: I85d1e193162d6b689f114764254dd7f314d2cfa0
This commit is contained in:
parent
5b1db95619
commit
2f09e77b82
@ -285,11 +285,11 @@ CLEANFILES+= ${f:C/\.o/.bc/}
|
||||
.for f in \
|
||||
access.o brk.o close.o environ.o execve.o fork.o fsync.o \
|
||||
getgid.o getpid.o geteuid.o getuid.o gettimeofday.o getvfsstat.o \
|
||||
init.o kernel_utils.o link.o loadname.o lseek.o _mcontext.o mknod.o \
|
||||
mmap.o nanosleep.o open.o pread.o pwrite.o read.o sbrk.o \
|
||||
select.o setuid.o sigprocmask.o stack_utils.o stat.o stime.o \
|
||||
svrctl.o syscall.o _ucontext.o umask.o unlink.o wait4.o write.o \
|
||||
kill.o __sysctl.o
|
||||
init.o kernel_utils.o kill.o link.o loadname.o lseek.o _mcontext.o \
|
||||
minix_rs.o mknod.o mmap.o nanosleep.o open.o pread.o pwrite.o read.o \
|
||||
sbrk.o select.o sem.o setuid.o shmctl.o sigprocmask.o stack_utils.o \
|
||||
stat.o stime.o svrctl.o syscall.o __sysctl.o _ucontext.o umask.o \
|
||||
unlink.o wait4.o write.o
|
||||
${f} ${f:C/\.o/.bc/}: ${LIBMINIXCDIR}/sys/${f:C/\.o/.c/}
|
||||
OBJS+= ${f}
|
||||
CLEANFILES+= ${f}
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <sys/svrctl.h>
|
||||
#include <minix/sysinfo.h>
|
||||
#include <machine/partition.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
#include "servers/vfs/const.h"
|
||||
#include "servers/vfs/dmap.h"
|
||||
@ -298,9 +300,172 @@ mib_kern_boottime(struct mib_call * call __unused,
|
||||
return mib_copyout(oldp, 0, &tv, sizeof(tv));
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy over an ipc_perm structure to an ipc_perm_sysctl structure.
|
||||
*/
|
||||
static void
|
||||
prepare_ipc_perm(struct ipc_perm_sysctl * perms, const struct ipc_perm * perm)
|
||||
{
|
||||
|
||||
memset(perms, 0, sizeof(*perms));
|
||||
perms->_key = perm->_key;
|
||||
perms->uid = perm->uid;
|
||||
perms->gid = perm->gid;
|
||||
perms->cuid = perm->cuid;
|
||||
perms->cgid = perm->cgid;
|
||||
perms->mode = perm->mode;
|
||||
perms->_seq = perm->_seq;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implementation of CTL_KERN KERN_SYSVIPC KERN_SYSVIPC_INFO.
|
||||
*/
|
||||
static ssize_t
|
||||
mib_kern_ipc_info(struct mib_call * call, struct mib_node * node __unused,
|
||||
struct mib_oldp * oldp, struct mib_newp * newp __unused)
|
||||
{
|
||||
struct sem_sysctl_info semsi;
|
||||
struct shm_sysctl_info shmsi;
|
||||
struct semid_ds semds;
|
||||
struct shmid_ds shmds;
|
||||
ssize_t r, off;
|
||||
int i, max;
|
||||
|
||||
if (call->call_namelen != 1)
|
||||
return EINVAL;
|
||||
|
||||
/*
|
||||
* An important security note: according to the specification, IPC_STAT
|
||||
* (and therefore, logically, its SEM_STAT and SHM_STAT siblings)
|
||||
* performs read access checks on the caller, meaning that users other
|
||||
* than root may not obtain details about IPC objects for which they do
|
||||
* not have permission. However, NetBSD's sysctl(2) interface to
|
||||
* obtain the same information, which we mimic here, does *not* perform
|
||||
* such permission checks. For that reason, neither do we; the MIB
|
||||
* service is running as root, so it can freely make stat calls, and
|
||||
* expose the results to all users on the system. If this is to be
|
||||
* changed in the future, we would probably be better off moving the
|
||||
* processing of this sysctl(2) node into the IPC server altogether.
|
||||
*/
|
||||
off = 0;
|
||||
|
||||
switch (call->call_name[0]) {
|
||||
case KERN_SYSVIPC_SEM_INFO:
|
||||
memset(&semsi, 0, sizeof(semsi));
|
||||
if ((max = semctl(0, 0, IPC_INFO, &semsi.seminfo)) == -1)
|
||||
return -errno;
|
||||
/*
|
||||
* As a hackish exception, the requested size may imply that
|
||||
* just general information is to be returned, without throwing
|
||||
* an ENOMEM error because there is no space for full output.
|
||||
*/
|
||||
if (mib_getoldlen(oldp) == sizeof(semsi.seminfo))
|
||||
return mib_copyout(oldp, 0, &semsi.seminfo,
|
||||
sizeof(semsi.seminfo));
|
||||
/*
|
||||
* ipcs(1) blindly expects the returned array to be of size
|
||||
* seminfo.semmni, using the SEM_ALLOC mode flag to see whether
|
||||
* each entry is valid. If we return a smaller size, ipcs(1)
|
||||
* will access arbitrary memory.
|
||||
*/
|
||||
if (semsi.seminfo.semmni <= 0)
|
||||
return EINVAL;
|
||||
if (oldp == NULL)
|
||||
return sizeof(semsi) + sizeof(semsi.semids[0]) *
|
||||
(semsi.seminfo.semmni - 1);
|
||||
/*
|
||||
* Copy out entries one by one. For the first entry, copy out
|
||||
* the entire "semsi" structure. For subsequent entries, reuse
|
||||
* the single embedded 'semids' element of "semsi", and copy
|
||||
* out only that element.
|
||||
*/
|
||||
for (i = 0; i < semsi.seminfo.semmni; i++) {
|
||||
memset(&semsi.semids[0], 0, sizeof(semsi.semids[0]));
|
||||
if (i <= max && semctl(i, 0, SEM_STAT, &semds) >= 0) {
|
||||
prepare_ipc_perm(&semsi.semids[0].sem_perm,
|
||||
&semds.sem_perm);
|
||||
semsi.semids[0].sem_nsems = semds.sem_nsems;
|
||||
semsi.semids[0].sem_otime = semds.sem_otime;
|
||||
semsi.semids[0].sem_ctime = semds.sem_ctime;
|
||||
}
|
||||
if (off == 0)
|
||||
r = mib_copyout(oldp, off, &semsi,
|
||||
sizeof(semsi));
|
||||
else
|
||||
r = mib_copyout(oldp, off, &semsi.semids[0],
|
||||
sizeof(semsi.semids[0]));
|
||||
if (r < 0)
|
||||
return r;
|
||||
off += r;
|
||||
}
|
||||
break;
|
||||
case KERN_SYSVIPC_SHM_INFO:
|
||||
memset(&shmsi, 0, sizeof(shmsi));
|
||||
if ((max = shmctl(0, IPC_INFO,
|
||||
(struct shmid_ds *)&shmsi.shminfo)) == -1)
|
||||
return -errno;
|
||||
/*
|
||||
* As a hackish exception, the requested size may imply that
|
||||
* just general information is to be returned, without throwing
|
||||
* an ENOMEM error because there is no space for full output.
|
||||
*/
|
||||
if (mib_getoldlen(oldp) == sizeof(shmsi.shminfo))
|
||||
return mib_copyout(oldp, 0, &shmsi.shminfo,
|
||||
sizeof(shmsi.shminfo));
|
||||
/*
|
||||
* ipcs(1) blindly expects the returned array to be of size
|
||||
* shminfo.shmmni, using the SHMSEG_ALLOCATED (not exposed,
|
||||
* 0x0800) mode flag to see whether each entry is valid. If we
|
||||
* return a smaller size, ipcs(1) will access arbitrary memory.
|
||||
*/
|
||||
if (shmsi.shminfo.shmmni <= 0)
|
||||
return EINVAL;
|
||||
if (oldp == NULL)
|
||||
return sizeof(shmsi) + sizeof(shmsi.shmids[0]) *
|
||||
(shmsi.shminfo.shmmni - 1);
|
||||
/*
|
||||
* Copy out entries one by one. For the first entry, copy out
|
||||
* the entire "shmsi" structure. For subsequent entries, reuse
|
||||
* the single embedded 'shmids' element of "shmsi", and copy
|
||||
* out only that element.
|
||||
*/
|
||||
for (i = 0; i < (int)shmsi.shminfo.shmmni; i++) {
|
||||
memset(&shmsi.shmids[0], 0, sizeof(shmsi.shmids[0]));
|
||||
if (i <= max && shmctl(i, SHM_STAT, &shmds) == 0) {
|
||||
prepare_ipc_perm(&shmsi.shmids[0].shm_perm,
|
||||
&shmds.shm_perm);
|
||||
shmsi.shmids[0].shm_perm.mode |= 0x0800;
|
||||
shmsi.shmids[0].shm_segsz = shmds.shm_segsz;
|
||||
shmsi.shmids[0].shm_lpid = shmds.shm_lpid;
|
||||
shmsi.shmids[0].shm_cpid = shmds.shm_cpid;
|
||||
shmsi.shmids[0].shm_atime = shmds.shm_atime;
|
||||
shmsi.shmids[0].shm_dtime = shmds.shm_dtime;
|
||||
shmsi.shmids[0].shm_ctime = shmds.shm_ctime;
|
||||
shmsi.shmids[0].shm_nattch = shmds.shm_nattch;
|
||||
}
|
||||
if (off == 0)
|
||||
r = mib_copyout(oldp, off, &shmsi,
|
||||
sizeof(shmsi));
|
||||
else
|
||||
r = mib_copyout(oldp, off, &shmsi.shmids[0],
|
||||
sizeof(shmsi.shmids[0]));
|
||||
if (r < 0)
|
||||
return r;
|
||||
off += r;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
/* The CTL_KERN KERN_SYSVIPC nodes. */
|
||||
static struct mib_node mib_kern_ipc_table[] = {
|
||||
/* 1*/ /* KERN_SYSVIPC_INFO: not yet supported */
|
||||
/* 1*/ [KERN_SYSVIPC_INFO] = MIB_FUNC(_P | _RO | CTLTYPE_NODE, 0,
|
||||
mib_kern_ipc_info, "sysvipc_info",
|
||||
"System V style IPC information"),
|
||||
/* 2*/ [KERN_SYSVIPC_MSG] = MIB_INT(_P | _RO, 0, "sysvmsg", "System V "
|
||||
"style message support available"),
|
||||
/* 3*/ [KERN_SYSVIPC_SEM] = MIB_INT(_P | _RO, 1, "sysvsem", "System V "
|
||||
|
@ -234,6 +234,54 @@ put_kern_boottime(struct trace_proc * proc, const char * name,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print CTL_KERN KERN_SYSVIPC KERN_SYSVIPC_INFO.
|
||||
*/
|
||||
static int
|
||||
put_kern_sysvipc_info(struct trace_proc * proc, const char * name,
|
||||
int type, const void * ptr __unused, vir_bytes addr, size_t size)
|
||||
{
|
||||
const int *mib;
|
||||
const char *text;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* TODO: print the obtained structure(s). For now we are just
|
||||
* concerned with the name components.
|
||||
*/
|
||||
if (type != ST_NAME) {
|
||||
put_ptr(proc, name, addr);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
mib = (const int *)ptr;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
text = NULL;
|
||||
|
||||
if (i == 0) {
|
||||
switch (mib[i]) {
|
||||
case KERN_SYSVIPC_SEM_INFO: text = "<sem>"; break;
|
||||
case KERN_SYSVIPC_SHM_INFO: text = "<shm>"; break;
|
||||
case KERN_SYSVIPC_MSG_INFO: text = "<msg>"; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valuesonly && text != NULL)
|
||||
put_field(proc, NULL, text);
|
||||
else
|
||||
put_value(proc, NULL, "%d", mib[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The CTL_KERN KERN_SYSVIPC table. */
|
||||
static const struct sysctl_tab kern_sysvipc_tab[] = {
|
||||
PROC(KERN_SYSVIPC_INFO, 0, put_kern_sysvipc_info),
|
||||
};
|
||||
|
||||
/* The CTL_KERN table. */
|
||||
static const struct sysctl_tab kern_tab[] = {
|
||||
PROC(KERN_CLOCKRATE, sizeof(struct clockinfo), put_kern_clockrate),
|
||||
@ -242,6 +290,7 @@ static const struct sysctl_tab kern_tab[] = {
|
||||
PROC(KERN_CP_TIME, sizeof(uint64_t) * CPUSTATES, put_kern_cp_time),
|
||||
PROC(KERN_CONSDEV, sizeof(dev_t), put_kern_consdev),
|
||||
PROC(KERN_DRIVERS, 0, put_kern_drivers),
|
||||
NODE(KERN_SYSVIPC, kern_sysvipc_tab),
|
||||
PROC(KERN_BOOTTIME, 0, put_kern_boottime),
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user