File: CVE-2012-3512.patch

package info (click to toggle)
munin 1.4.5-3+deb6u1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze-lts
  • size: 4,988 kB
  • ctags: 806
  • sloc: perl: 8,936; sh: 3,105; java: 1,754; makefile: 585; python: 143
file content (173 lines) | stat: -rw-r--r-- 6,033 bytes parent folder | download
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
commit a0c9b6975a177f7898951c6ca120c3df0a4addeb
Author: Christoph Biedl <debian.axhn@manchmal.in-ulm.de>
Date:   Tue Jul 22 21:36:18 2014 +0200

    node: more secure state file handling
    
    [
      upstream commit 780634c
      bugfix commits 6183662 and 2b8d82e merged
      picked _resove_uid from 48640f1 and d7d1db6
    ]
    
    Currently, plugins which run as root mix their state files in the same
    directory as non-root plugins. The state directory is owned by munin:munin and
    is group-writable. Because of these facts, it is possible for an attacker who
    operates as user munin to cause a root-run plugin to run arbitrary code as
    root.
    
    This commit introduces :
    - a new plugin state directory root, owned by uid 0
    - each plugin runs in its own UID plugin state directory, owned by the said UID.
    
    Closes: #1234, D#679897, R#849830, CVE-2012-3512

diff --git a/Makefile b/Makefile
index 88f8952..1992193 100644
--- a/Makefile
+++ b/Makefile
@@ -127,8 +127,8 @@ install-plugins-prime: install-plugins build $(PLUGINS) Makefile Makefile.config
 	mkdir -p $(LIBDIR)/plugins
 	mkdir -p $(PLUGSTATE)
 
-	$(CHOWN) $(PLUGINUSER):$(GROUP) $(PLUGSTATE)
-	$(CHMOD) 0775 $(PLUGSTATE)
+	$(CHOWN) root:root $(PLUGSTATE)
+	$(CHMOD) 0755 $(PLUGSTATE)
 	$(CHMOD) 0755 $(CONFDIR)/plugin-conf.d
 
 	for p in build/plugins/node.d/* build/plugins/node.d.$(OSTYPE)/* ; do \
diff --git a/Makefile.config b/Makefile.config
index 84f155b..9098226 100644
--- a/Makefile.config
+++ b/Makefile.config
@@ -54,9 +54,12 @@ SSPOOLDIR  = $(PREFIX)/spool
 # Client only - Where to put RRD files and other intenal data
 DBDIR      = $(DESTDIR)/var/opt/munin
 
+# Where to put internal data for node (plugin state, ...)
+DBDIRNODE  = $(DESTDIR)/var/opt/munin-node
+
 # Client only - Where plugins should put their states. Must be writable by
 # group "munin", and should be preserved between reboots
-PLUGSTATE  = $(DBDIR)/plugin-state
+PLUGSTATE  = $(DBDIRNODE)/plugin-state
 
 # Where Munin should place its logs.
 LOGDIR     = $(PREFIX)/log/munin
diff --git a/debian/Makefile.config b/debian/Makefile.config
index f6f362a..8192def 100644
--- a/debian/Makefile.config
+++ b/debian/Makefile.config
@@ -5,6 +5,7 @@ PREFIX     = $(DESTDIR)/usr
 CONFDIR    = $(DESTDIR)/etc/munin
 HTMLDIR    = $(DESTDIR)/var/cache/munin/www
 DBDIR      = $(DESTDIR)/var/lib/munin
+DBDIRNODE  = $(DESTDIR)/var/lib/munin-node
 LOGDIR     = $(DESTDIR)/var/log/munin
 MANDIR     = $(PREFIX)/share/man
 
diff --git a/node/lib/Munin/Node/OS.pm b/node/lib/Munin/Node/OS.pm
index e7d00fd..7ef1835 100644
--- a/node/lib/Munin/Node/OS.pm
+++ b/node/lib/Munin/Node/OS.pm
@@ -280,6 +280,19 @@ sub set_plugin_umask {
     umask(0002);
 }
 
+sub set_umask { umask(0002) or croak "Unable to set umask: $!\n"; }
+
+sub mkdir_subdir {
+    my ($class, $path, $uid) = @_;
+
+    my $user = getpwuid($uid);
+
+    unless (-d "$path/$user") {
+        mkdir("$path/$user");
+        chown($uid, 0, "$path/$user");
+    }
+}
+
 
 1;
 
diff --git a/node/lib/Munin/Node/Service.pm b/node/lib/Munin/Node/Service.pm
index a292c0f..c23d36e 100644
--- a/node/lib/Munin/Node/Service.pm
+++ b/node/lib/Munin/Node/Service.pm
@@ -90,8 +90,13 @@ sub export_service_environment {
     my ($class, $service) = @_;
     print STDERR "# Setting up environment\n" if $config->{DEBUG};
 
+    # We append the USER to the MUNIN_PLUGSTATE, to avoid CVE-2012-3512
+    my $uid = _resolve_uid($service);
+    my $user = getpwuid($uid);
+    $ENV{MUNIN_PLUGSTATE} = "$Munin::Common::Defaults::MUNIN_PLUGSTATE/$user";
+
     # Provide a consistent default state-file.
-    $ENV{MUNIN_STATEFILE} = "$Munin::Common::Defaults::MUNIN_PLUGSTATE/$service-$ENV{MUNIN_MASTER_IP}";
+    $ENV{MUNIN_STATEFILE} = "$ENV{MUNIN_PLUGSTATE}/$service-$ENV{MUNIN_MASTER_IP}";
 
     my $env = $config->{sconf}{$service}{env} or return;
 
@@ -102,6 +107,27 @@ sub export_service_environment {
 }
 
 
+
+# Resolves the uid the service should be run as.  Either of the arguments can
+# be undefined.  If $service_user cannot be resolved, an exception will be
+# thrown.
+sub _resolve_uid
+{
+    my ($service) = @_;
+
+    my $user = $config->{sconf}{$service}{user};
+
+    # Need to test for defined, since a user might be specified with UID = 0
+    my $service_user = defined $user ? $user : $config->{defuser};
+
+    my $u = Munin::Node::OS->get_uid($service_user);
+    croak "User '$service_user' required for '$service' does not exist."
+        unless defined $u;
+
+    return $u;
+}
+
+
 sub change_real_and_effective_user_and_group
 {
     my ($class, $service) = @_;
@@ -197,6 +223,10 @@ sub change_real_and_effective_user_and_group
 sub exec_service {
     my ($class, $dir, $service, $arg) = @_;
 
+    # XXX - Create the statedir for the user
+    my $uid = _resolve_uid($service);
+    Munin::Node::OS->mkdir_subdir("$Munin::Common::Defaults::MUNIN_PLUGSTATE", $uid);
+
     $class->change_real_and_effective_user_and_group($service);
 
     unless (Munin::Node::OS->check_perms_if_paranoid("$dir/$service")) {
diff --git a/plugins/lib/Munin/Plugin.pm b/plugins/lib/Munin/Plugin.pm
index 1706d8b..6cad470 100644
--- a/plugins/lib/Munin/Plugin.pm
+++ b/plugins/lib/Munin/Plugin.pm
@@ -42,7 +42,7 @@ If your Munin installation predates the MUNIN_* environment variables
 (introduced in 1.3.3) you can put this in your plugin configuration:
 
   [*]
-      env.MUNIN_PLUGSTATE /lib/munin/plugin-state
+      env.MUNIN_PLUGSTATE /var/lib/munin-node/plugin-state
       env.MUNIN_LIBDIR /usr/share/munin
 
 IF, indeed that is the munin plugin state directory.  The default
@@ -584,7 +584,7 @@ need to be run as a special user or need special priveliges.
 There is some test stuff in this module.
 
   Test like this:
-  MUNIN_PLUGSTATE=/var/lib/munin/plugin-state -e 'require "Plugin.pm.in"; Munin::Plugin::_test;' -- or something.
+  MUNIN_PLUGSTATE=/var/lib/munin-node/plugin-state -e 'require "Plugin.pm.in"; Munin::Plugin::_test;' -- or something.
 
   sub _test () {
     my $pos;