summaryrefslogtreecommitdiffstats
path: root/dom/clients/manager/ClientValidation.cpp
blob: 61e9338e124484c590e9c3a995da3dcb9112b293 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "ClientValidation.h"

#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/StaticPrefs_security.h"
#include "mozilla/net/MozURL.h"

namespace mozilla::dom {

using mozilla::ipc::ContentPrincipalInfo;
using mozilla::ipc::PrincipalInfo;
using mozilla::net::MozURL;

bool ClientIsValidPrincipalInfo(const PrincipalInfo& aPrincipalInfo) {
  // Ideally we would verify that the source process has permission to
  // create a window or worker with the given principal, but we don't
  // currently have any such restriction in place.  Instead, at least
  // verify the PrincipalInfo is an expected type and has a parsable
  // origin/spec.
  switch (aPrincipalInfo.type()) {
    // Any system and null principal is acceptable.
    case PrincipalInfo::TSystemPrincipalInfo:
    case PrincipalInfo::TNullPrincipalInfo: {
      return true;
    }

    // Validate content principals to ensure that the origin and spec are sane.
    case PrincipalInfo::TContentPrincipalInfo: {
      const ContentPrincipalInfo& content =
          aPrincipalInfo.get_ContentPrincipalInfo();

      // Verify the principal spec parses.
      RefPtr<MozURL> specURL;
      nsresult rv = MozURL::Init(getter_AddRefs(specURL), content.spec());
      NS_ENSURE_SUCCESS(rv, false);

      // Verify the principal originNoSuffix parses.
      RefPtr<MozURL> originURL;
      rv = MozURL::Init(getter_AddRefs(originURL), content.originNoSuffix());
      NS_ENSURE_SUCCESS(rv, false);

      nsAutoCString originOrigin;
      originURL->Origin(originOrigin);

      nsAutoCString specOrigin;
      specURL->Origin(specOrigin);

      // Linkable about URIs end up with a nested inner scheme of moz-safe-about
      // which will have been captured in the originNoSuffix but the spec and
      // its resulting specOrigin will not have this transformed scheme, so
      // ignore the "moz-safe-" prefix when the originURL has that transformed
      // scheme.
      if (originURL->Scheme().Equals("moz-safe-about")) {
        return specOrigin == originOrigin ||
               specOrigin == Substring(originOrigin, 9 /*moz-safe-*/,
                                       specOrigin.Length());
      }

      // For now require Clients to have a principal where both its
      // originNoSuffix and spec have the same origin.  This will
      // exclude a variety of unusual combinations within the browser
      // but its adequate for the features need to support right now.
      // If necessary we could expand this function to handle more
      // cases in the future.

      return specOrigin == originOrigin;
    }
    default: {
      break;
    }
  }

  // Windows and workers should not have expanded URLs, etc.
  return false;
}

bool ClientIsValidCreationURL(const PrincipalInfo& aPrincipalInfo,
                              const nsACString& aURL) {
  RefPtr<MozURL> url;
  nsresult rv = MozURL::Init(getter_AddRefs(url), aURL);
  NS_ENSURE_SUCCESS(rv, false);

  switch (aPrincipalInfo.type()) {
    case PrincipalInfo::TContentPrincipalInfo: {
      // Any origin can create an about:blank or about:srcdoc Client.
      if (aURL.LowerCaseEqualsLiteral("about:blank") ||
          aURL.LowerCaseEqualsLiteral("about:srcdoc")) {
        return true;
      }

      const ContentPrincipalInfo& content =
          aPrincipalInfo.get_ContentPrincipalInfo();

      // Parse the principal origin URL as well.  This ensures any MozURL
      // parser issues effect both URLs equally.
      RefPtr<MozURL> principalURL;
      rv = MozURL::Init(getter_AddRefs(principalURL), content.originNoSuffix());
      NS_ENSURE_SUCCESS(rv, false);

      nsAutoCString origin;
      url->Origin(origin);

      nsAutoCString principalOrigin;
      principalURL->Origin(principalOrigin);

      // The vast majority of sites should simply result in the same principal
      // and URL origin.
      if (principalOrigin == origin) {
        return true;
      }

      nsDependentCSubstring scheme = url->Scheme();

      // Generally any origin can also open javascript: windows and workers.
      if (scheme.LowerCaseEqualsLiteral("javascript")) {
        return true;
      }

      // Linkable about URIs end up with a nested inner scheme of moz-safe-about
      // but the url and its resulting origin will not have this transformed
      // scheme, so ignore the "moz-safe-" prefix when the principal has that
      // transformed scheme.
      if (principalURL->Scheme().Equals("moz-safe-about")) {
        return origin == principalOrigin ||
               origin ==
                   Substring(principalOrigin, 9 /*moz-safe-*/, origin.Length());
      }

      // Otherwise don't support this URL type in the clients sub-system for
      // now.  This will exclude a variety of internal browser clients, but
      // currently we don't need to support those.  This function can be
      // expanded to handle more cases as necessary.
      return false;
    }
    case PrincipalInfo::TSystemPrincipalInfo: {
      nsDependentCSubstring scheme = url->Scheme();

      // While many types of documents can be created with a system principal,
      // there are only a few that can reasonably become windows.  We attempt
      // to validate the list of known cases here with a simple scheme check.
      return scheme.LowerCaseEqualsLiteral("about") ||
             scheme.LowerCaseEqualsLiteral("chrome") ||
             scheme.LowerCaseEqualsLiteral("resource") ||
             scheme.LowerCaseEqualsLiteral("blob") ||
             scheme.LowerCaseEqualsLiteral("javascript") ||
             scheme.LowerCaseEqualsLiteral("view-source");
    }
    case PrincipalInfo::TNullPrincipalInfo: {
      // A wide variety of clients can have a null principal.  For example,
      // sandboxed iframes can have a normal content URL.  For now allow
      // any parsable URL for null principals.  This is relatively safe since
      // null principals have unique origins and won't most ClientManagerService
      // queries anyway.
      return true;
    }
    default: {
      break;
    }
  }

  // Clients (windows/workers) should never have an expanded principal type.
  return false;
}

}  // namespace mozilla::dom