diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_proc.c | 54 | ||||
-rw-r--r-- | sys/kern/kern_sysctl.c | 5 | ||||
-rw-r--r-- | sys/kern/vfs_lockf.c | 68 | ||||
-rw-r--r-- | sys/sys/lockf.h | 3 | ||||
-rw-r--r-- | sys/sys/proc.h | 12 | ||||
-rw-r--r-- | sys/sys/sysctl.h | 6 |
6 files changed, 96 insertions, 52 deletions
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 962fe11dea4..2ba584ca631 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_proc.c,v 1.24 2004/12/26 21:22:13 miod Exp $ */ +/* $OpenBSD: kern_proc.c,v 1.25 2005/03/10 17:26:10 tedu Exp $ */ /* $NetBSD: kern_proc.c,v 1.14 1996/02/09 18:59:41 christos Exp $ */ /* @@ -49,14 +49,6 @@ #include <sys/signalvar.h> #include <sys/pool.h> -/* - * Structure associated with user caching. - */ -struct uidinfo { - LIST_ENTRY(uidinfo) ui_hash; - uid_t ui_uid; - long ui_proccnt; -}; #define UIHASH(uid) (&uihashtbl[(uid) & uihash]) LIST_HEAD(uihashhead, uidinfo) *uihashtbl; u_long uihash; /* size of hash table - 1 */ @@ -115,38 +107,36 @@ procinit() * Change the count associated with number of processes * a given user is using. */ -int -chgproccnt(uid, diff) - uid_t uid; - int diff; +struct uidinfo * +uid_find(uid_t uid) { - register struct uidinfo *uip; - register struct uihashhead *uipp; + struct uidinfo *uip; + struct uihashhead *uipp; uipp = UIHASH(uid); LIST_FOREACH(uip, uipp, ui_hash) if (uip->ui_uid == uid) break; - if (uip) { - uip->ui_proccnt += diff; - if (uip->ui_proccnt > 0) - return (uip->ui_proccnt); - if (uip->ui_proccnt < 0) - panic("chgproccnt: procs < 0"); - LIST_REMOVE(uip, ui_hash); - FREE(uip, M_PROC); - return (0); - } - if (diff <= 0) { - if (diff == 0) - return(0); - panic("chgproccnt: lost user"); - } + if (uip) + return (uip); MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK); + bzero(uip, sizeof(*uip)); LIST_INSERT_HEAD(uipp, uip, ui_hash); uip->ui_uid = uid; - uip->ui_proccnt = diff; - return (diff); + + return (uip); +} + +int +chgproccnt(uid_t uid, int diff) +{ + struct uidinfo *uip; + + uip = uid_find(uid); + uip->ui_proccnt += diff; + if (uip->ui_proccnt < 0) + panic("chgproccnt: procs < 0"); + return (uip->ui_proccnt); } /* diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 5eb3744711f..7dad32b0e3b 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sysctl.c,v 1.123 2004/12/24 17:28:13 miod Exp $ */ +/* $OpenBSD: kern_sysctl.c,v 1.124 2005/03/10 17:26:10 tedu Exp $ */ /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ /*- @@ -266,6 +266,7 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) extern int userasymcrypto; extern int cryptodevallowsoft; #endif + extern int maxlocksperuid; /* all sysctl names at this level are terminal except a ton of them */ if (namelen != 1) { @@ -537,6 +538,8 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) return (sysctl_tc(name + 1, namelen - 1, oldp, oldlenp, newp, newlen)); #endif + case KERN_MAXLOCKSPERUID: + return (sysctl_int(oldp, oldlenp, newp, newlen, &maxlocksperuid)); default: return (EOPNOTSUPP); } diff --git a/sys/kern/vfs_lockf.c b/sys/kern/vfs_lockf.c index 4d1bf42f948..b01a869708d 100644 --- a/sys/kern/vfs_lockf.c +++ b/sys/kern/vfs_lockf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_lockf.c,v 1.9 2004/04/13 00:15:28 tedu Exp $ */ +/* $OpenBSD: vfs_lockf.c,v 1.10 2005/03/10 17:26:10 tedu Exp $ */ /* $NetBSD: vfs_lockf.c,v 1.7 1996/02/04 02:18:21 christos Exp $ */ /* @@ -79,6 +79,41 @@ lf_init(void) "lockfpl", &pool_allocator_nointr); } +struct lockf *lf_alloc(uid_t, int); +void lf_free(struct lockf *); + +/* + * We enforce a limit on locks by uid, so that a single user cannot + * run the kernel out of memory. For now, the limit is pretty coarse. + * There is no limit on root. + */ +int maxlocksperuid = 1024; + +struct lockf * +lf_alloc(uid_t uid, int allowfail) +{ + struct uidinfo *uip; + struct lockf *lock; + + uip = uid_find(uid); + if (uid && allowfail && uip->ui_lockcnt > maxlocksperuid) + return (NULL); + uip->ui_lockcnt++; + lock = pool_get(&lockfpool, PR_WAITOK); + lock->lf_uid = uid; + return (lock); +} +void +lf_free(struct lockf *lock) +{ + struct uidinfo *uip; + + uip = uid_find(lock->lf_uid); + uip->ui_lockcnt--; + pool_put(&lockfpool, lock); +} + + /* * Do an advisory lock operation. */ @@ -91,6 +126,7 @@ lf_advlock(head, size, id, op, fl, flags) register struct flock *fl; int flags; { + struct proc *p = curproc; register struct lockf *lock; off_t start, end; int error; @@ -139,7 +175,9 @@ lf_advlock(head, size, id, op, fl, flags) /* * Create the lockf structure. */ - lock = pool_get(&lockfpool, PR_WAITOK); + lock = lf_alloc(p->p_ucred->cr_uid, op != F_UNLCK); + if (!lock) + return (ENOMEM); lock->lf_start = start; lock->lf_end = end; lock->lf_id = id; @@ -158,16 +196,16 @@ lf_advlock(head, size, id, op, fl, flags) case F_UNLCK: error = lf_clearlock(lock); - pool_put(&lockfpool, lock); + lf_free(lock); return (error); case F_GETLK: error = lf_getlock(lock, fl); - pool_put(&lockfpool, lock); + lf_free(lock); return (error); default: - pool_put(&lockfpool, lock); + lf_free(lock); return (EINVAL); } /* NOTREACHED */ @@ -206,7 +244,7 @@ lf_setlock(lock) * Free the structure and return if nonblocking. */ if ((lock->lf_flags & F_WAIT) == 0) { - pool_put(&lockfpool, lock); + lf_free(lock); return (EAGAIN); } /* @@ -237,7 +275,7 @@ lf_setlock(lock) break; wproc = (struct proc *)waitblock->lf_id; if (wproc == (struct proc *)lock->lf_id) { - pool_put(&lockfpool, lock); + lf_free(lock); return (EDEADLK); } } @@ -272,7 +310,7 @@ lf_setlock(lock) * Delete ourselves from the waiting to lock list. */ TAILQ_REMOVE(&lock->lf_next->lf_blkhd, lock, lf_block); - pool_put(&lockfpool, lock); + lf_free(lock); return (error); } #else @@ -281,7 +319,7 @@ lf_setlock(lock) lock->lf_next = NULL; } if (error) { - pool_put(&lockfpool, lock); + lf_free(lock); return (error); } #endif @@ -327,7 +365,7 @@ lf_setlock(lock) overlap->lf_type == F_WRLCK) lf_wakelock(overlap); overlap->lf_type = lock->lf_type; - pool_put(&lockfpool, lock); + lf_free(lock); lock = overlap; /* for debug output below */ break; @@ -336,7 +374,7 @@ lf_setlock(lock) * Check for common starting point and different types. */ if (overlap->lf_type == lock->lf_type) { - pool_put(&lockfpool, lock); + lf_free(lock); lock = overlap; /* for debug output below */ break; } @@ -377,7 +415,7 @@ lf_setlock(lock) needtolink = 0; } else *prev = overlap->lf_next; - pool_put(&lockfpool, overlap); + lf_free(overlap); continue; case 4: /* overlap starts before lock */ @@ -447,7 +485,7 @@ lf_clearlock(lock) case 1: /* overlap == lock */ *prev = overlap->lf_next; - pool_put(&lockfpool, overlap); + lf_free(overlap); break; case 2: /* overlap contains lock: split it */ @@ -462,7 +500,7 @@ lf_clearlock(lock) case 3: /* lock contains overlap */ *prev = overlap->lf_next; lf = overlap->lf_next; - pool_put(&lockfpool, overlap); + lf_free(overlap); continue; case 4: /* overlap starts before lock */ @@ -672,7 +710,7 @@ lf_split(lock1, lock2) * Make a new lock consisting of the last part of * the encompassing lock */ - splitlock = pool_get(&lockfpool, PR_WAITOK); + splitlock = lf_alloc(lock1->lf_uid, 0); memcpy(splitlock, lock1, sizeof(*splitlock)); splitlock->lf_start = lock2->lf_end + 1; splitlock->lf_block.tqe_next = NULL; diff --git a/sys/sys/lockf.h b/sys/sys/lockf.h index 35e6da253fd..1b17d451522 100644 --- a/sys/sys/lockf.h +++ b/sys/sys/lockf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lockf.h,v 1.6 2004/01/14 19:34:05 grange Exp $ */ +/* $OpenBSD: lockf.h,v 1.7 2005/03/10 17:26:10 tedu Exp $ */ /* $NetBSD: lockf.h,v 1.5 1994/06/29 06:44:33 cgd Exp $ */ /* @@ -53,6 +53,7 @@ struct lockf { struct lockf *lf_next; /* A pointer to the next lock on this inode */ struct locklist lf_blkhd; /* The list of blocked locks */ TAILQ_ENTRY(lockf) lf_block; /* A request waiting for a lock */ + uid_t lf_uid; /* User ID responsible */ }; /* Maximum length of sleep chains to traverse to try and detect deadlock. */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index a8746d3eecf..d7a789b17e1 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.76 2004/11/23 19:08:55 miod Exp $ */ +/* $OpenBSD: proc.h,v 1.77 2005/03/10 17:26:10 tedu Exp $ */ /* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */ /*- @@ -314,6 +314,16 @@ struct pcred { }; #ifdef _KERNEL + +struct uidinfo { + LIST_ENTRY(uidinfo) ui_hash; + uid_t ui_uid; + long ui_proccnt; /* proc structs */ + long ui_lockcnt; /* lockf structs */ +}; + +struct uidinfo *uid_find(uid_t); + /* * We use process IDs <= PID_MAX; PID_MAX + 1 must also fit in a pid_t, * as it is used to represent "no process group". diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index d46a08bd585..eded7e9a0d4 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sysctl.h,v 1.81 2004/08/04 23:33:32 deraadt Exp $ */ +/* $OpenBSD: sysctl.h,v 1.82 2005/03/10 17:26:10 tedu Exp $ */ /* $NetBSD: sysctl.h,v 1.16 1996/04/09 20:55:36 cgd Exp $ */ /* @@ -182,7 +182,8 @@ struct ctlname { #define KERN_MAXCLUSTERS 67 /* number of mclusters */ #define KERN_EVCOUNT 68 /* node: event counters */ #define KERN_TIMECOUNTER 69 /* node: timecounter */ -#define KERN_MAXID 70 /* number of valid kern ids */ +#define KERN_MAXLOCKSPERUID 70 /* int: locks per uid */ +#define KERN_MAXID 71 /* number of valid kern ids */ #define CTL_KERN_NAMES { \ { 0, 0 }, \ @@ -255,6 +256,7 @@ struct ctlname { { "maxclusters", CTLTYPE_INT }, \ { "evcount", CTLTYPE_NODE }, \ { "timecounter", CTLTYPE_NODE }, \ + { "maxlocksperuid", CTLTYPE_INT }, \ } /* |