From: Oliver Kurth Date: Mon, 5 Aug 2019 18:21:59 +0000 (-0700) Subject: Add RpcChannel_SendOneRawPriv() X-Git-Tag: stable-11.0.0~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=385dc97f645ccaa4a0550b53949715394a009fb6;p=thirdparty%2Fopen-vm-tools.git Add RpcChannel_SendOneRawPriv() Send privileged guest RPC "guestStore.connect" with it after the vmsvc RPC channel falls back to backdoor. --- diff --git a/open-vm-tools/lib/include/vmware/tools/guestrpc.h b/open-vm-tools/lib/include/vmware/tools/guestrpc.h index ee34802d5..2fecfdfd9 100644 --- a/open-vm-tools/lib/include/vmware/tools/guestrpc.h +++ b/open-vm-tools/lib/include/vmware/tools/guestrpc.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2008,2014-2016,2018 VMware, Inc. All rights reserved. + * Copyright (C) 2008,2014-2016,2018-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -204,15 +204,36 @@ RpcChannel_SendOneRaw(const char *data, char **result, size_t *resultLen); +#if defined(__linux__) || defined(_WIN32) +gboolean +RpcChannel_SendOneRawPriv(const char *data, + size_t dataLen, + char **result, + size_t *resultLen); +#endif + gboolean RpcChannel_SendOne(char **reply, size_t *repLen, const char *reqFmt, ...); +#if defined(__linux__) || defined(_WIN32) +gboolean +RpcChannel_SendOnePriv(char **reply, + size_t *repLen, + const char *reqFmt, + ...); +#endif + RpcChannel * RpcChannel_New(void); +#if defined(__linux__) || defined(_WIN32) +RpcChannel * +VSockChannel_New(void); +#endif + void RpcChannel_SetBackdoorOnly(void); diff --git a/open-vm-tools/lib/rpcChannel/bdoorChannel.c b/open-vm-tools/lib/rpcChannel/bdoorChannel.c index 8856c60b0..d3572a8d2 100644 --- a/open-vm-tools/lib/rpcChannel/bdoorChannel.c +++ b/open-vm-tools/lib/rpcChannel/bdoorChannel.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2008-2016,2018 VMware, Inc. All rights reserved. + * Copyright (C) 2008-2016,2018-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -271,6 +271,7 @@ BackdoorChannel_New(void) BackdoorChannelSetCallbacks(ret); ret->_private = bdoor; + g_mutex_init(&ret->outLock); return ret; } diff --git a/open-vm-tools/lib/rpcChannel/rpcChannel.c b/open-vm-tools/lib/rpcChannel/rpcChannel.c index 0dcb3ffb0..837a0abb9 100644 --- a/open-vm-tools/lib/rpcChannel/rpcChannel.c +++ b/open-vm-tools/lib/rpcChannel/rpcChannel.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2008-2016,2018 VMware, Inc. All rights reserved. + * Copyright (C) 2008-2016,2018-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -129,7 +129,7 @@ RpcChannelRestart(gpointer _chan) RpcChannelStopNoLock(&chan->impl); /* Clear vSocket channel failure */ - Debug(LGPFX "Clearing backdoor behavior ...\n"); + Log(LGPFX "Clearing backdoor behavior ...\n"); gVSocketFailed = FALSE; chanStarted = RpcChannel_Start(&chan->impl); @@ -184,9 +184,9 @@ RpcChannelCheckReset(gpointer _chan) } /* Reset was successful. */ - Debug(LGPFX "Channel was reset successfully.\n"); + Log(LGPFX "Channel was reset successfully.\n"); chan->rpcResetErrorCount = 0; - Debug(LGPFX "Clearing backdoor behavior ...\n"); + Log(LGPFX "Clearing backdoor behavior ...\n"); gVSocketFailed = FALSE; if (chan->resetCb != NULL) { @@ -806,9 +806,6 @@ RpcChannel_New(void) #else chan = BackdoorChannel_New(); #endif - if (chan) { - g_mutex_init(&chan->outLock); - } return chan; } @@ -852,14 +849,14 @@ RpcChannel_Start(RpcChannel *chan) ok = funcs->start(chan); if (!ok && funcs->onStartErr != NULL) { - Debug(LGPFX "Fallback to backdoor ...\n"); + Log(LGPFX "Fallback to backdoor ...\n"); funcs->onStartErr(chan); ok = BackdoorChannel_Fallback(chan); /* * As vSocket is not available, we stick the backdoor * behavior until the channel is reset/restarted. */ - Debug(LGPFX "Sticking backdoor behavior ...\n"); + Log(LGPFX "Sticking backdoor behavior ...\n"); gVSocketFailed = TRUE; } @@ -996,7 +993,7 @@ RpcChannel_Send(RpcChannel *chan, resLen = 0; /* retry once */ - Debug(LGPFX "Stop RpcOut channel and try to send again ...\n"); + Log(LGPFX "Stop RpcOut channel and try to send again ...\n"); funcs->stopRpcOut(chan); if (RpcChannel_Start(chan)) { /* The channel may get switched from vsocket to backdoor */ @@ -1038,22 +1035,28 @@ exit: * @param[in] dataLen data length * @param[in] result reply, should be freed by calling RpcChannel_Free. * @param[in] resultLen reply length + * @param[in] priv TRUE : create VSock channel for privileged guest RPC. + FALSE: follow regular RPC channel creation process. * @returns TRUE on success. */ -gboolean -RpcChannel_SendOneRaw(const char *data, - size_t dataLen, - char **result, - size_t *resultLen) +static gboolean +RpcChannelSendOneRaw(const char *data, + size_t dataLen, + char **result, + size_t *resultLen, + gboolean priv) { RpcChannel *chan; - gboolean status; - - status = FALSE; + gboolean status = FALSE; +#if (defined(__linux__) && !defined(USERWORLD)) || defined(_WIN32) + chan = priv ? VSockChannel_New() : RpcChannel_New(); +#else chan = RpcChannel_New(); +#endif + if (chan == NULL) { if (result != NULL) { *result = Util_SafeStrdup("RpcChannel: Unable to create " @@ -1072,6 +1075,14 @@ RpcChannel_SendOneRaw(const char *data, } } goto sent; + } else if (RpcChannel_GetType(chan) != RPCCHANNEL_TYPE_PRIV_VSOCK) { + if (result != NULL) { + *result = Util_SafeStrdup("Permission denied"); + if (resultLen != NULL) { + *resultLen = strlen(*result); + } + } + goto sent; } else if (!RpcChannel_Send(chan, data, dataLen, result, resultLen)) { /* We already have the description of the error */ goto sent; @@ -1091,6 +1102,54 @@ sent: } +/** + * Open/close RpcChannel each time for sending a Rpc message, this is a wrapper + * for RpcChannel APIs. + * + * @param[in] data request data + * @param[in] dataLen data length + * @param[in] result reply, should be freed by calling RpcChannel_Free. + * @param[in] resultLen reply length + + * @returns TRUE on success. + */ + +gboolean +RpcChannel_SendOneRaw(const char *data, + size_t dataLen, + char **result, + size_t *resultLen) +{ + return RpcChannelSendOneRaw(data, dataLen, result, resultLen, FALSE); +} + + +#if defined(__linux__) || defined(_WIN32) + +/** + * Open/close VSock RPC Channel each time for sending a privileged Rpc message, + * this is a wrapper for RpcChannel APIs. + * + * @param[in] data request data + * @param[in] dataLen data length + * @param[in] result reply, should be freed by calling RpcChannel_Free. + * @param[in] resultLen reply length + + * @returns TRUE on success. + */ + +gboolean +RpcChannel_SendOneRawPriv(const char *data, + size_t dataLen, + char **result, + size_t *resultLen) +{ + return RpcChannelSendOneRaw(data, dataLen, result, resultLen, TRUE); +} + +#endif + + /** * Open/close RpcChannel each time for sending a Rpc message, this is a wrapper * for RpcChannel APIs. @@ -1098,18 +1157,20 @@ sent: * @param[out] reply reply, should be freed by calling RpcChannel_Free. * @param[out] repLen reply length * @param[in] reqFmt request data - * @param[in] ... optional arguments depending on reqFmt. + * @param[in] args optional arguments depending on reqFmt. + * @param[in] priv TRUE : create VSock channel for privileged guest RPC. + FALSE: follow regular RPC channel creation process. * @returns TRUE on success. */ -gboolean -RpcChannel_SendOne(char **reply, - size_t *repLen, - char const *reqFmt, - ...) +static gboolean +RpcChannelSendOne(char **reply, + size_t *repLen, + char const *reqFmt, + va_list args, + gboolean priv) { - va_list args; gboolean status; char *request; size_t reqLen = 0; @@ -1117,9 +1178,7 @@ RpcChannel_SendOne(char **reply, status = FALSE; /* Format the request string */ - va_start(args, reqFmt); request = Str_Vasprintf(&reqLen, reqFmt, args); - va_end(args); /* * If Str_Vasprintf failed, write NULL into the reply if the caller wanted @@ -1129,32 +1188,7 @@ RpcChannel_SendOne(char **reply, goto error; } - /* - * If the command doesn't contain a space, add one to the end to maintain - * compatibility with old VMXs. - * - * For a long time, the GuestRpc logic in the VMX was wired to expect a - * trailing space in every command, even commands without arguments. That is - * no longer true, but we must continue to add a trailing space because we - * don't know whether we're talking to an old or new VMX. - */ - if (request[reqLen - 1] != ' ') { - char *tmp; - - tmp = Str_Asprintf(NULL, "%s ", request); - free(request); - request = tmp; - - /* - * If Str_Asprintf failed, write NULL into reply if the caller wanted - * a reply back. - */ - if (request == NULL) { - goto error; - } - } - - status = RpcChannel_SendOneRaw(request, reqLen, reply, repLen); + status = RpcChannelSendOneRaw(request, reqLen, reply, repLen, priv); free(request); @@ -1170,3 +1204,65 @@ error: } return FALSE; } + + +/** + * Open/close RpcChannel each time for sending a Rpc message, this is a wrapper + * for RpcChannel APIs. + * + * @param[out] reply reply, should be freed by calling RpcChannel_Free. + * @param[out] repLen reply length + * @param[in] reqFmt request data + * @param[in] ... optional arguments depending on reqFmt. + + * @returns TRUE on success. + */ + +gboolean +RpcChannel_SendOne(char **reply, + size_t *repLen, + char const *reqFmt, + ...) +{ + va_list args; + gboolean status; + + va_start(args, reqFmt); + status = RpcChannelSendOne(reply, repLen, reqFmt, args, FALSE); + va_end(args); + + return status; +} + + +#if defined(__linux__) || defined(_WIN32) + +/** + * Open/close VSock RPC Channel each time for sending a privileged Rpc message, + * this is a wrapper for RpcChannel APIs. + * + * @param[out] reply reply, should be freed by calling RpcChannel_Free. + * @param[out] repLen reply length + * @param[in] reqFmt request data + * @param[in] ... optional arguments depending on reqFmt. + + * @returns TRUE on success. + */ + +gboolean +RpcChannel_SendOnePriv(char **reply, + size_t *repLen, + char const *reqFmt, + ...) +{ + va_list args; + gboolean status; + + va_start(args, reqFmt); + status = RpcChannelSendOne(reply, repLen, reqFmt, args, TRUE); + va_end(args); + + return status; +} + +#endif diff --git a/open-vm-tools/lib/rpcChannel/rpcChannelInt.h b/open-vm-tools/lib/rpcChannel/rpcChannelInt.h index 47806a769..6584fc21f 100644 --- a/open-vm-tools/lib/rpcChannel/rpcChannelInt.h +++ b/open-vm-tools/lib/rpcChannel/rpcChannelInt.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2008-2016,2018 VMware, Inc. All rights reserved. + * Copyright (C) 2008-2016,2018-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -77,8 +77,6 @@ struct _RpcChannel { gboolean outStarted; }; -RpcChannel *VSockChannel_New(void); -RpcChannel *BackdoorChannel_New(void); gboolean BackdoorChannel_Fallback(RpcChannel *chan); diff --git a/open-vm-tools/lib/rpcChannel/vsockChannel.c b/open-vm-tools/lib/rpcChannel/vsockChannel.c index e8b80a242..db2eb737e 100644 --- a/open-vm-tools/lib/rpcChannel/vsockChannel.c +++ b/open-vm-tools/lib/rpcChannel/vsockChannel.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2013-2016,2018 VMware, Inc. All rights reserved. + * Copyright (C) 2013-2016,2018-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -588,6 +588,7 @@ VSockChannel_New(void) chan->_private = vsock; chan->funcs = &funcs; + g_mutex_init(&chan->outLock); return chan; }