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
|
From 513b3863d999f91b47d7e9f26710390db55f9463 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Thu, 14 Jan 2016 14:28:37 +0100
Subject: ui-shared: prevent malicious filename from injecting headers
---
html.c | 26 ++++++++++++++++++++++++++
html.h | 1 +
ui-shared.c | 8 +++++---
3 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/html.c b/html.c
index 959148c..d89df3a 100644
--- a/html.c
+++ b/html.c
@@ -239,6 +239,32 @@ void html_url_arg(const char *txt)
html(txt);
}
+void html_header_arg_in_quotes(const char *txt)
+{
+ const char *t = txt;
+ while (t && *t) {
+ unsigned char c = *t;
+ const char *e = NULL;
+ if (c == '\\')
+ e = "\\\\";
+ else if (c == '\r')
+ e = "\\r";
+ else if (c == '\n')
+ e = "\\n";
+ else if (c == '"')
+ e = "\\\"";
+ if (e) {
+ html_raw(txt, t - txt);
+ html(e);
+ txt = t + 1;
+ }
+ t++;
+ }
+ if (t != txt)
+ html(txt);
+
+}
+
void html_hidden(const char *name, const char *value)
{
html("<input type='hidden' name='");
diff --git a/html.h b/html.h
index c554763..c72e845 100644
--- a/html.h
+++ b/html.h
@@ -23,6 +23,7 @@ extern void html_ntxt(int len, const char *txt);
extern void html_attr(const char *txt);
extern void html_url_path(const char *txt);
extern void html_url_arg(const char *txt);
+extern void html_header_arg_in_quotes(const char *txt);
extern void html_hidden(const char *name, const char *value);
extern void html_option(const char *value, const char *text, const char *selected_value);
extern void html_intoption(int value, const char *text, int selected_value);
diff --git a/ui-shared.c b/ui-shared.c
index 21f581f..54bbde7 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -692,9 +692,11 @@ void cgit_print_http_headers(void)
htmlf("Content-Type: %s\n", ctx.page.mimetype);
if (ctx.page.size)
htmlf("Content-Length: %zd\n", ctx.page.size);
- if (ctx.page.filename)
- htmlf("Content-Disposition: inline; filename=\"%s\"\n",
- ctx.page.filename);
+ if (ctx.page.filename) {
+ html("Content-Disposition: inline; filename=\"");
+ html_header_arg_in_quotes(ctx.page.filename);
+ html("\"\n");
+ }
if (!ctx.env.authenticated)
html("Cache-Control: no-cache, no-store\n");
htmlf("Last-Modified: %s\n", http_date(ctx.page.modified));
--
cgit v0.12-20-g4fde
|