untrusted comment: verify with openbsd-64-base.pub RWQq6XmS4eDAcWbOz93Dlq9QLLAVmAdzUopJGlnCg+mpqd3m5bE8lCH0EESJCAjmYe6UL69UiEaq1TOtVQU2ZVAjH0ozNsLlWQA= OpenBSD 6.4 errata 004, 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-64-base.pub -x 004_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.26 diff -u -p -r1.26 vfs_lockf.c --- sys/kern/vfs_lockf.c 6 Oct 2018 21:12:23 -0000 1.26 +++ sys/kern/vfs_lockf.c 12 Nov 2018 19:12:01 -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 */ @@ -352,20 +397,14 @@ lf_setlock(struct lockf *lock) * Check for common starting point and different types. */ if (overlap->lf_type == lock->lf_type) { - /* - * If the lock about to be freed already is in - * the list, update the previous lock to point - * to the lock after the freed one. - */ - if (!needtolink) - *prev = lock->lf_next; lf_free(lock); lock = overlap; /* for debug output below */ 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); @@ -393,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 = &overlap->lf_next; lf_wakelock(overlap); needtolink = 0; continue; @@ -416,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; @@ -445,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) @@ -454,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 */ @@ -469,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 */ @@ -526,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 @@ -554,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; @@ -569,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; } @@ -595,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; } @@ -649,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; } /* @@ -669,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:12:01 -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