untrusted comment: verify with openbsd-63-base.pub
RWRxzbLwAd76ZXrF5y82i+3P6GPPKyKMr+4Gavd+jzA1P2AVu3tia4KkcWQ+8LnMi+4e8bb+9es0Ic2u+Itgs/wwOMVuFlBztA0=
OpenBSD 6.3 errata 023, November 17, 2018:
A recent change to POSIX file locks could cause incorrect results during
lock acquisition.
Apply by doing:
signify -Vep /etc/signify/openbsd-63-base.pub -x 023_lockf.patch.sig \
-m - | (cd /usr/src && patch -p0)
And then rebuild and install a new kernel:
KK=`sysctl -n kern.osversion | cut -d# -f1`
cd /usr/src/sys/arch/`machine`/compile/$KK
make obj
make config
make
make install
Index: sys/kern/vfs_lockf.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_lockf.c,v
retrieving revision 1.25
diff -u -p -r1.25 vfs_lockf.c
--- sys/kern/vfs_lockf.c 26 Feb 2018 13:43:51 -0000 1.25
+++ sys/kern/vfs_lockf.c 12 Nov 2018 19:19:15 -0000
@@ -122,12 +122,49 @@ lf_free(struct lockf *lock)
{
struct uidinfo *uip;
+ if (*lock->lf_head == lock) {
+ *lock->lf_head = lock->lf_next;
+ }
+
+ lf_unlink(lock);
+
uip = uid_find(lock->lf_uid);
uip->ui_lockcnt--;
uid_release(uip);
pool_put(&lockfpool, lock);
}
+void
+lf_link(struct lockf *lock1, struct lockf *lock2)
+{
+ if (lock1->lf_next != NULL) {
+ lock2->lf_next = lock1->lf_next;
+ lock1->lf_next->lf_prev = lock2;
+ }
+ lock1->lf_next = lock2;
+
+ if (lock2->lf_prev != NULL) {
+ lock1->lf_prev = lock2->lf_prev;
+ lock2->lf_prev->lf_next = lock1;
+ }
+ lock2->lf_prev = lock1;
+
+ if (*lock1->lf_head == NULL) {
+ *lock1->lf_head = lock1;
+ } else if (*lock2->lf_head == lock2) {
+ *lock1->lf_head = lock1;
+ }
+}
+
+void
+lf_unlink(struct lockf *lock)
+{
+ if (lock->lf_prev != NULL)
+ lock->lf_prev->lf_next = lock->lf_next;
+ if (lock->lf_next != NULL)
+ lock->lf_next->lf_prev = lock->lf_prev;
+ lock->lf_prev = lock->lf_next = NULL;
+}
/*
* Do an advisory lock operation.
@@ -187,6 +224,7 @@ lf_advlock(struct lockf **head, off_t si
lock->lf_id = id;
lock->lf_head = head;
lock->lf_type = fl->l_type;
+ lock->lf_prev = NULL;
lock->lf_next = NULL;
TAILQ_INIT(&lock->lf_blkhd);
lock->lf_flags = flags;
@@ -218,7 +256,7 @@ lf_setlock(struct lockf *lock)
{
struct lockf *block;
struct lockf **head = lock->lf_head;
- struct lockf **prev, *overlap, *ltmp;
+ struct lockf *prev, *overlap, *ltmp;
static char lockstr[] = "lockf";
int ovcase, priority, needtolink, error;
@@ -285,6 +323,8 @@ lf_setlock(struct lockf *lock)
/*
* Add our lock to the blocked list and sleep until we're free.
* Remember who blocked us (for deadlock detection).
+ * Since lock is not yet part of any list, it's safe to let the
+ * lf_next field refer to the blocking lock.
*/
lock->lf_next = block;
#ifdef LOCKF_DEBUG
@@ -312,8 +352,9 @@ lf_setlock(struct lockf *lock)
* Skip over locks owned by other processes.
* Handle any locks that overlap and are owned by ourselves.
*/
- prev = head;
block = *head;
+ prev = NULL;
+ overlap = NULL;
needtolink = 1;
for (;;) {
ovcase = lf_findoverlap(block, lock, SELF, &prev, &overlap);
@@ -331,8 +372,12 @@ lf_setlock(struct lockf *lock)
switch (ovcase) {
case 0: /* no overlap */
if (needtolink) {
- *prev = lock;
- lock->lf_next = overlap;
+ if (overlap) /* insert before overlap */
+ lf_link(lock, overlap);
+ else if (prev) /* last lock in list */
+ lf_link(prev, lock);
+ else /* first lock in list */
+ *head = lock;
}
break;
case 1: /* overlap == lock */
@@ -357,8 +402,9 @@ lf_setlock(struct lockf *lock)
break;
}
if (overlap->lf_start == lock->lf_start) {
- *prev = lock;
- lock->lf_next = overlap;
+ if (!needtolink)
+ lf_unlink(lock);
+ lf_link(lock, overlap);
overlap->lf_start = lock->lf_end + 1;
} else
lf_split(overlap, lock);
@@ -386,22 +432,19 @@ lf_setlock(struct lockf *lock)
* Add the new lock if necessary and delete the overlap.
*/
if (needtolink) {
- *prev = lock;
- lock->lf_next = overlap->lf_next;
- prev = &lock->lf_next;
+ lf_link(lock, overlap);
needtolink = 0;
- } else
- *prev = overlap->lf_next;
+ }
lf_free(overlap);
continue;
case 4: /* overlap starts before lock */
/*
* Add lock after overlap on the list.
*/
- lock->lf_next = overlap->lf_next;
- overlap->lf_next = lock;
+ if (!needtolink)
+ lf_unlink(lock);
+ lf_link(overlap, lock);
overlap->lf_end = lock->lf_start - 1;
- prev = &lock->lf_next;
lf_wakelock(overlap);
needtolink = 0;
continue;
@@ -409,10 +452,8 @@ lf_setlock(struct lockf *lock)
/*
* Add the new lock before overlap.
*/
- if (needtolink) {
- *prev = lock;
- lock->lf_next = overlap;
- }
+ if (needtolink)
+ lf_link(lock, overlap);
overlap->lf_start = lock->lf_end + 1;
lf_wakelock(overlap);
break;
@@ -438,7 +479,7 @@ lf_clearlock(struct lockf *lock)
{
struct lockf **head = lock->lf_head;
struct lockf *lf = *head;
- struct lockf *overlap, **prev;
+ struct lockf *overlap, *prev;
int ovcase;
if (lf == NULL)
@@ -447,13 +488,11 @@ lf_clearlock(struct lockf *lock)
if (lockf_debug & DEBUG_CLEARLOCK)
lf_print("lf_clearlock", lock);
#endif /* LOCKF_DEBUG */
- prev = head;
while ((ovcase = lf_findoverlap(lf, lock, SELF, &prev, &overlap))) {
lf_wakelock(overlap);
switch (ovcase) {
case 1: /* overlap == lock */
- *prev = overlap->lf_next;
lf_free(overlap);
break;
case 2: /* overlap contains lock: split it */
@@ -462,16 +501,13 @@ lf_clearlock(struct lockf *lock)
break;
}
lf_split(overlap, lock);
- overlap->lf_next = lock->lf_next;
break;
case 3: /* lock contains overlap */
- *prev = overlap->lf_next;
lf = overlap->lf_next;
lf_free(overlap);
continue;
case 4: /* overlap starts before lock */
overlap->lf_end = lock->lf_start - 1;
- prev = &overlap->lf_next;
lf = overlap->lf_next;
continue;
case 5: /* overlap ends after lock */
@@ -519,10 +555,9 @@ lf_getlock(struct lockf *lock, struct fl
struct lockf *
lf_getblock(struct lockf *lock)
{
- struct lockf **prev, *overlap, *lf;
+ struct lockf *prev, *overlap, *lf;
- prev = lock->lf_head;
- lf = *prev;
+ lf = *lock->lf_head;
while (lf_findoverlap(lf, lock, OTHERS, &prev, &overlap) != 0) {
/*
* We've found an overlap, see if it blocks us
@@ -547,7 +582,7 @@ lf_getblock(struct lockf *lock)
*/
int
lf_findoverlap(struct lockf *lf, struct lockf *lock, int type,
- struct lockf ***prev, struct lockf **overlap)
+ struct lockf **prev, struct lockf **overlap)
{
off_t start, end;
@@ -562,7 +597,7 @@ lf_findoverlap(struct lockf *lf, struct
while (lf != NULL) {
if (((type & SELF) && lf->lf_id != lock->lf_id) ||
((type & OTHERS) && lf->lf_id == lock->lf_id)) {
- *prev = &lf->lf_next;
+ *prev = lf;
*overlap = lf = lf->lf_next;
continue;
}
@@ -588,7 +623,7 @@ lf_findoverlap(struct lockf *lf, struct
DPRINTF(("no overlap\n"), DEBUG_FINDOVR);
if ((type & SELF) && end != -1 && lf->lf_start > end)
return (0);
- *prev = &lf->lf_next;
+ *prev = lf;
*overlap = lf = lf->lf_next;
continue;
}
@@ -642,18 +677,18 @@ lf_split(struct lockf *lock1, struct loc
lf_print("splitting from", lock2);
}
#endif /* LOCKF_DEBUG */
+
/*
* Check to see if splitting into only two pieces.
*/
if (lock1->lf_start == lock2->lf_start) {
lock1->lf_start = lock2->lf_end + 1;
- lock2->lf_next = lock1;
+ lf_link(lock2, lock1);
return;
}
if (lock1->lf_end == lock2->lf_end) {
lock1->lf_end = lock2->lf_start - 1;
- lock2->lf_next = lock1->lf_next;
- lock1->lf_next = lock2;
+ lf_link(lock1, lock2);
return;
}
/*
@@ -662,13 +697,15 @@ lf_split(struct lockf *lock1, struct loc
*/
splitlock = lf_alloc(lock1->lf_uid, 0);
memcpy(splitlock, lock1, sizeof(*splitlock));
+ splitlock->lf_prev = NULL;
+ splitlock->lf_next = NULL;
splitlock->lf_start = lock2->lf_end + 1;
splitlock->lf_block.tqe_next = NULL;
TAILQ_INIT(&splitlock->lf_blkhd);
lock1->lf_end = lock2->lf_start - 1;
- lock2->lf_next = splitlock;
- lock1->lf_next = lock2;
+ lf_link(lock1, lock2);
+ lf_link(lock2, splitlock);
}
/*
Index: sys/sys/lockf.h
===================================================================
RCS file: /cvs/src/sys/sys/lockf.h,v
retrieving revision 1.9
diff -u -p -r1.9 lockf.h
--- sys/sys/lockf.h 24 Mar 2013 17:45:25 -0000 1.9
+++ sys/sys/lockf.h 12 Nov 2018 19:19:15 -0000
@@ -50,6 +50,7 @@ struct lockf {
off_t lf_end; /* The byte # of the end of the lock (-1=EOF)*/
caddr_t lf_id; /* The id of the resource holding the lock */
struct lockf **lf_head; /* Back pointer to the head of lockf list */
+ struct lockf *lf_prev; /* A pointer to the previous lock on this inode */
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 */
@@ -67,13 +68,15 @@ int lf_advlock(struct lockf **,
off_t, caddr_t, int, struct flock *, int);
int lf_clearlock(struct lockf *);
int lf_findoverlap(struct lockf *,
- struct lockf *, int, struct lockf ***, struct lockf **);
+ struct lockf *, int, struct lockf **, struct lockf **);
struct lockf *
lf_getblock(struct lockf *);
int lf_getlock(struct lockf *, struct flock *);
int lf_setlock(struct lockf *);
void lf_split(struct lockf *, struct lockf *);
void lf_wakelock(struct lockf *);
+void lf_link(struct lockf *, struct lockf *);
+void lf_unlink(struct lockf *);
__END_DECLS
#ifdef LOCKF_DEBUG