summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_proc.c54
-rw-r--r--sys/kern/kern_sysctl.c5
-rw-r--r--sys/kern/vfs_lockf.c68
-rw-r--r--sys/sys/lockf.h3
-rw-r--r--sys/sys/proc.h12
-rw-r--r--sys/sys/sysctl.h6
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 }, \
}
/*