summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorAntonello Cruz <Antonello.Cruz@Sun.COM>2008-10-24 12:57:08 -0700
committerAntonello Cruz <Antonello.Cruz@Sun.COM>2008-10-24 12:57:08 -0700
commitc5a9a4fc75359f623d03e4eab6a03c9cabe175a3 (patch)
tree545e7bf9b55a6e84eb99bd47b8425375a3c9df51 /usr
parent4f2e01b27b6f050ac264ee29e4fea7a9045ce86e (diff)
downloadillumos-joyent-c5a9a4fc75359f623d03e4eab6a03c9cabe175a3.tar.gz
6753802 procfs may access kernel data it shouldn't
Diffstat (limited to 'usr')
-rw-r--r--usr/src/uts/common/contract/device.c21
-rw-r--r--usr/src/uts/common/contract/process.c37
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_tmpl.c56
-rw-r--r--usr/src/uts/common/fs/proc/prioctl.c29
-rw-r--r--usr/src/uts/common/os/contract.c97
-rw-r--r--usr/src/uts/common/sys/contract_impl.h25
6 files changed, 170 insertions, 95 deletions
diff --git a/usr/src/uts/common/contract/device.c b/usr/src/uts/common/contract/device.c
index b34eb2e962..d692dabc81 100644
--- a/usr/src/uts/common/contract/device.c
+++ b/usr/src/uts/common/contract/device.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/mutex.h>
#include <sys/debug.h>
#include <sys/types.h>
@@ -498,9 +496,11 @@ ctmpl_device_free(struct ct_template *template)
* the {PRIV_SYS_DEVICES} privilege asserted in its effective set.
*/
static int
-ctmpl_device_set(struct ct_template *tmpl, ct_param_t *param, const cred_t *cr)
+ctmpl_device_set(struct ct_template *tmpl, ct_kparam_t *kparam,
+ const cred_t *cr)
{
ctmpl_device_t *dtmpl = tmpl->ctmpl_data;
+ ct_param_t *param = &kparam->param;
int error;
dev_info_t *dip;
int spec_type;
@@ -510,12 +510,12 @@ ctmpl_device_set(struct ct_template *tmpl, ct_param_t *param, const cred_t *cr)
ASSERT(MUTEX_HELD(&tmpl->ctmpl_lock));
if (param->ctpm_id == CTDP_MINOR) {
- str_value = (char *)param->ctpm_value;
+ str_value = (char *)kparam->ctpm_kbuf;
str_value[param->ctpm_size - 1] = '\0';
} else {
if (param->ctpm_size < sizeof (uint64_t))
return (EINVAL);
- param_value = *(uint64_t *)param->ctpm_value;
+ param_value = *(uint64_t *)kparam->ctpm_kbuf;
}
switch (param->ctpm_id) {
@@ -597,10 +597,11 @@ ctmpl_device_set(struct ct_template *tmpl, ct_param_t *param, const cred_t *cr)
* returns the value of the requested term.
*/
static int
-ctmpl_device_get(struct ct_template *template, ct_param_t *param)
+ctmpl_device_get(struct ct_template *template, ct_kparam_t *kparam)
{
ctmpl_device_t *dtmpl = template->ctmpl_data;
- uint64_t *param_value = param->ctpm_value;
+ ct_param_t *param = &kparam->param;
+ uint64_t *param_value = kparam->ctpm_kbuf;
ASSERT(MUTEX_HELD(&template->ctmpl_lock));
@@ -608,7 +609,7 @@ ctmpl_device_get(struct ct_template *template, ct_param_t *param)
param->ctpm_id == CTDP_NONEG) {
if (param->ctpm_size < sizeof (uint64_t))
return (EINVAL);
- param->ctpm_size = sizeof (uint64_t);
+ kparam->ret_size = sizeof (uint64_t);
}
switch (param->ctpm_id) {
@@ -620,9 +621,9 @@ ctmpl_device_get(struct ct_template *template, ct_param_t *param)
break;
case CTDP_MINOR:
if (dtmpl->ctd_minor) {
- param->ctpm_size = strlcpy((char *)param->ctpm_value,
+ kparam->ret_size = strlcpy((char *)kparam->ctpm_kbuf,
dtmpl->ctd_minor, param->ctpm_size);
- param->ctpm_size++;
+ kparam->ret_size++;
} else {
return (ENOENT);
}
diff --git a/usr/src/uts/common/contract/process.c b/usr/src/uts/common/contract/process.c
index 97e9be4735..4b5d4d0ae8 100644
--- a/usr/src/uts/common/contract/process.c
+++ b/usr/src/uts/common/contract/process.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/mutex.h>
#include <sys/debug.h>
#include <sys/types.h>
@@ -223,9 +221,11 @@ ctmpl_process_free(struct ct_template *template)
* the desired terms.
*/
static int
-ctmpl_process_set(struct ct_template *tmpl, ct_param_t *param, const cred_t *cr)
+ctmpl_process_set(struct ct_template *tmpl, ct_kparam_t *kparam,
+ const cred_t *cr)
{
ctmpl_process_t *ctp = tmpl->ctmpl_data;
+ ct_param_t *param = &kparam->param;
contract_t *ct;
int error;
uint64_t param_value;
@@ -233,12 +233,12 @@ ctmpl_process_set(struct ct_template *tmpl, ct_param_t *param, const cred_t *cr)
if ((param->ctpm_id == CTPP_SVC_FMRI) ||
(param->ctpm_id == CTPP_CREATOR_AUX)) {
- str_value = (char *)param->ctpm_value;
+ str_value = (char *)kparam->ctpm_kbuf;
str_value[param->ctpm_size - 1] = '\0';
} else {
if (param->ctpm_size < sizeof (uint64_t))
return (EINVAL);
- param_value = *(uint64_t *)param->ctpm_value;
+ param_value = *(uint64_t *)kparam->ctpm_kbuf;
/*
* No process contract parameters are > 32 bits.
* Unless it is a string.
@@ -355,17 +355,18 @@ ctmpl_process_set(struct ct_template *tmpl, ct_param_t *param, const cred_t *cr)
* returns the requested term.
*/
static int
-ctmpl_process_get(struct ct_template *template, ct_param_t *param)
+ctmpl_process_get(struct ct_template *template, ct_kparam_t *kparam)
{
ctmpl_process_t *ctp = template->ctmpl_data;
- uint64_t *param_value = param->ctpm_value;
+ ct_param_t *param = &kparam->param;
+ uint64_t *param_value = kparam->ctpm_kbuf;
if (param->ctpm_id == CTPP_SUBSUME ||
param->ctpm_id == CTPP_PARAMS ||
param->ctpm_id == CTPP_EV_FATAL) {
if (param->ctpm_size < sizeof (uint64_t))
return (EINVAL);
- param->ctpm_size = sizeof (uint64_t);
+ kparam->ret_size = sizeof (uint64_t);
}
switch (param->ctpm_id) {
@@ -378,28 +379,28 @@ ctmpl_process_get(struct ct_template *template, ct_param_t *param)
break;
case CTPP_SVC_FMRI:
if (ctp->ctp_svc_fmri == NULL) {
- param->ctpm_size =
- strlcpy((char *)param->ctpm_value,
+ kparam->ret_size =
+ strlcpy((char *)kparam->ctpm_kbuf,
CT_PR_SVC_DEFAULT, param->ctpm_size);
} else {
- param->ctpm_size =
- strlcpy((char *)param->ctpm_value,
+ kparam->ret_size =
+ strlcpy((char *)kparam->ctpm_kbuf,
refstr_value(ctp->ctp_svc_fmri), param->ctpm_size);
}
- param->ctpm_size++;
+ kparam->ret_size++;
break;
case CTPP_CREATOR_AUX:
if (ctp->ctp_svc_aux == NULL) {
- param->ctpm_size =
- strlcpy((char *)param->ctpm_value,
+ kparam->ret_size =
+ strlcpy((char *)kparam->ctpm_kbuf,
refstr_value(conp_svc_aux_default),
param->ctpm_size);
} else {
- param->ctpm_size =
- strlcpy((char *)param->ctpm_value,
+ kparam->ret_size =
+ strlcpy((char *)kparam->ctpm_kbuf,
refstr_value(ctp->ctp_svc_aux), param->ctpm_size);
}
- param->ctpm_size++;
+ kparam->ret_size++;
break;
case CTPP_EV_FATAL:
*param_value = ctp->ctp_ev_fatal;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c b/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c
index 595988ef04..65f25cdf33 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
@@ -125,14 +123,11 @@ ctfs_tmpl_ioctl(
caller_context_t *ct)
{
ctfs_tmplnode_t *tmplnode = vp->v_data;
- ct_param_t param;
- STRUCT_DECL(ct_param, uarg);
+ ct_kparam_t kparam;
+ ct_param_t *param = &kparam.param;
ctid_t ctid;
- uint32_t local_ctpm_size;
int error;
- STRUCT_INIT(uarg, flag);
-
switch (cmd) {
case CT_TACTIVATE:
ASSERT(tmplnode->ctfs_tmn_tmpl != NULL);
@@ -150,39 +145,24 @@ ctfs_tmpl_ioctl(
*rvalp = ctid;
break;
case CT_TSET:
- if (copyin((void *)arg, STRUCT_BUF(uarg), STRUCT_SIZE(uarg)))
- return (EFAULT);
- param.ctpm_id = STRUCT_FGET(uarg, ctpm_id);
- param.ctpm_size = STRUCT_FGET(uarg, ctpm_size);
- if (param.ctpm_size > CT_PARAM_MAX_SIZE ||
- param.ctpm_size == 0)
- return (EINVAL);
- param.ctpm_value = kmem_alloc(param.ctpm_size, KM_SLEEP);
- if (copyin(STRUCT_FGETP(uarg, ctpm_value), param.ctpm_value,
- param.ctpm_size))
- return (EFAULT);
- error = ctmpl_set(tmplnode->ctfs_tmn_tmpl, &param, cr);
- kmem_free(param.ctpm_value, param.ctpm_size);
+ error = ctparam_copyin((void *)arg, &kparam, flag, cmd);
+ if (error != 0)
+ return (error);
+ error = ctmpl_set(tmplnode->ctfs_tmn_tmpl, &kparam, cr);
+ kmem_free(kparam.ctpm_kbuf, param->ctpm_size);
+
return (error);
case CT_TGET:
- if (copyin((void *)arg, STRUCT_BUF(uarg), STRUCT_SIZE(uarg)))
- return (EFAULT);
- param.ctpm_id = STRUCT_FGET(uarg, ctpm_id);
- param.ctpm_size = STRUCT_FGET(uarg, ctpm_size);
- if (param.ctpm_size > CT_PARAM_MAX_SIZE)
- param.ctpm_size = CT_PARAM_MAX_SIZE;
- if (param.ctpm_size == 0)
- return (EINVAL);
- local_ctpm_size = param.ctpm_size;
- param.ctpm_value = kmem_alloc(param.ctpm_size, KM_SLEEP);
- error = ctmpl_get(tmplnode->ctfs_tmn_tmpl, &param);
- STRUCT_FSET(uarg, ctpm_size, param.ctpm_size);
- if (!error &&
- (copyout(param.ctpm_value, STRUCT_FGETP(uarg, ctpm_value),
- MIN(local_ctpm_size, param.ctpm_size))) ||
- copyout(STRUCT_BUF(uarg), (void *)arg, STRUCT_SIZE(uarg)))
- error = EFAULT;
- kmem_free(param.ctpm_value, local_ctpm_size);
+ error = ctparam_copyin((void *)arg, &kparam, flag, cmd);
+ if (error != 0)
+ return (error);
+ error = ctmpl_get(tmplnode->ctfs_tmn_tmpl, &kparam);
+ if (error != 0) {
+ kmem_free(kparam.ctpm_kbuf, param->ctpm_size);
+ } else {
+ error = ctparam_copyout(&kparam, (void *)arg, flag);
+ }
+
return (error);
default:
return (EINVAL);
diff --git a/usr/src/uts/common/fs/proc/prioctl.c b/usr/src/uts/common/fs/proc/prioctl.c
index 45a10b88f7..7d2c93d8d8 100644
--- a/usr/src/uts/common/fs/proc/prioctl.c
+++ b/usr/src/uts/common/fs/proc/prioctl.c
@@ -26,9 +26,6 @@
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All rights reserved. */
-
-#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.29 */
-
#include <sys/types.h>
#include <sys/param.h>
#include <sys/vmparam.h>
@@ -86,39 +83,45 @@ extern void oprgetstatus(kthread_t *, prstatus_t *, zone_t *);
extern void oprgetpsinfo(proc_t *, prpsinfo_t *, kthread_t *);
static int oprgetmap(proc_t *, list_t *);
-/*ARGSUSED*/
static int
prctioctl(prnode_t *pnp, int cmd, intptr_t arg, int flag, cred_t *cr)
{
int error = 0;
- ct_param_t param;
+ ct_kparam_t kparam;
+ ct_param_t *param = &kparam.param;
ct_template_t *tmpl;
if (cmd != CT_TSET && cmd != CT_TGET)
return (EINVAL);
- if (copyin((void *)arg, &param, sizeof (ct_param_t)))
- return (EFAULT);
+ error = ctparam_copyin((void *)arg, &kparam, flag, cmd);
+ if (error != 0)
+ return (error);
- if ((error = prlock(pnp, ZNO)) != 0)
+ if ((error = prlock(pnp, ZNO)) != 0) {
+ kmem_free(kparam.ctpm_kbuf, param->ctpm_size);
return (error);
+ }
tmpl = pnp->pr_common->prc_thread->t_lwp->lwp_ct_active[pnp->pr_cttype];
if (tmpl == NULL) {
prunlock(pnp);
+ kmem_free(kparam.ctpm_kbuf, param->ctpm_size);
return (ESTALE);
}
if (cmd == CT_TSET)
- error = ctmpl_set(tmpl, &param, cr);
+ error = ctmpl_set(tmpl, &kparam, cr);
else
- error = ctmpl_get(tmpl, &param);
+ error = ctmpl_get(tmpl, &kparam);
prunlock(pnp);
- if (cmd == CT_TGET && error == 0 &&
- copyout(&param, (void *)arg, sizeof (ct_param_t)))
- error = EFAULT;
+ if (cmd == CT_TGET && error == 0) {
+ error = ctparam_copyout(&kparam, (void *)arg, flag);
+ } else {
+ kmem_free(kparam.ctpm_kbuf, param->ctpm_size);
+ }
return (error);
}
diff --git a/usr/src/uts/common/os/contract.c b/usr/src/uts/common/os/contract.c
index 0c711e930e..a292f4e14f 100644
--- a/usr/src/uts/common/os/contract.c
+++ b/usr/src/uts/common/os/contract.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Contracts
* ---------
@@ -171,6 +169,7 @@
#include <sys/list.h>
#include <sys/sysmacros.h>
#include <sys/proc.h>
+#include <sys/ctfs.h>
#include <sys/contract_impl.h>
#include <sys/contract/process_impl.h>
#include <sys/dditypes.h>
@@ -1418,6 +1417,82 @@ contract_type_pbundle(ct_type_t *type, proc_t *pp)
}
/*
+ * ctparam_copyin
+ *
+ * copyin a ct_param_t for CT_TSET or CT_TGET commands.
+ * If ctparam_copyout() is not called after ctparam_copyin(), then
+ * the caller must kmem_free() the buffer pointed by kparam->ctpm_kbuf.
+ *
+ * The copyin/out of ct_param_t is not done in ctmpl_set() and ctmpl_get()
+ * because prctioctl() calls ctmpl_set() and ctmpl_get() while holding a
+ * process lock.
+ */
+int
+ctparam_copyin(const void *uaddr, ct_kparam_t *kparam, int flag, int cmd)
+{
+ uint32_t size;
+ void *ubuf;
+ ct_param_t *param = &kparam->param;
+ STRUCT_DECL(ct_param, uarg);
+
+ STRUCT_INIT(uarg, flag);
+ if (copyin(uaddr, STRUCT_BUF(uarg), STRUCT_SIZE(uarg)))
+ return (EFAULT);
+ size = STRUCT_FGET(uarg, ctpm_size);
+ ubuf = STRUCT_FGETP(uarg, ctpm_value);
+
+ if (size > CT_PARAM_MAX_SIZE || size == 0)
+ return (EINVAL);
+
+ kparam->ctpm_kbuf = kmem_alloc(size, KM_SLEEP);
+ if (cmd == CT_TSET) {
+ if (copyin(ubuf, kparam->ctpm_kbuf, size)) {
+ kmem_free(kparam->ctpm_kbuf, size);
+ return (EFAULT);
+ }
+ }
+ param->ctpm_id = STRUCT_FGET(uarg, ctpm_id);
+ param->ctpm_size = size;
+ param->ctpm_value = ubuf;
+ kparam->ret_size = 0;
+
+ return (0);
+}
+
+/*
+ * ctparam_copyout
+ *
+ * copyout a ct_kparam_t and frees the buffer pointed by the member
+ * ctpm_kbuf of ct_kparam_t
+ */
+int
+ctparam_copyout(ct_kparam_t *kparam, void *uaddr, int flag)
+{
+ int r = 0;
+ ct_param_t *param = &kparam->param;
+ STRUCT_DECL(ct_param, uarg);
+
+ STRUCT_INIT(uarg, flag);
+
+ STRUCT_FSET(uarg, ctpm_id, param->ctpm_id);
+ STRUCT_FSET(uarg, ctpm_size, kparam->ret_size);
+ STRUCT_FSETP(uarg, ctpm_value, param->ctpm_value);
+ if (copyout(STRUCT_BUF(uarg), uaddr, STRUCT_SIZE(uarg))) {
+ r = EFAULT;
+ goto error;
+ }
+ if (copyout(kparam->ctpm_kbuf, param->ctpm_value,
+ MIN(kparam->ret_size, param->ctpm_size))) {
+ r = EFAULT;
+ }
+
+error:
+ kmem_free(kparam->ctpm_kbuf, param->ctpm_size);
+
+ return (r);
+}
+
+/*
* ctmpl_free
*
* Frees a template.
@@ -1458,9 +1533,10 @@ ctmpl_dup(ct_template_t *template)
* Sets the requested terms of a template.
*/
int
-ctmpl_set(ct_template_t *template, ct_param_t *param, const cred_t *cr)
+ctmpl_set(ct_template_t *template, ct_kparam_t *kparam, const cred_t *cr)
{
int result = 0;
+ ct_param_t *param = &kparam->param;
uint64_t param_value;
if (param->ctpm_id == CTP_COOKIE ||
@@ -1469,7 +1545,7 @@ ctmpl_set(ct_template_t *template, ct_param_t *param, const cred_t *cr)
if (param->ctpm_size < sizeof (uint64_t)) {
return (EINVAL);
} else {
- param_value = *(uint64_t *)param->ctpm_value;
+ param_value = *(uint64_t *)kparam->ctpm_kbuf;
}
}
@@ -1503,7 +1579,7 @@ ctmpl_set(ct_template_t *template, ct_param_t *param, const cred_t *cr)
*/
/* FALLTHROUGH */
default:
- result = template->ctmpl_ops->ctop_set(template, param, cr);
+ result = template->ctmpl_ops->ctop_set(template, kparam, cr);
}
mutex_exit(&template->ctmpl_lock);
@@ -1517,7 +1593,7 @@ ctmpl_set(ct_template_t *template, ct_param_t *param, const cred_t *cr)
*
* If the term requested is a variable-sized term and the buffer
* provided is too small for the data, we truncate the data and return
- * the buffer size necessary to fit the term in param->ctpm_size. If the
+ * the buffer size necessary to fit the term in kparam->ret_size. If the
* term requested is fix-sized (uint64_t) and the buffer provided is too
* small, we return EINVAL. This should never happen if you're using
* libcontract(3LIB), only if you call ioctl with a hand constructed
@@ -1527,9 +1603,10 @@ ctmpl_set(ct_template_t *template, ct_param_t *param, const cred_t *cr)
* parameters.
*/
int
-ctmpl_get(ct_template_t *template, ct_param_t *param)
+ctmpl_get(ct_template_t *template, ct_kparam_t *kparam)
{
int result = 0;
+ ct_param_t *param = &kparam->param;
uint64_t *param_value;
if (param->ctpm_id == CTP_COOKIE ||
@@ -1538,8 +1615,8 @@ ctmpl_get(ct_template_t *template, ct_param_t *param)
if (param->ctpm_size < sizeof (uint64_t)) {
return (EINVAL);
} else {
- param_value = param->ctpm_value;
- param->ctpm_size = sizeof (uint64_t);
+ param_value = kparam->ctpm_kbuf;
+ kparam->ret_size = sizeof (uint64_t);
}
}
@@ -1555,7 +1632,7 @@ ctmpl_get(ct_template_t *template, ct_param_t *param)
*param_value = template->ctmpl_ev_crit;
break;
default:
- result = template->ctmpl_ops->ctop_get(template, param);
+ result = template->ctmpl_ops->ctop_get(template, kparam);
}
mutex_exit(&template->ctmpl_lock);
diff --git a/usr/src/uts/common/sys/contract_impl.h b/usr/src/uts/common/sys/contract_impl.h
index 687fdfa6df..704ff12666 100644
--- a/usr/src/uts/common/sys/contract_impl.h
+++ b/usr/src/uts/common/sys/contract_impl.h
@@ -26,8 +26,6 @@
#ifndef _SYS_CONTRACT_IMPL_H
#define _SYS_CONTRACT_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/list.h>
#include <sys/poll.h>
@@ -108,6 +106,15 @@ typedef struct ct_param32 {
#endif /* _SYSCALL32 */
+/*
+ * in kernel version of parameter structure.
+ */
+typedef struct ct_kparam {
+ ct_param_t param; /* copy of user ct_param_t */
+ void *ctpm_kbuf; /* kernel buffer for parameter value */
+ uint32_t ret_size; /* parameter value size for copyout */
+} ct_kparam_t;
+
struct proc;
/*
@@ -116,9 +123,9 @@ struct proc;
typedef struct ctmplops {
struct ct_template *(*ctop_dup)(struct ct_template *);
void (*ctop_free)(struct ct_template *);
- int (*ctop_set)(struct ct_template *, ct_param_t *,
+ int (*ctop_set)(struct ct_template *, ct_kparam_t *,
const cred_t *);
- int (*ctop_get)(struct ct_template *, ct_param_t *);
+ int (*ctop_get)(struct ct_template *, ct_kparam_t *);
int (*ctop_create)(struct ct_template *, ctid_t *);
uint_t allevents;
} ctmplops_t;
@@ -308,14 +315,20 @@ typedef struct ct_listener {
* Contract template interfaces
*/
void ctmpl_free(ct_template_t *);
-int ctmpl_set(ct_template_t *, ct_param_t *, const cred_t *);
-int ctmpl_get(ct_template_t *, ct_param_t *);
+int ctmpl_set(ct_template_t *, ct_kparam_t *, const cred_t *);
+int ctmpl_get(ct_template_t *, ct_kparam_t *);
ct_template_t *ctmpl_dup(ct_template_t *);
void ctmpl_activate(ct_template_t *);
void ctmpl_clear(ct_template_t *);
int ctmpl_create(ct_template_t *, ctid_t *);
/*
+ * Contract parameter functions
+ */
+int ctparam_copyin(const void *, ct_kparam_t *, int, int);
+int ctparam_copyout(ct_kparam_t *, void *, int);
+
+/*
* Contract functions
*/
void contract_init(void);