Bug 15801 - `NT_STATUS_ACCESS_DENIED making remote directory` on OpenBSD
Summary: `NT_STATUS_ACCESS_DENIED making remote directory` on OpenBSD
Status: ASSIGNED
Alias: None
Product: Samba 4.1 and newer
Classification: Unclassified
Component: File services (show other bugs)
Version: 4.22.0rc1
Hardware: All OpenBSD
: P5 regression (vote)
Target Milestone: 4.22
Assignee: Jule Anger
QA Contact: Samba QA Contact
URL: https://gitlab.com/samba-team/samba/-...
Keywords:
Depends on:
Blocks:
 
Reported: 2025-02-08 18:36 UTC by Bjorn Ketelaars
Modified: 2025-03-06 14:07 UTC (History)
4 users (show)

See Also:


Attachments
Patch rep_renameat2() in lib/replace/replace.c (602 bytes, patch)
2025-02-17 04:26 UTC, Bjorn Ketelaars
no flags Details
output ktrace/kdump (1.28 MB, text/plain)
2025-02-27 19:19 UTC, Bjorn Ketelaars
no flags Details
log.smbd (426.84 KB, text/plain)
2025-02-27 19:20 UTC, Bjorn Ketelaars
no flags Details
Patch for v4-22-test (2.67 KB, patch)
2025-03-05 12:44 UTC, Stefan Metzmacher
slow: review+
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Bjorn Ketelaars 2025-02-08 18:36:32 UTC
On OpenBSD, as of 4.22.0rc1 using `mkdir xx` to create a directory xx on a share with `smbclient` results in `NT_STATUS_ACCESS_DENIED making remote directory \xx`.

Directory `xx` can be seen on the filesystem with permission set to 000.

smbd.log show the following:

```
[2025/02/08 19:09:38.536282,  3] ../../source3/smbd/open.c:4803(mkdir_internal)
  mkdir_internal: RENAMEAT failed for '.::TMPNAME:D:32572%53344051196936958:xx' -> 'xx': NT_STATUS_ACCESS_DENIED
[2025/02/08 19:09:38.536322,  3] ../../source3/smbd/open.c:4819(mkdir_internal)
  mkdir_internal: NT_STATUS_ACCESS_DENIED: rollback and unlink '.::TMPNAME:D:32572%53344051196936958:xx'
[2025/02/08 19:09:38.536693,  3] ../../source3/smbd/open.c:4826(mkdir_internal)
  mkdir_internal: SMB_VFS_UNLINKAT(.::TMPNAME:D:32572%53344051196936958:xx): OK
[2025/02/08 19:09:38.536719,  3] ../../source3/smbd/open.c:4841(mkdir_internal)
  mkdir_internal: NT_STATUS_ACCESS_DENIED: restoring '.::TMPNAME:D:32572%53344051196936958:xx' -> 'xx'
[2025/02/08 19:09:38.536743,  2] ../../source3/smbd/open.c:4980(open_directory)
  open_directory: unable to create xx. Error was NT_STATUS_ACCESS_DENIED
[2025/02/08 19:09:38.536973,  3] ../../source3/smbd/smb2_server.c:4076(smbd_smb2_request_error_ex)
  smbd_smb2_request_error_ex: smbd_smb2_request_error_ex: idx[1] status[NT_STATUS_ACCESS_DENIED] || at ../../source3/smbd/smb2_create.c:393
[2025/02/08 19:09:38.579408,  3] ../../source3/smbd/smb2_notify.c:246(smbd_smb2_notify_send)
  smbd_smb2_notify_send: notify change called on ., filter = FILE_NAME|DIR_NAME|ATTRIBUTES|CREATION|SECURITY|STREAM_SIZE|STREAM_WRITE, recursive = 0
[2025/02/08 19:09:38.601679,  3] ../../source3/smbd/smb2_server.c:4076(smbd_smb2_request_error_ex)
  smbd_smb2_request_error_ex: smbd_smb2_request_error_ex: idx[5] status[NT_STATUS_NO_SUCH_FILE] || at ../../source3/smbd/smb2_query_directory.c:161
[2025/02/08 19:09:38.633893,  3] ../../source3/smbd/smb2_trans2.c:2012(smbd_do_qfsinfo)
  smbd_do_qfsinfo: level = 1003
```

I believe this issue has been introduced by https://gitlab.com/samba-team/samba/-/merge_requests/3756.

Workaround is to set `vfs mkdir use tmp name = no`. With this `mkdir xx` works with smbclient without any issues. The directory has been created on the filesystem with correct permissions.
Comment 1 Bjorn Ketelaars 2025-02-17 04:25:01 UTC
https://gitlab.com/samba-team/samba/-/commit/f6550e804ea5604b1d7ec67e629fad8baee87f8b adds a `renameat2()` replacement to lib/replace. On OpenBSD `__NR_renameat2` will be undefined as it is not Linux leaving a function that looks like this.

```
int rep_renameat2(int __oldfd, const char *__old, int __newfd,
    const char *__new, unsigned int __flags)
{
  if (__flags != 0) {

     errno = EINVAL;
     return -1;
  }

  return renameat(__oldfd, __old, __newfd, __new);
}
```

The how flags are set so the Linux renameat2 syscall is meant to run. The  return `renameat()` is never reached.

Proposed patch is attached to this ticket.
Comment 2 Bjorn Ketelaars 2025-02-17 04:26:56 UTC
Created attachment 18567 [details]
Patch rep_renameat2() in lib/replace/replace.c
Comment 3 Stefan Metzmacher 2025-02-22 15:48:13 UTC
(In reply to Bjorn Ketelaars from comment #1)

The replacement is correct it should return an error
if flags is not 0 !

The caller needs to handle that, also for older linux kernels.
Comment 4 Stefan Metzmacher 2025-02-27 14:34:15 UTC
(In reply to Bjorn Ketelaars from comment #0)

It seems that renameat() on OpenBSD is not able to replace
an existing directory (at least if it has 000 permissions).

https://man.openbsd.org/rename.2 says EACCES can happen for
these cases:
[EACCES]
    A component of either path prefix denies search permission.
[EACCES]
    The requested change requires writing in a directory that denies write permission.
[EACCES]
    The from argument is a directory and denies write permission.
EACCES]
    The from or to argument specifies a relative path but search permission is denied for the directory which the fromfd or tofd file descriptor, respectively, references.

What are the permissions of the parent directory?

Would it possible for you to provide level 10 logs,
see https://wiki.samba.org/index.php/Client_specific_logging for some hints.

As well as the output of something like strace, I guess openbsd would have to use ktrace/kdump. What we need a verbose listing of systemcalls and their arguments and return values. (Over the time where smbclient does the 'mkdir xx'.
Comment 5 Ralph Böhme 2025-02-27 15:46:22 UTC
Replacing a 000 directory seems to work for me on Linux:

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
        int ret;

        if (argc < 3) {
                printf("Usage: %s SRC DST\n", argv[0]);
                return 1;
        }

        ret = renameat(AT_FDCWD, argv[1], AT_FDCWD, argv[2]);
        if (ret != 0) {
                return 1;
        }

        return 0;
}

$ rmdir /srv/samba/test/dir/*                  
$ mkdir /srv/samba/test/dir/a
$ mkdir /srv/samba/test/dir/b             
$ chmod 0000 /srv/samba/test/dir/b
$ strace -v ./rename /srv/samba/test/dir/a /srv/samba/test/dir/b 2>&1 | grep renameat
renameat(AT_FDCWD, "/srv/samba/test/dir/a", AT_FDCWD, "/srv/samba/test/dir/b") = 0
Comment 6 Bjorn Ketelaars 2025-02-27 19:19:47 UTC
Created attachment 18590 [details]
output ktrace/kdump
Comment 7 Bjorn Ketelaars 2025-02-27 19:20:20 UTC
Created attachment 18591 [details]
log.smbd
Comment 8 Bjorn Ketelaars 2025-02-27 19:27:16 UTC
(In reply to Stefan Metzmacher from comment #4)

> What are the permissions of the parent directory?
777

> Would it possible for you to provide level 10 logs,
Output of ktrace/kdump as well as log.smbd have been attached to this ticket.
Comment 9 Bjorn Ketelaars 2025-03-04 06:00:11 UTC
(In reply to Stefan Metzmacher from comment #4)

> It seems that renameat() on OpenBSD is not able to replace an existing directory (at least if it has 000 permissions).

You are correct. The directory that is going to be replaced by mkdirat() needs to be writeable. As OpenBSD does not have renameat2() an alternative strategy is used, which first creates a dir using mkdirat() and then replaces it using renameat(). The call to mkdirat() sets mode 0 [0]. Setting mode S_IWUSR [1] solves the issue at hand for me. I think this is a cleaner solution than the attached patch.

Not sure what the downside is of setting mode S_IWUSR (versus 0), and if this is an acceptable solution. Change can be easily scoped to OpenBSD by using #ifdef/#else/#endif.

What do you think?


[0] https://gitlab.com/samba-team/samba/-/blob/master/source3/smbd/open.c?ref_type=heads#L4781-4784
[1] https://gitlab.com/samba-team/samba/-/blob/master/source3/smbd/open.c?ref_type=heads#L4784
Comment 10 Stefan Metzmacher 2025-03-04 16:47:32 UTC
(In reply to Bjorn Ketelaars from comment #9)

That should be possible or we disable the new code completely.

Can you point me to the OpenBSD sources where S_IWUSR
makes the difference?

I don't see it in
https://github.com/openbsd/src/blob/dac07517c712395c09494e498add8682cbbc60c9/sys/kern/vfs_syscalls.c#L2982
Comment 11 Bjorn Ketelaars 2025-03-04 19:00:41 UTC
(In reply to Stefan Metzmacher from comment #10)

> Can you point me to the OpenBSD sources where S_IWUSR makes the difference?

If I'm not mistaken it happens in ufs_rename() [0].

[0] https://github.com/openbsd/src/blob/master/sys/ufs/ufs/ufs_vnops.c#L788C12-L788C22
Comment 12 Stefan Metzmacher 2025-03-05 10:07:10 UTC
(In reply to Bjorn Ketelaars from comment #11)

Yes, and also the source directory needs the write bit.

So I think we should just disable the new code in order to
avoid the regression
Comment 13 Samba QA Contact 2025-03-05 12:38:03 UTC
This bug was referenced in samba master:

a3f129f66346dcec41a01caf8060fe1a9da484ac
Comment 14 Stefan Metzmacher 2025-03-05 12:44:04 UTC
Created attachment 18596 [details]
Patch for v4-22-test
Comment 15 Ralph Böhme 2025-03-05 12:57:25 UTC
Reassigning to Jule for inclusion in 4.22.
Comment 16 Jule Anger 2025-03-05 14:08:21 UTC
Pushed to autobuild-v4-22-test.
Comment 17 Samba QA Contact 2025-03-05 15:14:11 UTC
This bug was referenced in samba v4-22-test:

ca2add8c96822cccc91d5008ab975c54e7244533
Comment 18 Samba QA Contact 2025-03-06 14:07:51 UTC
This bug was referenced in samba v4-22-stable (Release samba-4.22.0):

ca2add8c96822cccc91d5008ab975c54e7244533