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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
|
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8b0381d1101a269a5921ee3d78920fa66420018b..91e568a3201d71921b93a9d4d6da9c01224bedea 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -32,7 +32,13 @@ before_script:
after_script:
- rm -rf _build/*/lib/pleroma
+.using-ci-base:
+ tags:
+ - amd64
+
build:
+ extends:
+ - .using-ci-base
stage: build
only:
changes: &build_changes_policy
@@ -44,6 +50,8 @@ build:
- mix compile --force
spec-build:
+ extends:
+ - .using-ci-base
stage: test
only:
changes:
@@ -57,6 +65,8 @@ spec-build:
- mix pleroma.openapi_spec spec.json
benchmark:
+ extends:
+ - .using-ci-base
stage: benchmark
when: manual
variables:
@@ -71,6 +81,8 @@ benchmark:
- mix pleroma.load_testing
unit-testing:
+ extends:
+ - .using-ci-base
stage: test
only:
changes: *build_changes_policy
@@ -94,6 +106,8 @@ unit-testing:
path: coverage.xml
unit-testing-erratic:
+ extends:
+ - .using-ci-base
stage: test
retry: 2
allow_failure: true
@@ -129,6 +143,8 @@ unit-testing-erratic:
# - mix test --trace --only federated
unit-testing-rum:
+ extends:
+ - .using-ci-base
stage: test
only:
changes: *build_changes_policy
@@ -162,6 +178,8 @@ lint:
- mix format --check-formatted
analysis:
+ extends:
+ - .using-ci-base
stage: test
only:
changes: *build_changes_policy
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6fc6aaee23c312a43f67b5210688b28e1060554..468ec101293b462c8eddaddf375d0de9e8d68fcd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Removed
+## 2.5.3
+
+### Security
+- Emoji pack loader sanitizes pack names
+- Reduced permissions of config files and directories, distros requiring greater permissions like group-read need to pre-create the directories
+
## 2.5.2
### Security
diff --git a/changelog.d/emoji-pack-sanitization.security b/changelog.d/emoji-pack-sanitization.security
new file mode 100644
index 0000000000000000000000000000000000000000..f3218abd4d78e57813b9259a62a73f73b32499a2
--- /dev/null
+++ b/changelog.d/emoji-pack-sanitization.security
@@ -0,0 +1 @@
+Emoji pack loader sanitizes pack names
diff --git a/changelog.d/otp_perms.security b/changelog.d/otp_perms.security
new file mode 100644
index 0000000000000000000000000000000000000000..a3da1c677b6c58beb60613a90615a6fa04c42955
--- /dev/null
+++ b/changelog.d/otp_perms.security
@@ -0,0 +1 @@
+- Reduced permissions of config files and directories, distros requiring greater permissions like group-read need to pre-create the directories
\ No newline at end of file
diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex
index 5c93f19ff5aa45c4908c33bb34963f53b5dfa79f..5d8b254a223e8d7b3fd8b07691dd8f9cbcc072e2 100644
--- a/lib/mix/tasks/pleroma/instance.ex
+++ b/lib/mix/tasks/pleroma/instance.ex
@@ -266,12 +266,20 @@ def run(["gen" | rest]) do
config_dir = Path.dirname(config_path)
psql_dir = Path.dirname(psql_path)
+ # Note: Distros requiring group read (0o750) on those directories should
+ # pre-create the directories.
[config_dir, psql_dir, static_dir, uploads_dir]
|> Enum.reject(&File.exists?/1)
- |> Enum.map(&File.mkdir_p!/1)
+ |> Enum.each(fn dir ->
+ File.mkdir_p!(dir)
+ File.chmod!(dir, 0o700)
+ end)
shell_info("Writing config to #{config_path}.")
+ # Sadly no fchmod(2) equivalent in Elixir…
+ File.touch!(config_path)
+ File.chmod!(config_path, 0o640)
File.write(config_path, result_config)
shell_info("Writing the postgres script to #{psql_path}.")
File.write(psql_path, result_psql)
@@ -290,8 +298,7 @@ def run(["gen" | rest]) do
else
shell_error(
"The task would have overwritten the following files:\n" <>
- (Enum.map(will_overwrite, &"- #{&1}\n") |> Enum.join("")) <>
- "Rerun with `--force` to overwrite them."
+ Enum.map_join(will_overwrite, &"- #{&1}\n") <> "Rerun with `--force` to overwrite them."
)
end
end
diff --git a/lib/pleroma/config/release_runtime_provider.ex b/lib/pleroma/config/release_runtime_provider.ex
index 91e5f1a540e2d034357262c3e68b67c681f95ef0..9ec0f975e8c9b9b6f1e827700f7e13d40bca8e72 100644
--- a/lib/pleroma/config/release_runtime_provider.ex
+++ b/lib/pleroma/config/release_runtime_provider.ex
@@ -20,6 +20,20 @@ def load(config, opts) do
with_runtime_config =
if File.exists?(config_path) do
+ # <https://git.pleroma.social/pleroma/pleroma/-/issues/3135>
+ %File.Stat{mode: mode} = File.lstat!(config_path)
+
+ if Bitwise.band(mode, 0o007) > 0 do
+ raise "Configuration at #{config_path} has world-permissions, execute the following: chmod o= #{config_path}"
+ end
+
+ if Bitwise.band(mode, 0o020) > 0 do
+ raise "Configuration at #{config_path} has group-wise write permissions, execute the following: chmod g-w #{config_path}"
+ end
+
+ # Note: Elixir doesn't provides a getuid(2)
+ # so cannot forbid group-read only when config is owned by us
+
runtime_config = Config.Reader.read!(config_path)
with_defaults
diff --git a/lib/pleroma/emoji/pack.ex b/lib/pleroma/emoji/pack.ex
index a361ea2009ae187df70c39889b145e7ed7f36dab..6e58f88981299916b913274173d3d5da11a97be5 100644
--- a/lib/pleroma/emoji/pack.ex
+++ b/lib/pleroma/emoji/pack.ex
@@ -285,6 +285,7 @@ def update_metadata(name, data) do
@spec load_pack(String.t()) :: {:ok, t()} | {:error, :file.posix()}
def load_pack(name) do
+ name = Path.basename(name)
pack_file = Path.join([emoji_path(), name, "pack.json"])
with {:ok, _} <- File.stat(pack_file),
diff --git a/mix.exs b/mix.exs
index 79fd9c9efebee61253cb417aed03fc95b52bf7be..d1cdb151dd25545b31f777e8c3b57e42db673357 100644
--- a/mix.exs
+++ b/mix.exs
@@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
def project do
[
app: :pleroma,
- version: version("2.5.2"),
+ version: version("2.5.3"),
elixir: "~> 1.11",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
diff --git a/test/pleroma/config/release_runtime_provider_test.exs b/test/pleroma/config/release_runtime_provider_test.exs
index 4e0d4c838a661c307be24034d43cd65627c81de3..8ff578e6352684fc99dccf073f808f5a006ae636 100644
--- a/test/pleroma/config/release_runtime_provider_test.exs
+++ b/test/pleroma/config/release_runtime_provider_test.exs
@@ -17,6 +17,8 @@ test "loads release defaults config and warns about non-existent runtime config"
end
test "merged runtime config" do
+ assert :ok == File.chmod!("test/fixtures/config/temp.secret.exs", 0o640)
+
merged =
ReleaseRuntimeProvider.load([], config_path: "test/fixtures/config/temp.secret.exs")
@@ -25,6 +27,8 @@ test "merged runtime config" do
end
test "merged exported config" do
+ assert :ok == File.chmod!("test/fixtures/config/temp.exported_from_db.secret.exs", 0o640)
+
ExUnit.CaptureIO.capture_io(fn ->
merged =
ReleaseRuntimeProvider.load([],
@@ -37,6 +41,9 @@ test "merged exported config" do
end
test "runtime config is merged with exported config" do
+ assert :ok == File.chmod!("test/fixtures/config/temp.secret.exs", 0o640)
+ assert :ok == File.chmod!("test/fixtures/config/temp.exported_from_db.secret.exs", 0o640)
+
merged =
ReleaseRuntimeProvider.load([],
config_path: "test/fixtures/config/temp.secret.exs",
diff --git a/test/pleroma/emoji/pack_test.exs b/test/pleroma/emoji/pack_test.exs
index 18b99da75b3f68352f9c8915711cff7a9b4407f8..00001abfcdb32793ad9f637ebe83689b22e76f2c 100644
--- a/test/pleroma/emoji/pack_test.exs
+++ b/test/pleroma/emoji/pack_test.exs
@@ -90,4 +90,8 @@ test "add emoji file", %{pack: pack} do
assert updated_pack.files_count == 1
end
+
+ test "load_pack/1 ignores path traversal in a forged pack name", %{pack: pack} do
+ assert {:ok, ^pack} = Pack.load_pack("../../../../../dump_pack")
+ end
end
diff --git a/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
index 9d99df27c8e891d9ca8d1bd48fd938cb2c7e64fe..83bf59c6f3425944d3eb070ac1086b44fc59416d 100644
--- a/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
@@ -65,7 +65,7 @@ test "it works for incoming unqualified emoji reactions" do
object = Object.get_by_ap_id(data["object"])
assert object.data["reaction_count"] == 1
- assert match?([[emoji, _]], object.data["reactions"])
+ assert match?([[^emoji, _]], object.data["reactions"])
end
test "it reject invalid emoji reactions" do
diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs
index 57fa0f0476d70f4e5069ab6526a0546085dc6fc8..40f79d10302a2912c7284d14fb55500dc0f32654 100644
--- a/test/pleroma/web/mastodon_api/update_credentials_test.exs
+++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs
@@ -375,7 +375,7 @@ test "updates the user's background, upload_limit, returns a HTTP 413", %{
"pleroma_background_image" => new_background_oversized
})
- assert user_response = json_response_and_validate_schema(res, 413)
+ assert _user_response = json_response_and_validate_schema(res, 413)
assert user.background == %{}
clear_config([:instance, :upload_limit], upload_limit)
|