Skip to content

Commit 66859fe

Browse files
committed
MEDIUM: protect from deleting map files still in use
1 parent 7be50be commit 66859fe

File tree

3 files changed

+121
-1
lines changed

3 files changed

+121
-1
lines changed

e2e/tests/storage_maps/haproxy.cfg

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# _version=42
2+
3+
global
4+
log 127.0.0.1 local2
5+
chroot /var/lib/haproxy
6+
pidfile /var/run/haproxy.pid
7+
maxconn 4000
8+
user haproxy
9+
group haproxy
10+
stats socket /var/lib/haproxy/stats level admin
11+
12+
defaults
13+
mode http
14+
log global
15+
option httplog
16+
option dontlognull
17+
option http-server-close
18+
option forwardfor except 127.0.0.0/8
19+
option redispatch
20+
retries 3
21+
timeout http-request 10s
22+
timeout queue 1m
23+
timeout connect 10s
24+
timeout client 1m
25+
timeout server 1m
26+
timeout http-keep-alive 10s
27+
timeout check 10s
28+
maxconn 3000
29+
30+
frontend test_storage_maps
31+
bind *:1337 crt
32+
#use_backend %[str(active),map(/etc/haproxy/maps/mapfile_example2.map)]
33+
use_backend %[str(active),map(/etc/haproxy/maps/mapfile_example.map)]
34+
35+
default_backend test_maps
36+
37+
backend test_storage_maps
38+
server appx 127.0.0.1:8080 check disabled
39+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env bats
2+
#
3+
# Copyright 2021 HAProxy Technologies
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http:#www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
load '../../libs/dataplaneapi'
19+
load "../../libs/get_json_path"
20+
load '../../libs/version'
21+
load '../../libs/haproxy_config_setup'
22+
23+
@test "Refuse to delete still used ssl certificate file" {
24+
run docker cp "${BATS_TEST_DIRNAME}/mapfile_example.map" "${DOCKER_CONTAINER_NAME}:/etc/haproxy/maps/"
25+
assert_success
26+
27+
run dpa_curl DELETE "/services/haproxy/storage/maps/mapfile_example.map"
28+
assert_success
29+
30+
dpa_curl_status_body_safe '$output'
31+
echo -e "$output"
32+
assert_equal $SC 409
33+
34+
assert dpa_docker_exec 'ls /etc/haproxy/maps/mapfile_example.map'
35+
36+
# clean up this test
37+
assert dpa_docker_exec 'rm /etc/haproxy/maps/mapfile_example.map'
38+
}
39+
40+
@test "Allow to delete ssl certificate file referenced in comments" {
41+
run docker cp "${BATS_TEST_DIRNAME}/mapfile_example2.map" "${DOCKER_CONTAINER_NAME}:/etc/haproxy/maps/"
42+
assert_success
43+
44+
run dpa_curl DELETE "/services/haproxy/storage/maps/mapfile_example2.map"
45+
assert_success
46+
47+
dpa_curl_status_body_safe '$output'
48+
echo -e "$output"
49+
assert_equal $SC 204
50+
51+
refute dpa_docker_exec 'ls /etc/haproxy/maps/mapfile_example2.map'
52+
53+
# clean up this test
54+
run dpa_docker_exec 'rm /etc/haproxy/maps/mapfile_example2.map'
55+
}

handlers/map_storage.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package handlers
1717

1818
import (
19+
"bufio"
20+
"fmt"
1921
"os"
2022
"path/filepath"
2123
"strings"
@@ -134,7 +136,31 @@ type StorageDeleteStorageMapHandlerImpl struct {
134136
}
135137

136138
func (h *StorageDeleteStorageMapHandlerImpl) Handle(params storage.DeleteStorageMapParams, principal interface{}) middleware.Responder {
137-
err := h.Client.MapStorage.Delete(params.Name)
139+
runningConf := strings.NewReader(h.Client.Configuration.Parser.String())
140+
141+
filename, err := h.Client.MapStorage.Get(params.Name)
142+
if err != nil {
143+
e := misc.HandleError(err)
144+
return storage.NewDeleteStorageSSLCertificateDefault(int(*e.Code)).WithPayload(e)
145+
}
146+
147+
// this is far from perfect but should provide a basic level of protection
148+
scanner := bufio.NewScanner(runningConf)
149+
150+
lineNr := 0
151+
152+
for scanner.Scan() {
153+
line := strings.TrimSpace(scanner.Text())
154+
if strings.Contains(line, filename) && !strings.HasPrefix(line, "#") {
155+
errCode := misc.ErrHTTPConflict
156+
errMsg := fmt.Sprintf("rejecting attempt to delete file %s referenced in haproxy conf at line %d: %s", filename, lineNr-1, line)
157+
e := &models.Error{Code: &errCode, Message: &errMsg}
158+
return storage.NewDeleteStorageSSLCertificateDefault(int(*e.Code)).WithPayload(e)
159+
}
160+
lineNr++
161+
}
162+
163+
err = h.Client.MapStorage.Delete(params.Name)
138164
if err != nil {
139165
e := misc.HandleError(err)
140166
return storage.NewDeleteStorageMapDefault(int(*e.Code)).WithPayload(e)

0 commit comments

Comments
 (0)