Skip to content

Commit 398bc40

Browse files
committed
Bug 1882596 - verify signature of content analysis client r=handyman
Differential Revision: https://phabricator.services.mozilla.com/D203476
1 parent 54229dd commit 398bc40

File tree

3 files changed

+44
-5
lines changed

3 files changed

+44
-5
lines changed

modules/libpref/init/StaticPrefList.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,14 @@
11471147
value: "A DLP agent"
11481148
mirror: never
11491149

1150+
# (optional) The organization name that the DLP agent should have. If this is
1151+
# non-empty and the DLP agent is not signed with this organization name,
1152+
# Firefox will fail the connection.
1153+
- name: browser.contentanalysis.client_signature
1154+
type: String
1155+
value: ""
1156+
mirror: never
1157+
11501158
# Content analysis by external applications, e.g. data-loss prevention apps
11511159
- name: browser.contentanalysis.enabled
11521160
type: bool

toolkit/components/contentanalysis/ContentAnalysis.cpp

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
# include <windows.h>
3333
# define SECURITY_WIN32 1
3434
# include <security.h>
35+
# include "mozilla/WinDllServices.h"
3536
#endif // XP_WIN
3637

3738
namespace mozilla::contentanalysis {
@@ -53,6 +54,7 @@ const char* kIsDLPEnabledPref = "browser.contentanalysis.enabled";
5354
const char* kIsPerUserPref = "browser.contentanalysis.is_per_user";
5455
const char* kPipePathNamePref = "browser.contentanalysis.pipe_path_name";
5556
const char* kDefaultAllowPref = "browser.contentanalysis.default_allow";
57+
const char* kClientSignature = "browser.contentanalysis.client_signature";
5658

5759
nsresult MakePromise(JSContext* aCx, RefPtr<mozilla::dom::Promise>* aPromise) {
5860
nsIGlobalObject* go = xpc::CurrentNativeGlobal(aCx);
@@ -179,8 +181,9 @@ ContentAnalysisRequest::GetWindowGlobalParent(
179181
return NS_OK;
180182
}
181183

182-
nsresult ContentAnalysis::CreateContentAnalysisClient(nsCString&& aPipePathName,
183-
bool aIsPerUser) {
184+
nsresult ContentAnalysis::CreateContentAnalysisClient(
185+
nsCString&& aPipePathName, nsString&& aClientSignatureSetting,
186+
bool aIsPerUser) {
184187
MOZ_ASSERT(!NS_IsMainThread());
185188
// This method should only be called once
186189
MOZ_ASSERT(!mCaClientPromise->IsResolved());
@@ -189,6 +192,30 @@ nsresult ContentAnalysis::CreateContentAnalysisClient(nsCString&& aPipePathName,
189192
content_analysis::sdk::Client::Create({aPipePathName.Data(), aIsPerUser})
190193
.release());
191194
LOGD("Content analysis is %s", client ? "connected" : "not available");
195+
#ifdef XP_WIN
196+
if (client && !aClientSignatureSetting.IsEmpty()) {
197+
std::string agentPath = client->GetAgentInfo().binary_path;
198+
nsString agentWidePath = NS_ConvertUTF8toUTF16(agentPath);
199+
UniquePtr<wchar_t[]> orgName =
200+
mozilla::DllServices::Get()->GetBinaryOrgName(agentWidePath.Data());
201+
bool signatureMatches = false;
202+
if (orgName) {
203+
auto dependentOrgName = nsDependentString(orgName.get());
204+
LOGD("Content analysis client signed with organization name \"%S\"",
205+
static_cast<const wchar_t*>(dependentOrgName.get()));
206+
signatureMatches = aClientSignatureSetting.Equals(dependentOrgName);
207+
} else {
208+
LOGD("Content analysis client has no signature");
209+
}
210+
if (!signatureMatches) {
211+
LOGE(
212+
"Got mismatched content analysis client signature! All content "
213+
"analysis operations will fail.");
214+
mCaClientPromise->Reject(NS_ERROR_INVALID_SIGNATURE, __func__);
215+
return NS_OK;
216+
}
217+
}
218+
#endif // XP_WIN
192219
mCaClientPromise->Resolve(client, __func__);
193220

194221
return NS_OK;
@@ -709,12 +736,15 @@ ContentAnalysis::GetIsActive(bool* aIsActive) {
709736
return rv;
710737
}
711738
bool isPerUser = Preferences::GetBool(kIsPerUserPref);
739+
nsString clientSignature;
740+
// It's OK if this fails, we will default to the empty string
741+
Preferences::GetString(kClientSignature, clientSignature);
712742
rv = NS_DispatchBackgroundTask(NS_NewCancelableRunnableFunction(
713743
"ContentAnalysis::CreateContentAnalysisClient",
714744
[owner = RefPtr{this}, pipePathName = std::move(pipePathName),
715-
isPerUser]() mutable {
716-
owner->CreateContentAnalysisClient(std::move(pipePathName),
717-
isPerUser);
745+
clientSignature = std::move(clientSignature), isPerUser]() mutable {
746+
owner->CreateContentAnalysisClient(
747+
std::move(pipePathName), std::move(clientSignature), isPerUser);
718748
}));
719749
if (NS_WARN_IF(NS_FAILED(rv))) {
720750
mCaClientPromise->Reject(rv, __func__);

toolkit/components/contentanalysis/ContentAnalysis.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class ContentAnalysis final : public nsIContentAnalysis {
9999
ContentAnalysis(const ContentAnalysis&) = delete;
100100
ContentAnalysis& operator=(ContentAnalysis&) = delete;
101101
nsresult CreateContentAnalysisClient(nsCString&& aPipePathName,
102+
nsString&& aClientSignatureSetting,
102103
bool aIsPerUser);
103104
nsresult RunAnalyzeRequestTask(
104105
const RefPtr<nsIContentAnalysisRequest>& aRequest, bool aAutoAcknowledge,

0 commit comments

Comments
 (0)