[libvirt] [PATCH v5 2/5] util: Create virFileAccessibleAs function

Eric Blake eblake at redhat.com
Fri Oct 21 15:18:33 UTC 2011


On 10/21/2011 07:12 AM, Michal Privoznik wrote:
> This function checks if a given path is accessible under
> given uid and gid.
> ---
>   src/util/util.c |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   src/util/util.h |    3 ++
>   2 files changed, 86 insertions(+), 0 deletions(-)
>
> diff --git a/src/util/util.c b/src/util/util.c
> index af27344..7343485 100644
> --- a/src/util/util.c
> +++ b/src/util/util.c
> @@ -671,6 +671,77 @@ virFileIsExecutable(const char *file)
>   }
>
>   #ifndef WIN32
> +/* Check that a file is accessible under certain
> + * user&  gid.
> + * @mode can be F_OK, or a bitwise combination of R_OK, W_OK, and X_OK.
> + * see 'man access' for more details.
> + * Returns 0 on success, -errno on fail,
> + *>0 on signaled child.

That's awkward.  How about just stating:

Returns 0 on success, -1 on fail with errno set.

> + */
> +int
> +virFileAccessibleAs(const char *path, int mode,
> +                    uid_t uid, gid_t gid)
> +{
> +    pid_t pid = 0;
> +    int waitret, status, ret = 0;
> +    int forkRet = 0;
> +    bool do_fork = (uid != getuid() || gid != getgid());
> +
> +    if (do_fork)
> +        forkRet = virFork(&pid);

The control flow is a bit hard to follow.  While it looks correct, I 
think it would be easier to read as follows (it also matches my proposal 
to return -1 with errno set, when encountering error):

if (uid == getuid() && gid == getgid())
     return access(path, mode);

forkRet = virFork(&pid);

... code without reference to do_fork ...

> +    if (pid) { /* parent */
> +        do {
> +            if ((waitret = waitpid(pid,&status, 0))<  0) {
> +                ret = -errno;
> +                virKillProcess(pid, SIGKILL);
> +                return ret;
> +            }
> +        } while (!WIFEXITED(status)&&  !WIFSIGNALED(status));

Use virPidWait() (from command.h), not this hand-rolled do/while loop. 
In particular, your loop will only ever execute exactly once, since 
status will always satisfy either WIFEXITED or WIFSIGNALED if waitpid() 
was successful; and you fail to handle EINTR as a reason to retry waitpid.

Returning a positive value for a signaled child is awkward; I would just 
treat that as failure, by setting errno to EIO and returning -1.  The 
likelihood of the child dying by signal is super-slim, not to mention 
that I don't see how the client can behave any better by knowing that 
the child process died than if it just reacted as if access were denied 
in the first place.

> @@ -993,6 +1064,18 @@ childerror:
>
>   #else /* WIN32 */
>
> +int
> +virFileAccessibleAs(const char *path ATTRIBUTE_UNUSED,
> +                    int mode ATTRIBUTE_UNUSED,
> +                    uid_t uid ATTRIBUTE_UNUSED,
> +                    git_t gid ATTRIBUTE_UNUSED)
> +{
> +    virUtilError(VIR_ERR_INTERNAL_ERROR,
> +                 "%s", _("virFileAccessibleAs is not implemented for WIN32"));
> +
> +    return -ENOSYS;

Rather than failing with -ENOSYS, can we at least try access(path, 
mode), ignoring uid and gid?  It may have false negatives (fail in cases 
where a different uid would succeed), but is more likely to be useful 
than just blindly declaring failure.

-- 
Eric Blake   eblake at redhat.com    +1-801-349-2682
Libvirt virtualization library http://libvirt.org




More information about the libvir-list mailing list