diff options
| author | Antonello Cruz <Antonello.Cruz@Sun.COM> | 2008-10-24 12:57:08 -0700 |
|---|---|---|
| committer | Antonello Cruz <Antonello.Cruz@Sun.COM> | 2008-10-24 12:57:08 -0700 |
| commit | c5a9a4fc75359f623d03e4eab6a03c9cabe175a3 (patch) | |
| tree | 545e7bf9b55a6e84eb99bd47b8425375a3c9df51 /usr | |
| parent | 4f2e01b27b6f050ac264ee29e4fea7a9045ce86e (diff) | |
| download | illumos-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.c | 21 | ||||
| -rw-r--r-- | usr/src/uts/common/contract/process.c | 37 | ||||
| -rw-r--r-- | usr/src/uts/common/fs/ctfs/ctfs_tmpl.c | 56 | ||||
| -rw-r--r-- | usr/src/uts/common/fs/proc/prioctl.c | 29 | ||||
| -rw-r--r-- | usr/src/uts/common/os/contract.c | 97 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/contract_impl.h | 25 |
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, ¶m, 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, ¶m); - 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, ¶m, 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, ¶m, cr); + error = ctmpl_set(tmpl, &kparam, cr); else - error = ctmpl_get(tmpl, ¶m); + error = ctmpl_get(tmpl, &kparam); prunlock(pnp); - if (cmd == CT_TGET && error == 0 && - copyout(¶m, (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); |
