1 1.13 riastrad /* $NetBSD: kern_uidinfo.c,v 1.13 2021/12/28 13:28:24 riastradh Exp $ */ 2 1.1 pooka 3 1.1 pooka /*- 4 1.1 pooka * Copyright (c) 1982, 1986, 1991, 1993 5 1.1 pooka * The Regents of the University of California. All rights reserved. 6 1.1 pooka * (c) UNIX System Laboratories, Inc. 7 1.1 pooka * All or some portions of this file are derived from material licensed 8 1.1 pooka * to the University of California by American Telephone and Telegraph 9 1.1 pooka * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 1.1 pooka * the permission of UNIX System Laboratories, Inc. 11 1.1 pooka * 12 1.1 pooka * Redistribution and use in source and binary forms, with or without 13 1.1 pooka * modification, are permitted provided that the following conditions 14 1.1 pooka * are met: 15 1.1 pooka * 1. Redistributions of source code must retain the above copyright 16 1.1 pooka * notice, this list of conditions and the following disclaimer. 17 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 pooka * notice, this list of conditions and the following disclaimer in the 19 1.1 pooka * documentation and/or other materials provided with the distribution. 20 1.1 pooka * 3. Neither the name of the University nor the names of its contributors 21 1.1 pooka * may be used to endorse or promote products derived from this software 22 1.1 pooka * without specific prior written permission. 23 1.1 pooka * 24 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 1.1 pooka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 1.1 pooka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 1.1 pooka * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 1.1 pooka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.1 pooka * SUCH DAMAGE. 35 1.1 pooka */ 36 1.1 pooka 37 1.1 pooka #include <sys/cdefs.h> 38 1.13 riastrad __KERNEL_RCSID(0, "$NetBSD: kern_uidinfo.c,v 1.13 2021/12/28 13:28:24 riastradh Exp $"); 39 1.1 pooka 40 1.1 pooka #include <sys/param.h> 41 1.1 pooka #include <sys/systm.h> 42 1.1 pooka #include <sys/kmem.h> 43 1.1 pooka #include <sys/proc.h> 44 1.1 pooka #include <sys/atomic.h> 45 1.1 pooka #include <sys/uidinfo.h> 46 1.6 christos #include <sys/sysctl.h> 47 1.6 christos #include <sys/kauth.h> 48 1.5 ad #include <sys/cpu.h> 49 1.1 pooka 50 1.1 pooka static SLIST_HEAD(uihashhead, uidinfo) *uihashtbl; 51 1.1 pooka static u_long uihash; 52 1.1 pooka 53 1.1 pooka #define UIHASH(uid) (&uihashtbl[(uid) & uihash]) 54 1.1 pooka 55 1.6 christos static int 56 1.6 christos sysctl_kern_uidinfo_cnt(SYSCTLFN_ARGS) 57 1.9 riastrad { 58 1.6 christos static const struct { 59 1.6 christos const char *name; 60 1.6 christos u_int value; 61 1.6 christos } nv[] = { 62 1.6 christos #define _MEM(n) { # n, offsetof(struct uidinfo, ui_ ## n) } 63 1.6 christos _MEM(proccnt), 64 1.6 christos _MEM(lwpcnt), 65 1.6 christos _MEM(lockcnt), 66 1.11 christos _MEM(semcnt), 67 1.6 christos _MEM(sbsize), 68 1.6 christos #undef _MEM 69 1.6 christos }; 70 1.6 christos 71 1.6 christos for (size_t i = 0; i < __arraycount(nv); i++) 72 1.6 christos if (strcmp(nv[i].name, rnode->sysctl_name) == 0) { 73 1.6 christos uint64_t cnt; 74 1.6 christos struct sysctlnode node = *rnode; 75 1.6 christos struct uidinfo *uip; 76 1.6 christos 77 1.6 christos node.sysctl_data = &cnt; 78 1.6 christos uip = uid_find(kauth_cred_geteuid(l->l_cred)); 79 1.6 christos 80 1.9 riastrad *(uint64_t *)node.sysctl_data = 81 1.6 christos *(u_long *)((char *)uip + nv[i].value); 82 1.6 christos 83 1.6 christos return sysctl_lookup(SYSCTLFN_CALL(&node)); 84 1.6 christos } 85 1.6 christos 86 1.6 christos return EINVAL; 87 1.6 christos } 88 1.6 christos 89 1.8 pooka static struct sysctllog *kern_uidinfo_sysctllog; 90 1.8 pooka 91 1.6 christos static void 92 1.6 christos sysctl_kern_uidinfo_setup(void) 93 1.6 christos { 94 1.6 christos const struct sysctlnode *rnode, *cnode; 95 1.6 christos 96 1.6 christos sysctl_createv(&kern_uidinfo_sysctllog, 0, NULL, &rnode, 97 1.6 christos CTLFLAG_PERMANENT, 98 1.6 christos CTLTYPE_NODE, "uidinfo", 99 1.6 christos SYSCTL_DESCR("Resource usage per uid"), 100 1.6 christos NULL, 0, NULL, 0, 101 1.6 christos CTL_KERN, CTL_CREATE, CTL_EOL); 102 1.6 christos 103 1.6 christos sysctl_createv(&kern_uidinfo_sysctllog, 0, &rnode, &cnode, 104 1.6 christos CTLFLAG_PERMANENT, 105 1.6 christos CTLTYPE_QUAD, "proccnt", 106 1.6 christos SYSCTL_DESCR("Number of processes for the current user"), 107 1.6 christos sysctl_kern_uidinfo_cnt, 0, NULL, 0, 108 1.6 christos CTL_CREATE, CTL_EOL); 109 1.6 christos sysctl_createv(&kern_uidinfo_sysctllog, 0, &rnode, &cnode, 110 1.6 christos CTLFLAG_PERMANENT, 111 1.6 christos CTLTYPE_QUAD, "lwpcnt", 112 1.6 christos SYSCTL_DESCR("Number of lwps for the current user"), 113 1.6 christos sysctl_kern_uidinfo_cnt, 0, NULL, 0, 114 1.6 christos CTL_CREATE, CTL_EOL); 115 1.6 christos sysctl_createv(&kern_uidinfo_sysctllog, 0, &rnode, &cnode, 116 1.6 christos CTLFLAG_PERMANENT, 117 1.6 christos CTLTYPE_QUAD, "lockcnt", 118 1.6 christos SYSCTL_DESCR("Number of locks for the current user"), 119 1.6 christos sysctl_kern_uidinfo_cnt, 0, NULL, 0, 120 1.6 christos CTL_CREATE, CTL_EOL); 121 1.6 christos sysctl_createv(&kern_uidinfo_sysctllog, 0, &rnode, &cnode, 122 1.6 christos CTLFLAG_PERMANENT, 123 1.11 christos CTLTYPE_QUAD, "semcnt", 124 1.11 christos SYSCTL_DESCR("Number of semaphores used for the current user"), 125 1.11 christos sysctl_kern_uidinfo_cnt, 0, NULL, 0, 126 1.11 christos CTL_CREATE, CTL_EOL); 127 1.11 christos sysctl_createv(&kern_uidinfo_sysctllog, 0, &rnode, &cnode, 128 1.11 christos CTLFLAG_PERMANENT, 129 1.6 christos CTLTYPE_QUAD, "sbsize", 130 1.6 christos SYSCTL_DESCR("Socket buffers used for the current user"), 131 1.6 christos sysctl_kern_uidinfo_cnt, 0, NULL, 0, 132 1.6 christos CTL_CREATE, CTL_EOL); 133 1.6 christos } 134 1.6 christos 135 1.12 simonb static int 136 1.12 simonb uid_stats(struct hashstat_sysctl *hs, bool fill) 137 1.12 simonb { 138 1.12 simonb struct uidinfo *uip; 139 1.12 simonb uint64_t chain; 140 1.12 simonb 141 1.12 simonb strlcpy(hs->hash_name, "uihash", sizeof(hs->hash_name)); 142 1.12 simonb strlcpy(hs->hash_desc, "user info (uid->used proc) hash", 143 1.12 simonb sizeof(hs->hash_desc)); 144 1.12 simonb if (!fill) 145 1.12 simonb return 0; 146 1.12 simonb 147 1.12 simonb hs->hash_size = uihash + 1; 148 1.12 simonb 149 1.12 simonb for (size_t i = 0; i < hs->hash_size; i++) { 150 1.12 simonb chain = 0; 151 1.12 simonb SLIST_FOREACH(uip, &uihashtbl[i], ui_hash) { 152 1.12 simonb membar_datadep_consumer(); 153 1.12 simonb chain++; 154 1.12 simonb } 155 1.12 simonb if (chain > 0) { 156 1.12 simonb hs->hash_used++; 157 1.12 simonb hs->hash_items += chain; 158 1.12 simonb if (chain > hs->hash_maxchain) 159 1.12 simonb hs->hash_maxchain = chain; 160 1.12 simonb } 161 1.12 simonb } 162 1.12 simonb 163 1.12 simonb return 0; 164 1.12 simonb } 165 1.12 simonb 166 1.1 pooka void 167 1.1 pooka uid_init(void) 168 1.1 pooka { 169 1.1 pooka 170 1.1 pooka /* 171 1.1 pooka * In case of MP system, SLIST_FOREACH would force a cache line 172 1.1 pooka * write-back for every modified 'uidinfo', thus we try to keep the 173 1.1 pooka * lists short. 174 1.1 pooka */ 175 1.5 ad const u_int uihash_sz = (maxcpus > 1 ? 1024 : 64); 176 1.1 pooka 177 1.1 pooka uihashtbl = hashinit(uihash_sz, HASH_SLIST, true, &uihash); 178 1.1 pooka 179 1.1 pooka /* 180 1.1 pooka * Ensure that uid 0 is always in the user hash table, as 181 1.1 pooka * sbreserve() expects it available from interrupt context. 182 1.1 pooka */ 183 1.1 pooka (void)uid_find(0); 184 1.6 christos sysctl_kern_uidinfo_setup(); 185 1.12 simonb hashstat_register("uihash", uid_stats); 186 1.1 pooka } 187 1.1 pooka 188 1.1 pooka struct uidinfo * 189 1.1 pooka uid_find(uid_t uid) 190 1.1 pooka { 191 1.1 pooka struct uidinfo *uip, *uip_first, *newuip; 192 1.1 pooka struct uihashhead *uipp; 193 1.1 pooka 194 1.1 pooka uipp = UIHASH(uid); 195 1.1 pooka newuip = NULL; 196 1.1 pooka 197 1.1 pooka /* 198 1.1 pooka * To make insertion atomic, abstraction of SLIST will be violated. 199 1.1 pooka */ 200 1.1 pooka uip_first = uipp->slh_first; 201 1.1 pooka again: 202 1.1 pooka SLIST_FOREACH(uip, uipp, ui_hash) { 203 1.10 riastrad membar_datadep_consumer(); 204 1.1 pooka if (uip->ui_uid != uid) 205 1.1 pooka continue; 206 1.2 ad if (newuip != NULL) 207 1.1 pooka kmem_free(newuip, sizeof(*newuip)); 208 1.1 pooka return uip; 209 1.1 pooka } 210 1.2 ad if (newuip == NULL) 211 1.1 pooka newuip = kmem_zalloc(sizeof(*newuip), KM_SLEEP); 212 1.1 pooka newuip->ui_uid = uid; 213 1.1 pooka 214 1.1 pooka /* 215 1.1 pooka * If atomic insert is unsuccessful, another thread might be 216 1.1 pooka * allocated this 'uid', thus full re-check is needed. 217 1.1 pooka */ 218 1.1 pooka newuip->ui_hash.sle_next = uip_first; 219 1.1 pooka membar_producer(); 220 1.1 pooka uip = atomic_cas_ptr(&uipp->slh_first, uip_first, newuip); 221 1.1 pooka if (uip != uip_first) { 222 1.1 pooka uip_first = uip; 223 1.1 pooka goto again; 224 1.1 pooka } 225 1.1 pooka 226 1.1 pooka return newuip; 227 1.1 pooka } 228 1.1 pooka 229 1.1 pooka /* 230 1.1 pooka * Change the count associated with number of processes 231 1.1 pooka * a given user is using. 232 1.1 pooka */ 233 1.1 pooka int 234 1.1 pooka chgproccnt(uid_t uid, int diff) 235 1.1 pooka { 236 1.1 pooka struct uidinfo *uip; 237 1.1 pooka long proccnt; 238 1.1 pooka 239 1.1 pooka uip = uid_find(uid); 240 1.1 pooka proccnt = atomic_add_long_nv(&uip->ui_proccnt, diff); 241 1.13 riastrad KASSERTMSG(proccnt >= 0, "uid=%d diff=%d proccnt=%ld", 242 1.13 riastrad uid, diff, proccnt); 243 1.1 pooka return proccnt; 244 1.1 pooka } 245 1.1 pooka 246 1.6 christos /* 247 1.6 christos * Change the count associated with number of lwps 248 1.6 christos * a given user is using. 249 1.6 christos */ 250 1.6 christos int 251 1.6 christos chglwpcnt(uid_t uid, int diff) 252 1.6 christos { 253 1.6 christos struct uidinfo *uip; 254 1.6 christos long lwpcnt; 255 1.6 christos 256 1.6 christos uip = uid_find(uid); 257 1.6 christos lwpcnt = atomic_add_long_nv(&uip->ui_lwpcnt, diff); 258 1.13 riastrad KASSERTMSG(lwpcnt >= 0, "uid=%d diff=%d lwpcnt=%ld", 259 1.13 riastrad uid, diff, lwpcnt); 260 1.6 christos return lwpcnt; 261 1.6 christos } 262 1.6 christos 263 1.11 christos /* 264 1.11 christos * Change the count associated with number of semaphores 265 1.11 christos * a given user is using. 266 1.11 christos */ 267 1.11 christos int 268 1.11 christos chgsemcnt(uid_t uid, int diff) 269 1.11 christos { 270 1.11 christos struct uidinfo *uip; 271 1.11 christos long semcnt; 272 1.11 christos 273 1.11 christos uip = uid_find(uid); 274 1.11 christos semcnt = atomic_add_long_nv(&uip->ui_semcnt, diff); 275 1.13 riastrad KASSERTMSG(semcnt >= 0, "uid=%d diff=%d semcnt=%ld", 276 1.13 riastrad uid, diff, semcnt); 277 1.11 christos return semcnt; 278 1.11 christos } 279 1.11 christos 280 1.1 pooka int 281 1.1 pooka chgsbsize(struct uidinfo *uip, u_long *hiwat, u_long to, rlim_t xmax) 282 1.1 pooka { 283 1.1 pooka rlim_t nsb; 284 1.2 ad const long diff = to - *hiwat; 285 1.1 pooka 286 1.3 ad nsb = (rlim_t)atomic_add_long_nv((long *)&uip->ui_sbsize, diff); 287 1.3 ad if (diff > 0 && nsb > xmax) { 288 1.2 ad atomic_add_long((long *)&uip->ui_sbsize, -diff); 289 1.1 pooka return 0; 290 1.1 pooka } 291 1.1 pooka *hiwat = to; 292 1.1 pooka return 1; 293 1.1 pooka } 294