NetBSD Problem Report #57374
From www@netbsd.org Sat Apr 22 13:36:16 2023
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))
(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id D1A791A923A
for <gnats-bugs@gnats.NetBSD.org>; Sat, 22 Apr 2023 13:36:15 +0000 (UTC)
Message-Id: <20230422133614.39EBF1A923B@mollari.NetBSD.org>
Date: Sat, 22 Apr 2023 13:36:14 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: fcntl(F_GETLK) with SEEK_CUR returns wrong answer when unlocked
X-Send-Pr-Version: www-1.0
>Number: 57374
>Category: kern
>Synopsis: fcntl(F_GETLK) with SEEK_CUR returns wrong answer when unlocked
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat Apr 22 13:40:00 +0000 2023
>Originator: Taylor R Campbell
>Release: current
>Organization:
The NetBSD Flockdation
>Environment:
flocked into a fever
>Description:
When fcntl(F_GETLK) is queried:
- with .l_start = S for some S,
- with .l_whence = SEEK_CUR (meaning: interpret .l_start relative to the file's current offset),
- on a file with no locks,
- on a file with nonzero current offset P,
what it returns is .l_start = S + P, .l_type = F_UNLCK, and .l_whence = SEEK_CUR.
This seems wrong: the returned range may not even overlap the queried range. It seems to me it should either return:
(a) .l_start = S, .l_type = F_UNLCK, .l_whence = SEEK_CUR; or
(b) .l_start = S + P, .l_type = F_UNLCK, .l_whence = SEEK_SET.
If I'm reading POSIX right, only option (a) is permitted:
> If no lock is found that would prevent this lock from being created, then the structure shall be left unchanged except for the lock type which shall be set to F_UNLCK.
https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html
The current behaviour happens because the former do_fcntl_lock (now moved to vn_advlock, but nxr has not yet seen this change as of press time) adds the file offset to .l_start in the case .l_whence = SEEK_CUR, but doesn't change .l_whence to reflect this:
246 if (fl->l_whence == SEEK_CUR) {
247 vn_lock(vp, LK_SHARED | LK_RETRY);
248 fl->l_start += fp->f_offset;
249 VOP_UNLOCK(vp);
250 }
https://nxr.netbsd.org/xref/src/sys/kern/sys_descrip.c?r=1.40#246
And when there is no lock, lf_getlock leaves the other members of the struct flock alone:
787 if ((block = lf_getblock(lock)) != NULL) {
...
799 } else {
800 fl->l_type = F_UNLCK;
801 }
https://nxr.netbsd.org/xref/src/sys/kern/vfs_lockf.c?r=1.78#799
And the caller of all this, sys_fcntl, just copies out the struct flock as it exists when do_fcntl_lock returns:
384 error = do_fcntl_lock(fd, cmd, &fl);
385 if (cmd == F_GETLK && error == 0)
386 error = copyout(&fl, SCARG(uap, arg), sizeof(fl));
https://nxr.netbsd.org/xref/src/sys/kern/sys_descrip.c?r=1.40#384
>How-To-Repeat:
$ cat test.c
#include <err.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
struct flock fl = {
.l_start = 1,
.l_len = 2,
.l_pid = getpid(),
.l_type = F_RDLCK,
.l_whence = SEEK_CUR,
};
int fd;
setprogname(argv[0]);
if (argc != 2)
errx(1, "Usage: %s <file>", getprogname());
if ((fd = open(argv[1], O_RDWR)) == -1)
err(1, "open");
printf("start=%lld len=%lld pid=%lld type=%d whence=%d\n",
(long long)fl.l_start,
(long long)fl.l_len,
(long long)fl.l_pid,
fl.l_type,
fl.l_whence);
if (lseek(fd, 3, SEEK_SET) == -1)
err(1, "lseek");
if (fcntl(fd, F_GETLK, &fl) == -1)
err(1, "fcntl(F_GETLK)");
printf("start=%lld len=%lld pid=%lld type=%d whence=%d\n",
(long long)fl.l_start,
(long long)fl.l_len,
(long long)fl.l_pid,
fl.l_type,
fl.l_whence);
if (close(fd) == -1)
warn("close");
fflush(stderr);
return ferror(stderr);
}
$ make test.o test
cc -O2 -c test.c
cc -O2 -o test test.c
$ ./test test.o
start=1 len=2 pid=20836 type=1 whence=1
start=4 len=2 pid=20836 type=2 whence=1
>Fix:
Yes, please!
(Contact us)
$NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2023
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.