Reputation: 5678
I received a bug report
that has me scratching my head. In my program, I test the
writability of a directory (which is the user's home directory by
default) before having readline
collect history and write it to a file in that directory at program exit.
Here is the problematic code:
if (access(dirname, W_OK) != 0)
complain("cannot create %s in %s", filename, dirname, errno);
else {
use_readline_for_stuff();
write_history("%s/%s", dirname, filename);
exit(0);
}
(This is pseudo-C, of course. The real code is here)
The user (let's call her USER
) reports getting an error message "cannot create xxx in
/home/USER: permission denied", that disappears after manually creating the file with USER@host > touch /home/USER/xxx
.
I would expect an unwritable home directory to lead to all kind of
problems, but the user can even simply touch
a file in that directory.
The program doesn't run suid, USER owns her home directory (and clearly can create files in it). My program is apparently the only program that displays this kind of problem. It has been fairly widely used for years, and this is the first time this bug gets reported
The Linux manpage for access (2)
says
if a directory is found to be writable, it probably means that files can be created in the directory
Why probably? Why (and when) not always (apart from a race condition like someone changing permissions just after the access()
call, full inode tables or hitting user limits) all of which don't seem to be the problem here - especially since the access()
call fails, and touch xxx
succeeds.
Upvotes: 2
Views: 724
Reputation: 176
So, I know this is a 5 year old post, but as it doesn't have any answers. Since I found it while searching for the same problem, I thought I'd answer it with my own solution.
It's actually more of a workaround, because I don't know the cause. Similar to the OP, I had an NFS directory where calls to access(2)
to test for write permission were failing. Write operations themselves were not failing, just access(2)
tests.
Here is the test code I wrote to troubleshoot (run as home_access_test
in the examples below).
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv) {
char *hd = getenv("HOME");
if (argc > 1) {
hd = argv[1];
}
int mode = W_OK;
int r = 0;
printf("checking if %s is writable.\n",hd);
r = access(hd,mode);
if (r != 0) {
perror(hd);
printf("no.\n");
} else {
printf("yes.\n");
}
}
Here is an example of the test code / problem.
jdimpson@magpi:~ $ ./home_access_test /home/jdimpson
checking if /home/jdimpson is writable.
/home/jdimpson: Permission denied
no.
jdimpson@magpi:~ $ ls -ld /home/jdimpson
drwxrwxr-x 60 jdimpson jdimpson 4096 Feb 3 23:01 /home/jdimpson
jdimpson@magpi:~ $ mkdir foo
jdimpson@magpi:~ $ ls -ld /home/jdimpson/foo
drwxr-xr-x 2 jdimpson jdimpson 4096 Feb 3 23:02 /home/jdimpson/foo
jdimpson@magpi:~ $ ./home_access_test /home/jdimpson/foo
checking if /home/jdimpson/foo is writable.
yes.
jdimpson@magpi:~ $
To reiterate what this example shows, there are no actual write failures; just permission denied reported by access(2)
. This was a nuisance because I have a program that refuses to write to its config file because the directory that it is in is being tested using access(2)
.
In brief, my environment was a Linux NFS server and Linux NFS client, using NFSv3 over UDP.
The "solution" that I stumbled across was simple. Here's the setup:
jdimpson@magpi:/home $ sudo chmod a+w .
jdimpson@magpi:/home $ ls -ld . jdimpson/ phred/
drwxrwxrwx 20 root root 4096 Feb 3 23:23 .
drwxrwxr-x 61 jdimpson jdimpson 4096 Feb 3 23:21 jdimpson/
drwx------ 7 jdimpson jdimpson 4096 Feb 3 23:23 phred/
jdimpson@magpi:/home $ ~/home_access_test /home/jdimpson
checking if /home/jdimpson is writable.
/home/jdimpson: Permission denied
no.
jdimpson@magpi:/home $ ~/home_access_test /home/phred
checking if /home/phred is writable.
/home/phred: Permission denied
no.
Both these folder exhibit the problem. Then I moved one directory into the other, and back out again, which fixed that directory:
jdimpson@magpi:/home $ mv jdimpson/ phred
jdimpson@magpi:/home $ ~/home_access_test /home/phred/jdimpson/
bash: /home/jdimpson/home_access_test: No such file or directory
jdimpson@magpi:/home $ /home/phred/jdimpson/home_access_test /home/phred/jdimpson
checking if /home/phred/jdimpson is writable.
yes.
jdimpson@magpi:/home $ mv phred/jdimpson/ .
jdimpson@magpi:/home $ ~/home_access_test /home/jdimpson
checking if /home/jdimpson is writable.
yes.
And I repeated it for the other directory, which then fixed it as well:
jdimpson@magpi:/home $ ~/home_access_test /home/phred/
checking if /home/phred/ is writable.
/home/phred/: Permission denied
no.
jdimpson@magpi:/home $ mv phred/ jdimpson/
jdimpson@magpi:/home $ ~/home_access_test /home/jdimpson/phred
checking if /home/jdimpson/phred is writable.
yes.
jdimpson@magpi:/home $ mv jdimpson/phred/ .
jdimpson@magpi:/home $ ~/home_access_test /home/phred/
checking if /home/phred/ is writable.
yes.
sudo chmod go-w .
I don't know what the root cause was, and can only hypothesize that moving the folder into a sub-folder and then back out caused whatever meta-data that was incorrect to be fixed.
Not shown here, but running the script on the NFS server didn't exhibit the problem, and nor did moving the directories around in a similar fashion on the NFS server fix anything. So I assume the problem was caused in part by being on an NFS share.
Upvotes: 1