[BUG?] Executable flag lost when O_EXCL is not set

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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);
}



[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux