Skip to content

Commit

Permalink
virtfs-proxy-helper: use setresuid and setresgid
Browse files Browse the repository at this point in the history
The setfsuid and setfsgid system calls are obscure and they complicate
the error checking (that glibc's warn_unused_result "feature" forces
us to do).  Switch to the standard setresuid and setresgid functions.

Signed-off-by: Paolo Bonzini <[email protected]
Signed-off-by: Aneesh Kumar K.V <[email protected]>
  • Loading branch information
Paolo Bonzini authored and kvaneesh committed Dec 5, 2012
1 parent 16c6c80 commit 9fd2ecd
Showing 1 changed file with 64 additions and 29 deletions.
93 changes: 64 additions & 29 deletions fsdev/virtfs-proxy-helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,31 +272,76 @@ static int send_status(int sockfd, struct iovec *iovec, int status)
/*
* from man 7 capabilities, section
* Effect of User ID Changes on Capabilities:
* 4. If the file system user ID is changed from 0 to nonzero (see setfsuid(2))
* then the following capabilities are cleared from the effective set:
* CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID,
* CAP_LINUX_IMMUTABLE (since Linux 2.2.30), CAP_MAC_OVERRIDE, and CAP_MKNOD
* (since Linux 2.2.30). If the file system UID is changed from nonzero to 0,
* then any of these capabilities that are enabled in the permitted set
* are enabled in the effective set.
* If the effective user ID is changed from nonzero to 0, then the permitted
* set is copied to the effective set. If the effective user ID is changed
* from 0 to nonzero, then all capabilities are are cleared from the effective
* set.
*
* The setfsuid/setfsgid man pages warn that changing the effective user ID may
* expose the program to unwanted signals, but this is not true anymore: for an
* unprivileged (without CAP_KILL) program to send a signal, the real or
* effective user ID of the sending process must equal the real or saved user
* ID of the target process. Even when dropping privileges, it is enough to
* keep the saved UID to a "privileged" value and virtfs-proxy-helper won't
* be exposed to signals. So just use setresuid/setresgid.
*/
static int setfsugid(int uid, int gid)
static int setugid(int uid, int gid, int *suid, int *sgid)
{
int retval;

/*
* We still need DAC_OVERRIDE because we don't change
* We still need DAC_OVERRIDE because we don't change
* supplementary group ids, and hence may be subjected DAC rules
*/
cap_value_t cap_list[] = {
CAP_DAC_OVERRIDE,
};

setfsgid(gid);
setfsuid(uid);
*suid = geteuid();
*sgid = getegid();

if (setresgid(-1, gid, *sgid) == -1) {
retval = -errno;
goto err_out;
}

if (setresuid(-1, uid, *suid) == -1) {
retval = -errno;
goto err_sgid;
}

if (uid != 0 || gid != 0) {
return do_cap_set(cap_list, ARRAY_SIZE(cap_list), 0);
if (do_cap_set(cap_list, ARRAY_SIZE(cap_list), 0) < 0) {
retval = -errno;
goto err_suid;
}
}
return 0;

err_suid:
if (setresuid(-1, *suid, *suid) == -1) {
abort();
}
err_sgid:
if (setresgid(-1, *sgid, *sgid) == -1) {
abort();
}
err_out:
return retval;
}

/*
* This is used to reset the ugid back with the saved values
* There is nothing much we can do checking error values here.
*/
static void resetugid(int suid, int sgid)
{
if (setresgid(-1, sgid, sgid) == -1) {
abort();
}
if (setresuid(-1, suid, suid) == -1) {
abort();
}
}

/*
Expand Down Expand Up @@ -578,18 +623,15 @@ static int do_create_others(int type, struct iovec *iovec)

v9fs_string_init(&path);
v9fs_string_init(&oldpath);
cur_uid = geteuid();
cur_gid = getegid();

retval = proxy_unmarshal(iovec, offset, "dd", &uid, &gid);
if (retval < 0) {
return retval;
}
offset += retval;
retval = setfsugid(uid, gid);
retval = setugid(uid, gid, &cur_uid, &cur_gid);
if (retval < 0) {
retval = -errno;
goto err_out;
goto unmarshal_err_out;
}
switch (type) {
case T_MKNOD:
Expand Down Expand Up @@ -619,9 +661,10 @@ static int do_create_others(int type, struct iovec *iovec)
}

err_out:
resetugid(cur_uid, cur_gid);
unmarshal_err_out:
v9fs_string_free(&path);
v9fs_string_free(&oldpath);
setfsugid(cur_uid, cur_gid);
return retval;
}

Expand All @@ -641,24 +684,16 @@ static int do_create(struct iovec *iovec)
if (ret < 0) {
goto unmarshal_err_out;
}
cur_uid = geteuid();
cur_gid = getegid();
ret = setfsugid(uid, gid);
ret = setugid(uid, gid, &cur_uid, &cur_gid);
if (ret < 0) {
/*
* On failure reset back to the
* old uid/gid
*/
ret = -errno;
goto err_out;
goto unmarshal_err_out;
}
ret = open(path.data, flags, mode);
if (ret < 0) {
ret = -errno;
}

err_out:
setfsugid(cur_uid, cur_gid);
resetugid(cur_uid, cur_gid);
unmarshal_err_out:
v9fs_string_free(&path);
return ret;
Expand Down

0 comments on commit 9fd2ecd

Please sign in to comment.