From: Ephrim Khong <dr.khong@gmail.com>
To: linux-nfs <linux-nfs@vger.kernel.org>
Subject: [BUG?] Executable flag lost when O_EXCL is not set
Date: Tue, 9 Mar 2021 15:16:17 +0100 [thread overview]
Message-ID: <f84e3f21-e6eb-0698-0e6e-6f96dbed4ab7@gmail.com> (raw)
Hi,
I ran into an issue that might or might not be a bug in nfs4. When
creating a file that does not previously exist on my system with
openat(AT_FDCWD, fname, O_CREAT | O_EXCL, 0777);
vs.
openat(AT_FDCWD, fname, O_CREAT, 0777);
the file has permissions 0755 for the first version and 0600 for the
second. umask is 0022 in both cases, the calls are in the same program,
right after each other (with an unlink in between). I am mostly worried
about the executable bit for the owner, which is lost.
Executing the code on an ext4 filesystem "works", meaning that it
produces the same permissions for both openat calls, regardless of O_EXCL.
My questions would be
- Is that expected, or an indication that something is off?
- Could it be some issue in the backend, not in nfs4 itself?
- Can someone reproduce this on a NFS4 mount (test is below)?
Thanks
- Eph
System details
**************
The storage backend is some SPSC IBM System.
$> uname -a
Linux xxxx 5.4.0-66-generic #74-Ubuntu SMP Wed Jan 27 22:54:38 UTC 2021
x86_64 x86_64 x86_64 GNU/Linux
$> mount -vv |grep foo
10.0.11.183:/export/foo on /import/foo type nfs4
(rw,relatime,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=x.x.x.x,local_lock=none,addr=x.x.x.x)
strace
******
This is an strace of a program that triggered this behaviour. Note how
the second openat call has no O_EXCL, but the last lstat reports 0640 as
mode:
lstat("filename.sh", 0x7ffc2f148c20) = -1 ENOENT (No such file or
directory)
openat(AT_FDCWD, "filename.sh", O_WRONLY|O_CREAT|O_EXCL, 0777) = 4
write(4, "#!/bin/bash\n#\n# Build and run hb"..., 1973) = 1973
fstat(4, {st_mode=S_IFREG|0755, st_size=1973, ...}) = 0
close(4) = 0
lstat("filename.sh", {st_mode=S_IFREG|0755, st_size=1973, ...}) = 0
unlink("filename.sh") = 0
openat(AT_FDCWD, "filename.sh", O_WRONLY|O_CREAT|O_TRUNC, 0777) = 4
write(4, "#!/bin/bash\n#\n# Build and run hb"..., 1973) = 1973
close(4) = 0
lstat("filename.sh", {st_mode=S_IFREG|0640, st_size=1973, ...}) = 0
Test script to reproduce
************************
Reproduce with
gcc test.c && ./a.out test_file
The reported st_modes should be identical.
-------------8<---------------
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <malloc.h>
#define FAIL() {fprintf(stderr, "Failed at %s:%d\n", \
__FILE__,(int)__LINE__); exit(2); }
#define EXPECT(A,B) {if ((A) != (B)) FAIL(); }
int run_test(const char* const fname)
{
int res;
int fd;
struct stat mystat;
res = lstat(fname, &mystat);
if (res != -1)
{
/* File exists, delete */
res = unlink(fname);
EXPECT(res, 0);
}
res = lstat(fname, &mystat);
EXPECT(res, -1);
/* Create file with O_EXCL */
fd = openat(AT_FDCWD, fname, O_CREAT | O_EXCL, 0777);
if (fd == -1)
FAIL();
res = close(fd);
EXPECT(res, 0);
res = lstat(fname, &mystat);
EXPECT(res, 0);
printf("st_mode after creating with O_EXCL: %4o\n", mystat.st_mode);
/* Delete file */
res = unlink(fname);
EXPECT(res, 0);
/* Create file without O_EXCL */
fd = openat(AT_FDCWD, fname, O_CREAT, 0777);
if (fd == -1)
FAIL();
res = close(fd);
EXPECT(res, 0);
res = lstat(fname, &mystat);
EXPECT(res, 0);
printf("st_mode after creating w/o O_EXCL: %4o\n", mystat.st_mode);
}
int main(int argc, const char** argv)
{
if (argc < 2)
{
printf("Delete and re-create a file with different modes,\n");
printf("checking the file permissions bits each time.\n");
printf("Usage:\n");
printf(" %s <filename>\n", argv[0]);
printf("ATTENTION: The passed filename will be deleted.\n");
return 1;
}
const char* fname = argv[1];
return run_test(fname);
}
reply other threads:[~2021-03-09 14:17 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f84e3f21-e6eb-0698-0e6e-6f96dbed4ab7@gmail.com \
--to=dr.khong@gmail.com \
--cc=linux-nfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).