bool run(OperationContext* txn,
             const string& dbname,
             BSONObj& cmdObj,
             int options,
             string& errmsg,
             BSONObjBuilder& result) {
        RoleName roleName;
        PrivilegeVector privilegesToRemove;
        Status status = auth::parseAndValidateRolePrivilegeManipulationCommands(
            cmdObj, "revokePrivilegesFromRole", dbname, &roleName, &privilegesToRemove);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        ServiceContext* serviceContext = txn->getClient()->getServiceContext();
        stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext));

        AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);
        status = requireAuthSchemaVersion26Final(txn, authzManager);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        if (RoleGraph::isBuiltinRole(roleName)) {
            return appendCommandStatus(
                result,
                Status(ErrorCodes::InvalidRoleModification,
                       str::stream() << roleName.getFullName()
                                     << " is a built-in role and cannot be modified."));
        }

        BSONObj roleDoc;
        status = authzManager->getRoleDescription(
            txn, roleName, PrivilegeFormat::kShowSeparate, &roleDoc);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        PrivilegeVector privileges;
        status = auth::parseAndValidatePrivilegeArray(BSONArray(roleDoc["privileges"].Obj()),
                                                      &privileges);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        for (PrivilegeVector::iterator itToRm = privilegesToRemove.begin();
             itToRm != privilegesToRemove.end();
             ++itToRm) {
            for (PrivilegeVector::iterator curIt = privileges.begin(); curIt != privileges.end();
                 ++curIt) {
                if (curIt->getResourcePattern() == itToRm->getResourcePattern()) {
                    curIt->removeActions(itToRm->getActions());
                    if (curIt->getActions().empty()) {
                        privileges.erase(curIt);
                    }
                    break;
                }
            }
        }

        // Build up update modifier object to $set privileges.
        mutablebson::Document updateObj;
        mutablebson::Element setElement = updateObj.makeElementObject("$set");
        status = updateObj.root().pushBack(setElement);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }
        mutablebson::Element privilegesElement = updateObj.makeElementArray("privileges");
        status = setElement.pushBack(privilegesElement);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }
        status = authzManager->getBSONForPrivileges(privileges, privilegesElement);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        audit::logRevokePrivilegesFromRole(Client::getCurrent(), roleName, privilegesToRemove);

        BSONObjBuilder updateBSONBuilder;
        updateObj.writeTo(&updateBSONBuilder);
        status = updateRoleDocument(txn, roleName, updateBSONBuilder.done());
        // Must invalidate even on bad status - what if the write succeeded but the GLE failed?
        authzManager->invalidateUserCache();
        return appendCommandStatus(result, status);
    }