Module Name: src Committed By: christos Date: Sun Jan 28 22:24:58 UTC 2018
Modified Files: src/sys/kern: subr_interrupt.c Log Message: - don't return ENOMEM for errors not related to memory - don't overload return values (-error/+size) - don't allocate kernel memory from user supplied length. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/sys/kern/subr_interrupt.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/subr_interrupt.c diff -u src/sys/kern/subr_interrupt.c:1.3 src/sys/kern/subr_interrupt.c:1.4 --- src/sys/kern/subr_interrupt.c:1.3 Sat Jan 13 08:53:36 2018 +++ src/sys/kern/subr_interrupt.c Sun Jan 28 17:24:58 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_interrupt.c,v 1.3 2018/01/13 13:53:36 reinoud Exp $ */ +/* $NetBSD: subr_interrupt.c,v 1.4 2018/01/28 22:24:58 christos Exp $ */ /* * Copyright (c) 2015 Internet Initiative Japan Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: subr_interrupt.c,v 1.3 2018/01/13 13:53:36 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_interrupt.c,v 1.4 2018/01/28 22:24:58 christos Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -133,7 +133,7 @@ interrupt_avert_intr(u_int cpu_idx) ii_handler = interrupt_construct_intrids(cpuset); if (ii_handler == NULL) { - error = ENOMEM; + error = EINVAL; goto out; } nids = ii_handler->iih_nids; @@ -180,25 +180,24 @@ interrupt_intrio_list_line_size(void) * Return the size of interrupts list data on success. * Reterun 0 on failed. */ -static size_t -interrupt_intrio_list_size(void) +static int +interrupt_intrio_list_size(size_t *ilsize) { struct intrids_handler *ii_handler; - size_t ilsize; - ilsize = 0; + *ilsize = 0; /* buffer header */ - ilsize += sizeof(struct intrio_list); + *ilsize += sizeof(struct intrio_list); /* il_line body */ ii_handler = interrupt_construct_intrids(kcpuset_running); if (ii_handler == NULL) - return 0; - ilsize += interrupt_intrio_list_line_size() * (ii_handler->iih_nids); + return EOPNOTSUPP; + *ilsize += interrupt_intrio_list_line_size() * ii_handler->iih_nids; interrupt_destruct_intrids(ii_handler); - return ilsize; + return 0; } /* @@ -207,28 +206,17 @@ interrupt_intrio_list_size(void) * If "data" == NULL, simply return list structure bytes. */ static int -interrupt_intrio_list(struct intrio_list *il, int length) +interrupt_intrio_list(struct intrio_list *il, size_t ilsize) { struct intrio_list_line *illine; kcpuset_t *assigned, *avail; struct intrids_handler *ii_handler; intrid_t *ids; - size_t ilsize; u_int cpu_idx; - int nids, intr_idx, ret, line_size; - - ilsize = interrupt_intrio_list_size(); - if (ilsize == 0) - return -ENOMEM; - - if (il == NULL) - return ilsize; - - if (length < ilsize) - return -ENOMEM; + int nids, intr_idx, error, line_size; illine = (struct intrio_list_line *) - ((char *)il + sizeof(struct intrio_list)); + ((char *)il + sizeof(struct intrio_list)); il->il_lineoffset = (off_t)((uintptr_t)illine - (uintptr_t)il); kcpuset_create(&avail, true); @@ -238,19 +226,19 @@ interrupt_intrio_list(struct intrio_list ii_handler = interrupt_construct_intrids(kcpuset_running); if (ii_handler == NULL) { DPRINTF(("%s: interrupt_construct_intrids() failed\n", - __func__)); - ret = -ENOMEM; + __func__)); + error = EOPNOTSUPP; goto out; } line_size = interrupt_intrio_list_line_size(); - /* ensure interrupts are not added after interrupt_intrio_list_size(). */ + /* ensure interrupts are not added after interrupt_intrio_list_size() */ nids = ii_handler->iih_nids; ids = ii_handler->iih_intrids; if (ilsize < sizeof(struct intrio_list) + line_size * nids) { DPRINTF(("%s: interrupts are added during execution.\n", - __func__)); - ret = -ENOMEM; + __func__)); + error = EAGAIN; goto destruct_out; } @@ -264,19 +252,19 @@ interrupt_intrio_list(struct intrio_list interrupt_get_assigned(ids[intr_idx], assigned); for (cpu_idx = 0; cpu_idx < ncpu; cpu_idx++) { struct intrio_list_line_cpu *illcpu = - &illine->ill_cpu[cpu_idx]; + &illine->ill_cpu[cpu_idx]; illcpu->illc_assigned = - kcpuset_isset(assigned, cpu_idx) ? true : false; + kcpuset_isset(assigned, cpu_idx); illcpu->illc_count = - interrupt_get_count(ids[intr_idx], cpu_idx); + interrupt_get_count(ids[intr_idx], cpu_idx); } illine = (struct intrio_list_line *) - ((char *)illine + line_size); + ((char *)illine + line_size); } - ret = ilsize; + error = 0; il->il_version = INTRIO_LIST_VERSION; il->il_ncpus = ncpu; il->il_nintrs = nids; @@ -289,7 +277,7 @@ interrupt_intrio_list(struct intrio_list kcpuset_destroy(assigned); kcpuset_destroy(avail); - return ret; + return error; } /* @@ -298,42 +286,39 @@ interrupt_intrio_list(struct intrio_list static int interrupt_intrio_list_sysctl(SYSCTLFN_ARGS) { - int ret, error; + int error; void *buf; + size_t ilsize; if (oldlenp == NULL) return EINVAL; + if ((error = interrupt_intrio_list_size(&ilsize)) != 0) + return error; + /* * If oldp == NULL, the sysctl(8) caller process want to get the size of * intrctl list data only. */ if (oldp == NULL) { - ret = interrupt_intrio_list(NULL, 0); - if (ret < 0) - return -ret; - - *oldlenp = ret; + *oldlenp = ilsize; return 0; } /* - * If oldp != NULL, the sysctl(8) caller process want to get both the size - * and the contents of intrctl list data. + * If oldp != NULL, the sysctl(8) caller process want to get both the + * size and the contents of intrctl list data. */ - if (*oldlenp == 0) + if (*oldlenp < ilsize) return ENOMEM; - buf = kmem_zalloc(*oldlenp, KM_SLEEP); - ret = interrupt_intrio_list(buf, *oldlenp); - if (ret < 0) { - error = -ret; + buf = kmem_zalloc(ilsize, KM_SLEEP); + if ((error = interrupt_intrio_list(buf, ilsize)) != 0) goto out; - } - error = copyout(buf, oldp, *oldlenp); + error = copyout(buf, oldp, ilsize); out: - kmem_free(buf, *oldlenp); + kmem_free(buf, ilsize); return error; }