zdtm: Implemented get_current_dir_name wrapper that checks for 'x' permissions

Any filesystem syscall, that needs to navigate to inode by it's
absolute path performs successive lookup operations for each part of the
path. Lookup operation includes access rights check.
Usually but not always zdtm tests processes fall under 'other' access
category. Also, usually directories don't have 'x' bit set for other.
In case when bit 'x' is not set and user-ID and group-ID of a process
relate it to 'other', test's will not succeed in performing these
syscalls which are most of filesystem api, that has const char *path
as part of it arguments (open, openat, mkdir, bind, etc).
The observable behavior of that is that zdtm tests fail at file
creation ops on one system and pass on the other. The above is not
immediately clear to the developer by just looking at failed test's logs.
Investigation of that is also not quick for a developer due to the
complex structure of zdtm runtime where nested clones with
NAMESPACE flags take place alongside with bind-mounts.

As an additional note: 'get_current_dir_name' is documented as returning
EACCESS in case when some part of the path lacks read/list permissions.
But in fact it's not always so. Practice shows, that test processes can
get false success on this operation only to fail on later call to
something like mkdir/mknod/bind with a given path in arguments.

'get_cwd_check_perm' is a wrapper around 'get_current_dir_name'. It also
checks for permissions on the given filepath and logs the error. This
directs the developer towards the right investigation path or even
eliminates the need for investigation completely.

Signed-off-by: Valeriy Vdovin <valeriy.vdovin@virtuozzo.com>
This commit is contained in:
Valeriy Vdovin 2020-02-03 15:08:26 +03:00 committed by Andrei Vagin
parent c40c09cbbf
commit 691b4a4e7e
2 changed files with 48 additions and 0 deletions

View file

@ -94,3 +94,27 @@ err:
mnt_info_free(&m);
goto out;
}
int get_cwd_check_perm(char **result)
{
char *cwd;
*result = 0;
cwd = get_current_dir_name();
if (!cwd) {
pr_perror("failed to get current directory");
return -1;
}
if (access(cwd, X_OK)) {
pr_err("access check for bit X for current dir path '%s' "
"failed for uid:%d,gid:%d, error: %d(%s). "
"Bit 'x' should be set in all path components of "
"this directory\n",
cwd, getuid(), getgid(), errno, strerror(errno)
);
return -1;
}
*result = cwd;
return 0;
}

View file

@ -50,4 +50,28 @@ extern mnt_info_t *mnt_info_alloc(void);
extern void mnt_info_free(mnt_info_t **m);
extern mnt_info_t *get_cwd_mnt_info(void);
/*
* get_cwd_check_perm is called to check that cwd is actually usable for a calling
* process.
*
* Example output of a stat command on a '/root' path shows file access bits:
* > stat /root
* File: /root
* ...
* Access: (0550/dr-xr-x---) Uid: ( 0/root) Gid: ( 0/root)
* ^- no 'x' bit for other
*
* Here we can see that '/root' dir (that often can be part of cwd path) does not
* allow non-root user and non-root group to list contents of this directory.
* Calling process matching 'other' access category may succeed getting cwd path, but will
* fail performing further filesystem operations based on this path with confusing errors.
*
* This function calls get_current_dir_name and explicitly checks that bit 'x' is enabled for
* a calling process and logs the error.
*
* If check passes, stores get_current_dir's result in *result and returns 0
* If check fails, stores 0 in *result and returns -1
*/
extern int get_cwd_check_perm(char **result);
#endif /* ZDTM_FS_H_ */