Issue
On FreeBSD, chmod +t file
is a privileged operation if file
is not a directory:
$ echo >test
$ chmod +t test
chmod: test: Inappropriate file type or format
$ su
Password:
# chmod +t test
# ls -l test
-rw-r--r-T 1 fuz wheel 1 Jan 26 12:44 test
chmod(2) documents this behaviour:
[EFTYPE] The effective user ID is not the super-user, the mode
includes the sticky bit (S_ISVTX), and path does not
refer to a directory.
Meanwhile, sticky(7) explains that S_ISVTX
is ignored if file
is not a directory:
A special file mode, called the sticky bit (mode S_ISTXT), is used to
indicate special treatment for directories. It is ignored for regular
files. See chmod(2) or the file <sys/stat.h> for an explanation of file
modes.
What is the historical or technical reason why marking a non-directory as sticky on FreeBSD is a privileged operation? Why was an extra error code EFTYPE
invented for this where it should have been EPERM
or ENOTDIR
?
Solution
Historically, the original Unix disallowed this. The V7 chmod man page says
Ability to set this bit is restricted to the super-user since swap space is consumed by the images
The V7 chmod system call didn't return an error if the user tried to set the sticky bit, though, it just silently turned off the bit:
if (u.u_uid)
uap->fmode &= ~ISVTX;
This behavior was carried over unchanged to the BSDs. 4.3BSD has this code, which silently turns off the ISVTX bit on non-directories for non-root users:
if (u.u_uid) {
if ((ip->i_mode & IFMT) != IFDIR)
mode &= ~ISVTX;
...
}
The code was changed in 4.4BSD to return the error EFTYPE
, although the 4.4BSD chmod man page doesn't mention it. I don't know why it was changed.
if (cred->cr_uid) {
if (vp->v_type != VDIR && (mode & ISVTX))
return (EFTYPE);
...
}
FreeBSD 1.0 contains the same code as 4.4BSD.
if (cred->cr_uid) {
if (vp->v_type != VDIR && (mode & ISVTX))
return (EFTYPE);
...
}
This has carried over to current releases. FreeBSD 10.2 has this:
if (vp->v_type != VDIR && (mode & S_ISTXT)) {
if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0))
return (EFTYPE);
}
OpenBSD has similar code:
if (cred->cr_uid) {
if (vp->v_type != VDIR && (mode & S_ISTXT))
return (EFTYPE);
...
}
Solaris 10 silently ignores attempts by non-root users to set the sticky bit on files. (I will add source code snippets when available.)
Answered By - Mark Plotnick