Why is a file with 400 permissions seen writable by root but read-only by user?
Solution 1
test -w
aka [ -w
doesn't check the file mode. It checks if it's writable. For root, it is.
$ help test | grep '\-w'
-w FILE True if the file is writable by you.
The way I would test would be to do a bitwise comparison against the output of stat(1)
("%a
Access rights in octal").
(( 0$(stat -c %a somefile) & 0200 )) && echo rw || echo ro
Note the subshell $(...)
needs a 0
prefixed so that the output of stat
is interpreted as octal by (( ... ))
.
Solution 2
I think you have have misunderstood what -w
does. It does not check to see if the file has "Write permissions", it checks to see if the file is writable by the invoking user.
More specifically, it calls access(2)
or similar.
eg if a script has if [ -w /etc/shadow ]
then if you run strace
on the script you may see a line similar to
faccessat(AT_FDCWD, "/etc/shadow", W_OK)
Since root
can write to the file then it returns 0.
eg as a normal user:
faccessat(AT_FDCWD, "/etc/shadow", W_OK) = -1 EACCES (Permission denied)
As root
faccessat(AT_FDCWD, "/etc/shadow", W_OK) = 0
This, despite the fact that /etc/shadow
has permission 000
on my machine.
---------- 1 root root 4599 Jan 29 20:08 /etc/shadow
Now what you want to do gets interesting and isn't so simple.
If you want to check the simple permissions then check the ls
output, or call stat
or similar. But realize that ACLs can over-ride these permissions. Just because a file is permission 400 doesn't stop it from being writable...
Solution 3
The root user can do as she pleases, "normal" file permissions are no limitation. It won't directly execute a plain file without any eXecute permissions, just for a bit of insurance against foot target practice.
Related videos on Youtube
Comments
-
Rich almost 2 years
If I create a file as an unprivileged user, and change the permissions mode to
400
, it's seen by that user as read-only, correctly:$ touch somefile $ chmod 400 somefile $ [ -w somefile ] && echo rw || echo ro ro
All is well.
But then root comes along:
# [ -w somefile ] && echo rw || echo ro rw
What the heck? Sure, root can write to read-only files, but it shouldn't make a habit of it: Best Practice would tend to dictate that I should be able to test for the write permission bit, and if it's not, then it was set that way for a reason.
I guess I want to understand both why this is happening, and how can I get a false return code when testing a file that doesn't have the write bit set?
-
Rich about 6 yearsbtw I'm using both RHEL6 (
4.1.2(1)-release
) and RHEL7 (4.2.46(2)-release
). -
Kevin about 6 years"Best Practice would tend to dictate that I should be able to test for the write permission bit, and if it's not, then it was set that way for a reason." - Actually, best practice is "don't run stuff as root." If you're running as root, you've already decided to bypass permission checks. Manually re-implementing those permission checks in userspace is a recipe for disaster.
-
Rich about 6 years@Kevin Good for you if you can run stuff unprivileged. This is for manipulating
/etc/dhcp/dhcpd.conf
, which is owned by root. I'm using the vendor-supplieddhcpd
. Total disaster, huh? The file is checked into RCS, I'm automating use ofrcsdiff
,ci
andco
because we have operators that need to ... operate. The permission bit check (-w
, as detailed bytest(1)
) was going to be a first line of failure, working on the basis thatci -u
leaves a file read-only. I'm ditching that and going straight torcsdiff -q
and checking$?
. Undisastrousdhcpd
? It would be owned bydhcpd
. -
Kevin about 6 yearsIt's a potential disaster because you now have two different implementations of permissions checks: one in the kernel and one in userspace. Worse, those implementations are not even intended to produce identical results, so you can't just fuzz test them against each other. So now you have two paths to access which have to be locked down and secured independently of each other.
-
Rich about 6 years@Kevin Sure, they don't produce identical results and weren't intended to (despite the paucity of detail in manpages), but I explicitly want to check the write-permission bit; and the manpages for
bash
andtest
led me to believe that's what[ -w
is for. -
Tobias Kienzler about 6 yearsIf you want to prevent even root from accidentally modifying a file, try
chattr +i
. See also stackoverflow.com/q/48578108/321973
-
-
Rich about 6 yearsNo, "misunderstanding" would be reading the manpages wrong for
-w
:test(1)
is explicit: "FILE exists and write permission is granted", not "file may be written by current user". Nothing about overriding permissions, nor ACLs.bash(1)
is cagey: "True if file exists and is writable."ksh(1)
makes a subtle hint toward shenanigans: "-w file // True, if file exists and is writable by current process."zsh(1)
defers totest(1)
,zshmisc(1)
is worded asksh(1)
, andzshexpn(1)
details some interesting permissions-based globbing.csh(1)
is hilariously brief: "Write access". -
Rich about 6 yearsbtw: I accepted Patrick's answer, 1. because you didn't adequately answer the lead-on question: how can I get a false return code when testing a file that doesn't have the write bit set? and 2. because of the snarky lead-in presuming I misunderstood the manpages.
-
Rich about 6 yearsThanks for being concise. Good use of
(( ... & ... ))
. One typo corrected :-) -
Rich about 6 yearsMake that 3... No
if
required, octal permissions output is%a
not%d
, and(( ... ))
needs a prefixed0
to interpret the output ofstat
as octal. -
Jerb about 6 years@Rich The way I read this, I think your comments are coming across as a bit snarky as well. I'm not saying that anything you wrote was wrong, just that it would probably go over better if expressed in a more polite way.
-
user2948306 about 6 years@Patrick my
man stat
says "%d device number in decimal", but what we want are the "access rights", no? Your point about needing the 0 prefix is well-made, but I guess we just have to bodge it in there :). -
user2948306 about 6 years
stat -c 0%a
... -
phemmer about 6 years@sourcejedi ack, you're right. For some reason I was thinking %d was access rights in decimal. Restored the edit. thanks :-)
-
barbecue about 6 years"I think you have have misunderstood..." is not snarky. Your response however, 100% snarky.
-
Sebi about 6 years@Rich Also, while the manpages might not have been crystal clear, Stephen has stated that you may have "misunderstood what -w does", and not what manpages say, where the former looks to be the case, hence the question