Bug Summary

File:xlators/features/marker/utils/src/gsyncd.c
Location:line 98, column 9
Description:Potential leak of memory pointed to by 'str'

Annotated Source Code

1/*
2 Copyright (c) 2011-2012 Red Hat, Inc. <http://www.redhat.com>
3 This file is part of GlusterFS.
4
5 This file is licensed to you under your choice of the GNU Lesser
6 General Public License, version 3 or any later version (LGPLv3 or
7 later), or the GNU General Public License, version 2 (GPLv2), in all
8 cases as published by the Free Software Foundation.
9*/
10
11#ifndef _CONFIG_H
12#define _CONFIG_H
13#include "config.h"
14#endif
15
16#include <stdlib.h>
17#include <stdio.h>
18#include <unistd.h>
19#include <string.h>
20#include <sys/param.h> /* for PATH_MAX */
21
22/* NOTE (USE_LIBGLUSTERFS):
23 * ------------------------
24 * When USE_LIBGLUSTERFS debugging sumbol is passed; perform
25 * glusterfs translator like initialization so that glusterfs
26 * globals, contexts are valid when glustefs api's are invoked.
27 * We unconditionally pass then while building gsyncd binary.
28 */
29#ifdef USE_LIBGLUSTERFS1
30#include "glusterfs.h"
31#include "globals.h"
32#endif
33
34#include "common-utils.h"
35#include "run.h"
36#include "procdiggy.h"
37
38#define _GLUSTERD_CALLED_"_GLUSTERD_CALLED_" "_GLUSTERD_CALLED_"
39#define _GSYNCD_DISPATCHED_"_GSYNCD_DISPATCHED_" "_GSYNCD_DISPATCHED_"
40#define GSYNCD_CONF"geo-replication/gsyncd.conf" "geo-replication/gsyncd.conf"
41#define GSYNCD_PY"gsyncd.py" "gsyncd.py"
42#define RSYNC"rsync" "rsync"
43
44int restricted = 0;
45
46static int
47duplexpand (void **buf, size_t tsiz, size_t *len)
48{
49 size_t osiz = tsiz * *len;
50 char *p = realloc (*buf, osiz << 1);
51 if (!p) {
52 free(*buf);
53 return -1;
54 }
55
56 memset (p + osiz, 0, osiz);
57 *buf = p;
58 *len <<= 1;
59
60 return 0;
61}
62
63static int
64str2argv (char *str, char ***argv)
65{
66 char *p = NULL((void*)0);
67 char *savetok = NULL((void*)0);
68 int argc = 0;
69 size_t argv_len = 32;
70 int ret = 0;
71
72 assert (str)((str) ? (void) (0) : __assert_fail ("str", "gsyncd.c", 72, __PRETTY_FUNCTION__
))
;
73 str = strdup (str);
11
Memory is allocated
74 if (!str)
12
Assuming 'str' is non-null
13
Taking false branch
75 return -1;
76
77 *argv = calloc (argv_len, sizeof (**argv));
78 if (!*argv)
14
Taking true branch
79 goto error;
15
Control jumps to line 98
80
81 while ((p = strtok_r (str, " ", &savetok))) {
82 str = NULL((void*)0);
83
84 argc++;
85 if (argc == argv_len) {
86 ret = duplexpand ((void *)argv,
87 sizeof (**argv),
88 &argv_len);
89 if (ret == -1)
90 goto error;
91 }
92 (*argv)[argc - 1] = p;
93 }
94
95 return argc;
96
97 error:
98 fprintf (stderrstderr, "out of memory\n");
16
Potential leak of memory pointed to by 'str'
99 return -1;
100}
101
102static int
103invoke_gsyncd (int argc, char **argv)
104{
105 char config_file[PATH_MAX4096] = {0,};
106 size_t gluster_workdir_len = 0;
107 runner_t runner = {0,};
108 int i = 0;
109 int j = 0;
110 char *nargv[argc + 4];
111 char *python = NULL((void*)0);
112
113 if (restricted) {
114 size_t len;
115 /* in restricted mode we forcibly use the system-wide config */
116 runinit (&runner);
117 runner_add_args (&runner, SBIN_DIR"/usr/local/sbin""/gluster",
118 "--log-file=-", "system::", "getwd",
119 NULL((void*)0));
120 runner_redir (&runner, STDOUT_FILENO1, RUN_PIPE-1);
121 if (runner_start (&runner) == 0 &&
122 fgets (config_file, PATH_MAX4096,
123 runner_chio (&runner, STDOUT_FILENO1)) != NULL((void*)0) &&
124 (len = strlen (config_file)) &&
125 config_file[len - 1] == '\n' &&
126 runner_end (&runner) == 0)
127 gluster_workdir_len = len - 1;
128
129 if (gluster_workdir_len) {
130 if (gluster_workdir_len + 1 + strlen (GSYNCD_CONF"geo-replication/gsyncd.conf") + 1 >
131 PATH_MAX4096)
132 goto error;
133 config_file[gluster_workdir_len] = '/';
134 strcat (config_file, GSYNCD_CONF"geo-replication/gsyncd.conf");
135 } else
136 goto error;
137
138 if (setenv ("_GSYNCD_RESTRICTED_", "1", 1) == -1)
139 goto error;
140 }
141
142 if (chdir ("/") == -1)
143 goto error;
144
145 j = 0;
146 python = getenv("PYTHON");
147 if(!python)
148 python = PYTHON"/usr/bin/python";
149 nargv[j++] = python;
150 nargv[j++] = GSYNCD_PREFIX"/usr/local/libexec/glusterfs""/python/syncdaemon/"GSYNCD_PY"gsyncd.py";
151 for (i = 1; i < argc; i++)
152 nargv[j++] = argv[i];
153 if (config_file[0]) {
154 nargv[j++] = "-c";
155 nargv[j++] = config_file;
156 }
157 nargv[j++] = NULL((void*)0);
158
159 execvp (python, nargv);
160
161 fprintf (stderrstderr, "exec of '%s' failed\n", python);
162 return 127;
163
164 error:
165 fprintf (stderrstderr, "gsyncd initializaion failed\n");
166 return 1;
167}
168
169
170static int
171find_gsyncd (pid_t pid, pid_t ppid, char *name, void *data)
172{
173 char buf[NAME_MAX255 * 2] = {0,};
174 char path[PATH_MAX4096] = {0,};
175 char *p = NULL((void*)0);
176 int zeros = 0;
177 int ret = 0;
178 int fd = -1;
179 pid_t *pida = (pid_t *)data;
180
181 if (ppid != pida[0])
182 return 0;
183
184 sprintf (path, PROC"/proc""/%d/cmdline", pid);
185 fd = open (path, O_RDONLY00);
186 if (fd == -1)
187 return 0;
188 ret = read (fd, buf, sizeof (buf));
189 close (fd);
190 if (ret == -1)
191 return 0;
192 for (zeros = 0, p = buf; zeros < 2 && p < buf + ret; p++)
193 zeros += !*p;
194
195 ret = 0;
196 switch (zeros) {
197 case 2:
198 if ((strcmp (basename (buf), basename (PYTHON"/usr/bin/python")) ||
199 strcmp (basename (buf + strlen (buf) + 1), GSYNCD_PY"gsyncd.py")) == 0) {
200 ret = 1;
201 break;
202 }
203 /* fallthrough */
204 case 1:
205 if (strcmp (basename (buf), GSYNCD_PY"gsyncd.py") == 0)
206 ret = 1;
207 }
208
209 if (ret == 1) {
210 if (pida[1] != -1) {
211 fprintf (stderrstderr, GSYNCD_PY"gsyncd.py"" sibling is not unique");
212 return -1;
213 }
214 pida[1] = pid;
215 }
216
217 return 0;
218}
219
220static int
221invoke_rsync (int argc, char **argv)
222{
223 int i = 0;
224 char path[PATH_MAX4096] = {0,};
225 pid_t pid = -1;
226 pid_t ppid = -1;
227 pid_t pida[] = {-1, -1};
228 char *name = NULL((void*)0);
229 char buf[PATH_MAX4096 + 1] = {0,};
230 int ret = 0;
231
232 assert (argv[argc] == NULL)((argv[argc] == ((void*)0)) ? (void) (0) : __assert_fail ("argv[argc] == ((void*)0)"
, "gsyncd.c", 232, __PRETTY_FUNCTION__))
;
233
234 if (argc < 2 || strcmp (argv[1], "--server") != 0)
235 goto error;
236
237 for (i = 2; i < argc && argv[i][0] == '-'; i++);
238
239 if (!(i == argc - 2 && strcmp (argv[i], ".") == 0 && argv[i + 1][0] == '/')) {
240 fprintf (stderrstderr, "need an rsync invocation without protected args\n");
241 goto error;
242 }
243
244 /* look up sshd we are spawned from */
245 for (pid = getpid () ;; pid = ppid) {
246 ppid = pidinfo (pid, &name);
247 if (ppid < 0) {
248 fprintf (stderrstderr, "sshd ancestor not found\n");
249 goto error;
250 }
251 if (strcmp (name, "sshd") == 0) {
252 GF_FREE (name)__gf_free (name);
253 break;
254 }
255 GF_FREE (name)__gf_free (name);
256 }
257 /* look up "ssh-sibling" gsyncd */
258 pida[0] = pid;
259 ret = prociter (find_gsyncd, pida);
260 if (ret == -1 || pida[1] == -1) {
261 fprintf (stderrstderr, "gsyncd sibling not found\n");
262 goto error;
263 }
264 /* check if rsync target matches gsyncd target */
265 sprintf (path, PROC"/proc""/%d/cwd", pida[1]);
266 ret = readlink (path, buf, sizeof (buf));
267 if (ret == -1 || ret == sizeof (buf))
268 goto error;
269 if (strcmp (argv[argc - 1], "/") == 0 /* root dir cannot be a target */ ||
270 (strcmp (argv[argc - 1], path) /* match against gluster target */ &&
271 strcmp (argv[argc - 1], buf) /* match against file target */) != 0) {
272 fprintf (stderrstderr, "rsync target does not match "GEOREP"geo-replication"" session\n");
273 goto error;
274 }
275
276 argv[0] = RSYNC"rsync";
277
278 execvp (RSYNC"rsync", argv);
279
280 fprintf (stderrstderr, "exec of "RSYNC"rsync"" failed\n");
281 return 127;
282
283 error:
284 fprintf (stderrstderr, "disallowed "RSYNC"rsync"" invocation\n");
285 return 1;
286}
287
288
289struct invocable {
290 char *name;
291 int (*invoker) (int argc, char **argv);
292};
293
294struct invocable invocables[] = {
295 { "rsync", invoke_rsync },
296 { "gsyncd", invoke_gsyncd },
297 { NULL((void*)0), NULL((void*)0)}
298};
299
300int
301main (int argc, char **argv)
302{
303 char *evas = NULL((void*)0);
304 struct invocable *i = NULL((void*)0);
305 char *b = NULL((void*)0);
306 char *sargv = NULL((void*)0);
307
308#ifdef USE_LIBGLUSTERFS1
309 glusterfs_ctx_t *ctx = NULL((void*)0);
310
311 ctx = glusterfs_ctx_new ();
312 if (!ctx)
1
Assuming 'ctx' is non-null
2
Taking false branch
313 return ENOMEM12;
314
315 if (glusterfs_globals_init (ctx))
3
Taking false branch
316 return 1;
317
318 THIS(*__glusterfs_this_location())->ctx = ctx;
319#endif
320
321 evas = getenv (_GLUSTERD_CALLED_"_GLUSTERD_CALLED_");
322 if (evas && strcmp (evas, "1") == 0)
323 /* OK, we know glusterd called us, no need to look for further config
324 * ... altough this conclusion should not inherit to our children
325 */
326 unsetenv (_GLUSTERD_CALLED_"_GLUSTERD_CALLED_");
327 else {
328 /* we regard all gsyncd invocations unsafe
329 * that do not come from glusterd and
330 * therefore restrict it
331 */
332 restricted = 1;
333
334 if (!getenv (_GSYNCD_DISPATCHED_"_GSYNCD_DISPATCHED_")) {
4
Taking true branch
335 evas = getenv ("SSH_ORIGINAL_COMMAND");
336 if (evas)
5
Assuming 'evas' is null
6
Taking false branch
337 sargv = evas;
338 else {
339 evas = getenv ("SHELL");
340 if (evas && strcmp (basename (evas), "gsyncd") == 0 &&
8
Taking true branch
341 argc == 3 && strcmp (argv[1], "-c") == 0)
7
Assuming 'argc' is equal to 3
342 sargv = argv[2];
343 }
344 }
345
346 }
347
348 if (!(sargv && restricted))
9
Taking false branch
349 return invoke_gsyncd (argc, argv);
350
351 argc = str2argv (sargv, &argv);
10
Calling 'str2argv'
352 if (argc == -1 || setenv (_GSYNCD_DISPATCHED_"_GSYNCD_DISPATCHED_", "1", 1) == -1) {
353 fprintf (stderrstderr, "internal error\n");
354 return 1;
355 }
356
357 b = basename (argv[0]);
358 for (i = invocables; i->name; i++) {
359 if (strcmp (b, i->name) == 0)
360 return i->invoker (argc, argv);
361 }
362
363 fprintf (stderrstderr, "invoking %s in restricted SSH session is not allowed\n",
364 b);
365
366 return 1;
367}