NFSv3 protocol specifies that SETATTR can set file/dir mode and owner at the same time (as well as few other things). And yet Linux implementation of nfsd behaves in a quite strange way:
/* Revoke setuid/setgid on chown */
if (!S_ISDIR(inode->i_mode) &&
((iap->ia_valid & ATTR_UID) || (iap->ia_valid & ATTR_GID))) {
iap->ia_valid |= ATTR_KILL_PRIV;
if (iap->ia_valid & ATTR_MODE) {
/* we're setting mode too, just clear the s*id bits */
iap->ia_mode &= ~S_ISUID;
if (iap->ia_mode & S_IXGRP)
iap->ia_mode &= ~S_ISGID;
} else {
/* set ATTR_KILL_* bits and let VFS handle it */
iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
}
}
What is the reason for this? I spent a lot of time tracking it down in some old app (that for some reason could not copy a file via NFS without losing suid bit). Is it a bug? It happens even if new owner is the same.
It is a bug in Linux implementation of NFS server. See NFS specs.