On 07/03/2022 17:11, Paul Eggert wrote:
On 3/7/22 07:02, Pádraig Brady wrote:
When looking into https://bugs.gnu.org/54286
which discussed statx + AT_NO_AUTOMOUNT,
I was wondering about the fstatat changes in
https://github.com/coreutils/coreutils/commit/571f63f50
and whether some of those should also specify AT_NO_AUTOMOUNT?

I'm a bit lost, as I see no mention of fstatat in that commit.

That commit replaced some stat() calls with fstatat().

I was not aware of AT_NO_AUTOMOUNT until now, and am surprised about it.
POSIX says that stat(f,s) is supposed to be equivalent to
fstatat(AT_FDCWD,f,s,0). But if I understand things correctly, this
isn't true on GNU/Linux: you must pass AT_NO_AUTOMOUNT instead of 0. I
assume that this departure from POSIX was intentional, but even so it's
pretty confusing. Could you explain why AT_NO_AUTOMOUNT wasn't made the
default for fstatat?

Yes this is surprising.
I'm only going by the fstatat man page,
but I also see correlation of the issue in for e.g.:
https://bugs.python.org/issue35677

I've yet to dig into the original kernel discussions and implementation.

I suppose we first need to audit all of Gnulib's uses of fstatat and
statx to see whether they need AT_NO_AUTOMOUNT added. Once we're done
with that we can turn to Coreutils.

Yes I expect we'll have different treatments in different places.
Attached is an adjustment for ln in coreutils at least.

For example, what about the calls to fstatat in gnulib/lib/openat.h? Are
statat and lstatat intended as convenient aliases for fstatat, or as
directory-fd extensions to stat and lstat? If the former, they should be
left alone; if the latter, they need AT_NO_AUTOMOUNT. Or perhaps it
would be better to eliminate them and replace them with calls to
fstatat, since we'll need to decide on a call-by-call basis anyway.

I see unlinkat() uses lstatat(),
and in that context it would be better to specify AT_NO_AUTOMOUNT
I think since we're operating on the dir not the file itself.

Also agreed that eliminating these aliases
would avoid at least this particular ambiguity.

Another example: what about the fstatat call in gnulib/lib/fchmodat.c? I
suppose we should not add AT_NO_AUTOMOUNT there, under the theory that
GNU/Linux faccessat does not do the equivalent of AT_NO_AUTOMOUNT. Is
that right?

Yes the flag is not mentioned wrt that call,
I've yet to audit kernel code.

cheers,
Pádraig
From 1f5aa31f4787f4c585d663b56606ac6e5b068e4f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
Date: Mon, 7 Mar 2022 17:18:49 +0000
Subject: [PATCH] ln: avoid triggering automounts

* src/ln.c (do_link): Always pass AT_NO_AUTOMOUNT to fstatat().
NEWS: Mention the fix.
---
 NEWS     | 8 ++++----
 src/ln.c | 6 ++++--
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/NEWS b/NEWS
index 8e95be755..f57ca004b 100644
--- a/NEWS
+++ b/NEWS
@@ -34,10 +34,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   and the documentation has been clarified for unusual cases.
   [bug introduced in coreutils-7.0]
 
-  ls and stat no longer try to automount files, reverting to the behavior
-  before the statx() call was introduced.  Only `stat --cached=never`
-  will continue to automount files.
-  [bug introduced in coreutils-8.32]
+  ln, ls, and stat no longer try to automount files, reverting to the behavior
+  before the statx() and fstatat() calls were introduced.
+  Only `stat --cached=never` will continue to automount files.
+  [bug introduced in ln in coreutils-8.31, and ls and stat in coreutils-8.32]
 
   On macOS, 'mv A B' no longer fails with "Operation not supported"
   when A and B are in the same tmpfs file system.
diff --git a/src/ln.c b/src/ln.c
index bb4695853..6b9a1ec76 100644
--- a/src/ln.c
+++ b/src/ln.c
@@ -192,7 +192,8 @@ do_link (char const *source, int destdir_fd, char const *dest_base,
      diagnostics.  */
   if ((link_errno || dest_set) && !symbolic_link)
     {
-      source_status = fstatat (AT_FDCWD, source, &source_stats, nofollow_flag);
+      source_status = fstatat (AT_FDCWD, source, &source_stats,
+                               nofollow_flag | AT_NO_AUTOMOUNT);
       if (source_status != 0)
         {
           error (0, errno, _("failed to access %s"), quoteaf (source));
@@ -217,7 +218,8 @@ do_link (char const *source, int destdir_fd, char const *dest_base,
       if (force)
         {
           struct stat dest_stats;
-          if (fstatat (destdir_fd, dest_base, &dest_stats, AT_SYMLINK_NOFOLLOW)
+          if (fstatat (destdir_fd, dest_base, &dest_stats,
+                       AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT)
               != 0)
             {
               if (errno != ENOENT)
-- 
2.26.2

Reply via email to