diff options
author | gjb <gjb@FreeBSD.org> | 2014-06-27 22:05:21 +0000 |
---|---|---|
committer | gjb <gjb@FreeBSD.org> | 2014-06-27 22:05:21 +0000 |
commit | fc21f40567ac7485e9e987cf5a539bd0d11c7155 (patch) | |
tree | fce5301b062a855bc68b9cb76c6b5966c5a2acbe /sys/kern/kern_sysctl.c | |
parent | 2f456747e010bfa5a9dd3498aa5650e0ade39f22 (diff) | |
download | FreeBSD-src-fc21f40567ac7485e9e987cf5a539bd0d11c7155.zip FreeBSD-src-fc21f40567ac7485e9e987cf5a539bd0d11c7155.tar.gz |
Revert r267961, r267973:
These changes prevent sysctl(8) from returning proper output,
such as:
1) no output from sysctl(8)
2) erroneously returning ENOMEM with tools like truss(1)
or uname(1)
truss: can not get etype: Cannot allocate memory
Diffstat (limited to 'sys/kern/kern_sysctl.c')
-rw-r--r-- | sys/kern/kern_sysctl.c | 193 |
1 files changed, 44 insertions, 149 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index cb5a266..fec4aea 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -98,13 +98,10 @@ static struct sx sysctlmemlock; static int sysctl_root(SYSCTL_HANDLER_ARGS); -/* Root list */ -struct sysctl_oid_list sysctl__children = SLIST_HEAD_INITIALIZER(&sysctl__children); +struct sysctl_oid_list sysctl__children; /* root list */ static int sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse); -static int sysctl_old_kernel(struct sysctl_req *, const void *, size_t); -static int sysctl_new_kernel(struct sysctl_req *, void *, size_t); static struct sysctl_oid * sysctl_find_oidname(const char *name, struct sysctl_oid_list *list) @@ -139,118 +136,6 @@ sysctl_unlock(void) SYSCTL_XUNLOCK(); } -static int -sysctl_root_handler_locked(struct sysctl_oid *oid, void *arg1, intptr_t arg2, - struct sysctl_req *req) -{ - int error; - - oid->oid_running++; - SYSCTL_XUNLOCK(); - - if (!(oid->oid_kind & CTLFLAG_MPSAFE)) - mtx_lock(&Giant); - error = oid->oid_handler(oid, arg1, arg2, req); - if (!(oid->oid_kind & CTLFLAG_MPSAFE)) - mtx_unlock(&Giant); - - SYSCTL_XLOCK(); - oid->oid_running--; - if (oid->oid_running == 0 && (oid->oid_kind & CTLFLAG_DYING) != 0) - wakeup(&oid->oid_running); - - return (error); -} - -static void -sysctl_load_tunable_by_oid_locked(struct sysctl_oid *oidp) -{ - struct sysctl_req req; - struct sysctl_oid *curr; - char *penv; - char path[64]; - ssize_t rem = sizeof(path); - ssize_t len; - int val_int; - long val_long; - int64_t val_64; - int error; - - path[--rem] = 0; - - for (curr = oidp; curr != NULL; curr = SYSCTL_PARENT(curr)) { - len = strlen(curr->oid_name); - rem -= len; - if (curr != oidp) - rem -= 1; - if (rem < 0) { - printf("OID path exceeds %d bytes\n", (int)sizeof(path)); - return; - } - memcpy(path + rem, curr->oid_name, len); - if (curr != oidp) - path[rem + len] = '.'; - } - - penv = getenv(path + rem); - if (penv == NULL) - return; - - memset(&req, 0, sizeof(req)); - - req.td = curthread; - req.oldfunc = sysctl_old_kernel; - req.newfunc = sysctl_new_kernel; - req.lock = REQ_UNWIRED; - - switch (oidp->oid_kind & CTLTYPE) { - case CTLTYPE_INT: - val_int = strtoq(penv, NULL, 0); - req.newlen = sizeof(val_int); - req.newptr = &val_int; - break; - case CTLTYPE_UINT: - val_int = strtouq(penv, NULL, 0); - req.newlen = sizeof(val_int); - req.newptr = &val_int; - break; - case CTLTYPE_LONG: - val_long = strtoq(penv, NULL, 0); - req.newlen = sizeof(val_long); - req.newptr = &val_long; - break; - case CTLTYPE_ULONG: - val_long = strtouq(penv, NULL, 0); - req.newlen = sizeof(val_long); - req.newptr = &val_long; - break; - case CTLTYPE_S64: - val_64 = strtoq(penv, NULL, 0); - req.newlen = sizeof(val_64); - req.newptr = &val_64; - break; - case CTLTYPE_U64: - val_64 = strtouq(penv, NULL, 0); - req.newlen = sizeof(val_64); - req.newptr = &val_64; - break; - case CTLTYPE_STRING: - req.newlen = strlen(penv); - req.newptr = penv; - break; - default: - freeenv(penv); - return; - } - error = sysctl_root_handler_locked(oidp, oidp->oid_arg1, - oidp->oid_arg2, &req); - if (error != 0) { - printf("Setting sysctl '%s' to '%s' failed: %d\n", - path, penv, error); - } - freeenv(penv); -} - void sysctl_register_oid(struct sysctl_oid *oidp) { @@ -307,15 +192,6 @@ sysctl_register_oid(struct sysctl_oid *oidp) SLIST_INSERT_AFTER(q, oidp, oid_link); else SLIST_INSERT_HEAD(parent, oidp, oid_link); - - if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE && -#ifdef VIMAGE - (oidp->oid_kind & CTLFLAG_VNET) == 0 && -#endif - (oidp->oid_kind & CTLFLAG_TUN) != 0 && - (oidp->oid_kind & CTLFLAG_NOFETCH) == 0) { - sysctl_load_tunable_by_oid_locked(oidp); - } } void @@ -547,6 +423,8 @@ sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse) if (error) return (error); } + if (del) + free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID); } } if (oidp->oid_refcnt > 1 ) { @@ -611,16 +489,24 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent, } oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO); oidp->oid_parent = parent; - SLIST_INIT(&oidp->oid_children); + SLIST_NEXT(oidp, oid_link) = NULL; oidp->oid_number = number; oidp->oid_refcnt = 1; oidp->oid_name = strdup(name, M_SYSCTLOID); oidp->oid_handler = handler; oidp->oid_kind = CTLFLAG_DYN | kind; - oidp->oid_arg1 = arg1; - oidp->oid_arg2 = arg2; + if ((kind & CTLTYPE) == CTLTYPE_NODE) { + /* Allocate space for children */ + SYSCTL_CHILDREN_SET(oidp, malloc(sizeof(struct sysctl_oid_list), + M_SYSCTLOID, M_WAITOK)); + SLIST_INIT(SYSCTL_CHILDREN(oidp)); + oidp->oid_arg2 = arg2; + } else { + oidp->oid_arg1 = arg1; + oidp->oid_arg2 = arg2; + } oidp->oid_fmt = fmt; - if (descr != NULL) + if (descr) oidp->oid_descr = strdup(descr, M_SYSCTLOID); /* Update the context, if used */ if (clist != NULL) @@ -691,7 +577,7 @@ sysctl_register_all(void *arg) sysctl_register_oid(*oidp); SYSCTL_XUNLOCK(); } -SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_FIRST, sysctl_register_all, 0); +SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0); /* * "Staff-functions" @@ -739,7 +625,7 @@ sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i) printf(" Node\n"); if (!oidp->oid_handler) { sysctl_sysctl_debug_dump_node( - SYSCTL_CHILDREN(oidp), i + 2); + oidp->oid_arg1, i+2); } break; case CTLTYPE_INT: printf(" Int\n"); break; @@ -1207,28 +1093,26 @@ sysctl_handle_64(SYSCTL_HANDLER_ARGS) int sysctl_handle_string(SYSCTL_HANDLER_ARGS) { + int error=0; + char *tmparg; size_t outlen; - int error = 0; - /* check for zero-length buffer */ - if (arg2 == 0) - return (ENOMEM); - - if (req->oldptr != NULL) { - char *tmparg; - - /* try to make a coherent snapshot of the string */ - tmparg = malloc(arg2, M_SYSCTLTMP, M_WAITOK); - memcpy(tmparg, arg1, arg2); - - outlen = strnlen(tmparg, arg2 - 1) + 1; - error = SYSCTL_OUT(req, tmparg, outlen); + /* + * Attempt to get a coherent snapshot by copying to a + * temporary kernel buffer. + */ +retry: + outlen = strlen((char *)arg1)+1; + tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK); + if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) { free(tmparg, M_SYSCTLTMP); - } else { - outlen = strnlen((char *)arg1, arg2 - 1) + 1; - error = SYSCTL_OUT(req, NULL, outlen); + goto retry; } + + error = SYSCTL_OUT(req, tmparg, outlen); + free(tmparg, M_SYSCTLTMP); + if (error || !req->newptr) return (error); @@ -1239,6 +1123,7 @@ sysctl_handle_string(SYSCTL_HANDLER_ARGS) error = SYSCTL_IN(req, arg1, arg2); ((char *)arg1)[arg2] = '\0'; } + return (error); } @@ -1604,14 +1489,24 @@ sysctl_root(SYSCTL_HANDLER_ARGS) if (error != 0) return (error); #endif + oid->oid_running++; + SYSCTL_XUNLOCK(); #ifdef VIMAGE if ((oid->oid_kind & CTLFLAG_VNET) && arg1 != NULL) arg1 = (void *)(curvnet->vnet_data_base + (uintptr_t)arg1); #endif - error = sysctl_root_handler_locked(oid, arg1, arg2, req); + if (!(oid->oid_kind & CTLFLAG_MPSAFE)) + mtx_lock(&Giant); + error = oid->oid_handler(oid, arg1, arg2, req); + if (!(oid->oid_kind & CTLFLAG_MPSAFE)) + mtx_unlock(&Giant); KFAIL_POINT_ERROR(_debug_fail_point, sysctl_running, error); + SYSCTL_XLOCK(); + oid->oid_running--; + if (oid->oid_running == 0 && (oid->oid_kind & CTLFLAG_DYING) != 0) + wakeup(&oid->oid_running); return (error); } |