Add kern.ipc.{msqids,semsegs,sema} sysctls for FreeBSD32.

Stop leaking kernel pointers though theses sysctls and make sure that the
padding in the structures is zeroed on allocation to avoid other leaks.

Reviewed by:	gordon, kib
Obtained from:	CheriBSD
MFC after:	1 week
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D13459
This commit is contained in:
Brooks Davis 2018-02-02 18:03:12 +00:00
parent 49bc1b104e
commit 0fd25723bc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=328799
4 changed files with 134 additions and 7 deletions

View File

@ -49,6 +49,18 @@ struct semid_ds32 {
int32_t sem_ctime;
};
#ifdef _KERNEL
struct semid_kernel32 {
/* Data structure exposed to user space. */
struct semid_ds32 u;
/* Kernel-private components of the semaphore. */
int32_t label;
int32_t cred;
};
#endif /* _KERNEL */
union semun32 {
int val;
uint32_t buf;
@ -69,6 +81,17 @@ struct msqid_ds32 {
int32_t msg_ctime;
};
#ifdef _KERNEL
struct msqid_kernel32 {
/* Data structure exposed to user space. */
struct msqid_ds32 u;
/* Kernel-private components of the message queue. */
uint32_t label;
uint32_t cred;
};
#endif
struct shmid_ds32 {
struct ipc_perm32 shm_perm;
int32_t shm_segsz;
@ -80,6 +103,15 @@ struct shmid_ds32 {
int32_t shm_ctime;
};
#ifdef _KERNEL
struct shmid_kernel32 {
struct shmid_ds32 u;
int32_t *object;
int32_t *label;
int32_t *cred;
};
#endif
struct shm_info32 {
int32_t used_ids;
uint32_t shm_tot;

View File

@ -229,7 +229,7 @@ msginit()
msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG,
M_WAITOK);
M_WAITOK | M_ZERO);
/*
* msginfo.msgssz should be a power of two for efficiency reasons.
@ -1418,7 +1418,12 @@ static int
sysctl_msqids(SYSCTL_HANDLER_ARGS)
{
struct msqid_kernel tmsqk;
#ifdef COMPAT_FREEBSD32
struct msqid_kernel32 tmsqk32;
#endif
struct prison *pr, *rpr;
void *outaddr;
size_t outsize;
int error, i;
pr = req->td->td_ucred->cr_prison;
@ -1435,7 +1440,40 @@ sysctl_msqids(SYSCTL_HANDLER_ARGS)
tmsqk.u.msg_perm.key = IPC_PRIVATE;
}
mtx_unlock(&msq_mtx);
error = SYSCTL_OUT(req, &tmsqk, sizeof(tmsqk));
#ifdef COMPAT_FREEBSD32
if (SV_CURPROC_FLAG(SV_ILP32)) {
bzero(&tmsqk32, sizeof(tmsqk32));
freebsd32_ipcperm_out(&tmsqk.u.msg_perm,
&tmsqk32.u.msg_perm);
/* Don't copy u.msg_first or u.msg_last */
CP(tmsqk, tmsqk32, u.msg_cbytes);
CP(tmsqk, tmsqk32, u.msg_qnum);
CP(tmsqk, tmsqk32, u.msg_qbytes);
CP(tmsqk, tmsqk32, u.msg_lspid);
CP(tmsqk, tmsqk32, u.msg_lrpid);
CP(tmsqk, tmsqk32, u.msg_stime);
CP(tmsqk, tmsqk32, u.msg_rtime);
CP(tmsqk, tmsqk32, u.msg_ctime);
/* Don't copy label or cred */
outaddr = &tmsqk32;
outsize = sizeof(tmsqk32);
} else
#endif
{
/* Don't leak kernel pointers */
tmsqk.u.msg_first = NULL;
tmsqk.u.msg_last = NULL;
tmsqk.label = NULL;
tmsqk.cred = NULL;
/*
* XXX: some padding also exists, but we take care to
* allocate our pool of msqid_kernel structs with
* zeroed memory so this should be OK.
*/
outaddr = &tmsqk;
outsize = sizeof(tmsqk);
}
error = SYSCTL_OUT(req, outaddr, outsize);
if (error != 0)
break;
}

View File

@ -280,7 +280,7 @@ seminit(void)
sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK);
sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM,
M_WAITOK);
M_WAITOK | M_ZERO);
sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM,
M_WAITOK | M_ZERO);
semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK);
@ -1487,6 +1487,11 @@ sysctl_sema(SYSCTL_HANDLER_ARGS)
{
struct prison *pr, *rpr;
struct semid_kernel tsemak;
#ifdef COMPAT_FREEBSD32
struct semid_kernel32 tsemak32;
#endif
void *outaddr;
size_t outsize;
int error, i;
pr = req->td->td_ucred->cr_prison;
@ -1503,7 +1508,28 @@ sysctl_sema(SYSCTL_HANDLER_ARGS)
tsemak.u.sem_perm.key = IPC_PRIVATE;
}
mtx_unlock(&sema_mtx[i]);
error = SYSCTL_OUT(req, &tsemak, sizeof(tsemak));
#ifdef COMPAT_FREEBSD32
if (SV_CURPROC_FLAG(SV_ILP32)) {
bzero(&tsemak32, sizeof(tsemak32));
freebsd32_ipcperm_out(&tsemak.u.sem_perm,
&tsemak32.u.sem_perm);
/* Don't copy u.sem_base */
CP(tsemak, tsemak32, u.sem_nsems);
CP(tsemak, tsemak32, u.sem_otime);
CP(tsemak, tsemak32, u.sem_ctime);
/* Don't copy label or cred */
outaddr = &tsemak32;
outsize = sizeof(tsemak32);
} else
#endif
{
tsemak.u.sem_base = NULL;
tsemak.label = NULL;
tsemak.cred = NULL;
outaddr = &tsemak;
outsize = sizeof(tsemak);
}
error = SYSCTL_OUT(req, outaddr, outsize);
if (error != 0)
break;
}

View File

@ -866,7 +866,8 @@ shmrealloc(void)
if (shmalloced >= shminfo.shmmni)
return;
newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM,
M_WAITOK | M_ZERO);
for (i = 0; i < shmalloced; i++)
bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
for (; i < shminfo.shmmni; i++) {
@ -944,7 +945,8 @@ shminit(void)
}
}
shmalloced = shminfo.shmmni;
shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK);
shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM,
M_WAITOK|M_ZERO);
for (i = 0; i < shmalloced; i++) {
shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
shmsegs[i].u.shm_perm.seq = 0;
@ -1031,7 +1033,12 @@ static int
sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
{
struct shmid_kernel tshmseg;
#ifdef COMPAT_FREEBSD32
struct shmid_kernel32 tshmseg32;
#endif
struct prison *pr, *rpr;
void *outaddr;
size_t outsize;
int error, i;
SYSVSHM_LOCK();
@ -1048,7 +1055,31 @@ sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
if (tshmseg.cred->cr_prison != pr)
tshmseg.u.shm_perm.key = IPC_PRIVATE;
}
error = SYSCTL_OUT(req, &tshmseg, sizeof(tshmseg));
#ifdef COMPAT_FREEBSD32
if (SV_CURPROC_FLAG(SV_ILP32)) {
bzero(&tshmseg32, sizeof(tshmseg32));
freebsd32_ipcperm_out(&tshmseg.u.shm_perm,
&tshmseg32.u.shm_perm);
CP(tshmseg, tshmseg32, u.shm_segsz);
CP(tshmseg, tshmseg32, u.shm_lpid);
CP(tshmseg, tshmseg32, u.shm_cpid);
CP(tshmseg, tshmseg32, u.shm_nattch);
CP(tshmseg, tshmseg32, u.shm_atime);
CP(tshmseg, tshmseg32, u.shm_dtime);
CP(tshmseg, tshmseg32, u.shm_ctime);
/* Don't copy object, label, or cred */
outaddr = &tshmseg32;
outsize = sizeof(tshmseg32);
} else
#endif
{
tshmseg.object = NULL;
tshmseg.label = NULL;
tshmseg.cred = NULL;
outaddr = &tshmseg;
outsize = sizeof(tshmseg);
}
error = SYSCTL_OUT(req, outaddr, outsize);
if (error != 0)
break;
}