~ubuntu-branches/ubuntu/wily/clamav/wily-proposed

« back to all changes in this revision

Viewing changes to libclamav/c++/llvm/lib/System/Unix/Program.inc

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman, Sebastian Andrzej Siewior, Andreas Cadhalpun, Scott Kitterman, Javier Fernández-Sanguino
  • Date: 2015-01-28 00:25:13 UTC
  • mfrom: (0.48.14 sid)
  • Revision ID: package-import@ubuntu.com-20150128002513-lil2oi74cooy4lzr
Tags: 0.98.6+dfsg-1
[ Sebastian Andrzej Siewior ]
* update "fix-ssize_t-size_t-off_t-printf-modifier", include of misc.h was
  missing but was pulled in via the systemd patch.
* Don't leak return codes from libmspack to clamav API. (Closes: #774686).

[ Andreas Cadhalpun ]
* Add patch to avoid emitting incremental progress messages when not
  outputting to a terminal. (Closes: #767350)
* Update lintian-overrides for unused-file-paragraph-in-dep5-copyright.
* clamav-base.postinst: always chown /var/log/clamav and /var/lib/clamav
  to clamav:clamav, not only on fresh installations. (Closes: #775400)
* Adapt the clamav-daemon and clamav-freshclam logrotate scripts,
  so that they correctly work under systemd.
* Move the PidFile variable from the clamd/freshclam configuration files
  to the init scripts. This makes the init scripts more robust against
  misconfiguration and avoids error messages with systemd. (Closes: #767353)
* debian/copyright: drop files from Files-Excluded only present in github
  tarballs
* Drop Workaround-a-bug-in-libc-on-Hurd.patch, because hurd got fixed.
  (see #752237)
* debian/rules: Remove useless --with-system-tommath --without-included-ltdl
  configure options.

[ Scott Kitterman ]
* Stop stripping llvm when repacking the tarball as the system llvm on some
  releases is too old to use
* New upstream bugfix release
  - Library shared object revisions.
  - Includes a patch from Sebastian Andrzej Siewior making ClamAV pid files
    compatible with systemd.
  - Fix a heap out of bounds condition with crafted Yoda's crypter files.
    This issue was discovered by Felix Groebert of the Google Security Team.
  - Fix a heap out of bounds condition with crafted mew packer files. This
    issue was discovered by Felix Groebert of the Google Security Team.
  - Fix a heap out of bounds condition with crafted upx packer files. This
    issue was discovered by Kevin Szkudlapski of Quarkslab.
  - Fix a heap out of bounds condition with crafted upack packer files. This
    issue was discovered by Sebastian Andrzej Siewior. CVE-2014-9328.
  - Compensate a crash due to incorrect compiler optimization when handling
    crafted petite packer files. This issue was discovered by Sebastian
    Andrzej Siewior.
* Update lintian override for embedded zlib to match new so version

[ Javier Fernández-Sanguino ]
* Updated Spanish Debconf template translation (Closes: #773563)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//===- llvm/System/Unix/Program.cpp -----------------------------*- C++ -*-===//
 
2
//
 
3
//                     The LLVM Compiler Infrastructure
 
4
//
 
5
// This file is distributed under the University of Illinois Open Source
 
6
// License. See LICENSE.TXT for details.
 
7
//
 
8
//===----------------------------------------------------------------------===//
 
9
//
 
10
// This file implements the Unix specific portion of the Program class.
 
11
//
 
12
//===----------------------------------------------------------------------===//
 
13
 
 
14
//===----------------------------------------------------------------------===//
 
15
//=== WARNING: Implementation here must contain only generic UNIX code that
 
16
//===          is guaranteed to work on *all* UNIX variants.
 
17
//===----------------------------------------------------------------------===//
 
18
 
 
19
#include <llvm/Config/config.h>
 
20
#include "Unix.h"
 
21
#if HAVE_SYS_STAT_H
 
22
#include <sys/stat.h>
 
23
#endif
 
24
#if HAVE_SYS_RESOURCE_H
 
25
#include <sys/resource.h>
 
26
#endif
 
27
#if HAVE_SIGNAL_H
 
28
#include <signal.h>
 
29
#endif
 
30
#if HAVE_FCNTL_H
 
31
#include <fcntl.h>
 
32
#endif
 
33
#ifdef HAVE_POSIX_SPAWN
 
34
#include <spawn.h>
 
35
#if !defined(__APPLE__)
 
36
  extern char **environ;
 
37
#else
 
38
#include <crt_externs.h> // _NSGetEnviron
 
39
#endif
 
40
#endif
 
41
 
 
42
namespace llvm {
 
43
using namespace sys;
 
44
 
 
45
Program::Program() : Data_(0) {}
 
46
 
 
47
Program::~Program() {}
 
48
 
 
49
unsigned Program::GetPid() const {
 
50
  uint64_t pid = reinterpret_cast<uint64_t>(Data_);
 
51
  return static_cast<unsigned>(pid);
 
52
}
 
53
 
 
54
// This function just uses the PATH environment variable to find the program.
 
55
Path
 
56
Program::FindProgramByName(const std::string& progName) {
 
57
 
 
58
  // Check some degenerate cases
 
59
  if (progName.length() == 0) // no program
 
60
    return Path();
 
61
  Path temp;
 
62
  if (!temp.set(progName)) // invalid name
 
63
    return Path();
 
64
  // Use the given path verbatim if it contains any slashes; this matches
 
65
  // the behavior of sh(1) and friends.
 
66
  if (progName.find('/') != std::string::npos)
 
67
    return temp;
 
68
 
 
69
  // At this point, the file name does not contain slashes. Search for it
 
70
  // through the directories specified in the PATH environment variable.
 
71
 
 
72
  // Get the path. If its empty, we can't do anything to find it.
 
73
  const char *PathStr = getenv("PATH");
 
74
  if (PathStr == 0)
 
75
    return Path();
 
76
 
 
77
  // Now we have a colon separated list of directories to search; try them.
 
78
  size_t PathLen = strlen(PathStr);
 
79
  while (PathLen) {
 
80
    // Find the first colon...
 
81
    const char *Colon = std::find(PathStr, PathStr+PathLen, ':');
 
82
 
 
83
    // Check to see if this first directory contains the executable...
 
84
    Path FilePath;
 
85
    if (FilePath.set(std::string(PathStr,Colon))) {
 
86
      FilePath.appendComponent(progName);
 
87
      if (FilePath.canExecute())
 
88
        return FilePath;                    // Found the executable!
 
89
    }
 
90
 
 
91
    // Nope it wasn't in this directory, check the next path in the list!
 
92
    PathLen -= Colon-PathStr;
 
93
    PathStr = Colon;
 
94
 
 
95
    // Advance past duplicate colons
 
96
    while (*PathStr == ':') {
 
97
      PathStr++;
 
98
      PathLen--;
 
99
    }
 
100
  }
 
101
  return Path();
 
102
}
 
103
 
 
104
static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) {
 
105
  if (Path == 0) // Noop
 
106
    return false;
 
107
  const char *File;
 
108
  if (Path->isEmpty())
 
109
    // Redirect empty paths to /dev/null
 
110
    File = "/dev/null";
 
111
  else
 
112
    File = Path->c_str();
 
113
 
 
114
  // Open the file
 
115
  int InFD = open(File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
 
116
  if (InFD == -1) {
 
117
    MakeErrMsg(ErrMsg, "Cannot open file '" + std::string(File) + "' for "
 
118
              + (FD == 0 ? "input" : "output"));
 
119
    return true;
 
120
  }
 
121
 
 
122
  // Install it as the requested FD
 
123
  if (dup2(InFD, FD) == -1) {
 
124
    MakeErrMsg(ErrMsg, "Cannot dup2");
 
125
    close(InFD);
 
126
    return true;
 
127
  }
 
128
  close(InFD);      // Close the original FD
 
129
  return false;
 
130
}
 
131
 
 
132
#ifdef HAVE_POSIX_SPAWN
 
133
static bool RedirectIO_PS(const Path *Path, int FD, std::string *ErrMsg,
 
134
                          posix_spawn_file_actions_t &FileActions) {
 
135
  if (Path == 0) // Noop
 
136
    return false;
 
137
  const char *File;
 
138
  if (Path->isEmpty())
 
139
    // Redirect empty paths to /dev/null
 
140
    File = "/dev/null";
 
141
  else
 
142
    File = Path->c_str();
 
143
 
 
144
  if (int Err = posix_spawn_file_actions_addopen(&FileActions, FD,
 
145
                            File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666))
 
146
    return MakeErrMsg(ErrMsg, "Cannot dup2", Err);
 
147
  return false;
 
148
}
 
149
#endif
 
150
 
 
151
static void TimeOutHandler(int Sig) {
 
152
}
 
153
 
 
154
static void SetMemoryLimits (unsigned size)
 
155
{
 
156
#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT
 
157
  struct rlimit r;
 
158
  __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576;
 
159
 
 
160
  // Heap size
 
161
  getrlimit (RLIMIT_DATA, &r);
 
162
  r.rlim_cur = limit;
 
163
  setrlimit (RLIMIT_DATA, &r);
 
164
#ifdef RLIMIT_RSS
 
165
  // Resident set size.
 
166
  getrlimit (RLIMIT_RSS, &r);
 
167
  r.rlim_cur = limit;
 
168
  setrlimit (RLIMIT_RSS, &r);
 
169
#endif
 
170
#ifdef RLIMIT_AS  // e.g. NetBSD doesn't have it.
 
171
  // Virtual memory.
 
172
  getrlimit (RLIMIT_AS, &r);
 
173
  r.rlim_cur = limit;
 
174
  setrlimit (RLIMIT_AS, &r);
 
175
#endif
 
176
#endif
 
177
}
 
178
 
 
179
bool
 
180
Program::Execute(const Path &path, const char **args, const char **envp,
 
181
                 const Path **redirects, unsigned memoryLimit,
 
182
                  std::string *ErrMsg) {
 
183
  // If this OS has posix_spawn and there is no memory limit being implied, use
 
184
  // posix_spawn.  It is more efficient than fork/exec.
 
185
#ifdef HAVE_POSIX_SPAWN
 
186
  if (memoryLimit == 0) {
 
187
    posix_spawn_file_actions_t FileActions;
 
188
    posix_spawn_file_actions_init(&FileActions);
 
189
 
 
190
    if (redirects) {
 
191
      // Redirect stdin/stdout.
 
192
      if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) ||
 
193
          RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions))
 
194
        return false;
 
195
      if (redirects[1] == 0 || redirects[2] == 0 ||
 
196
          *redirects[1] != *redirects[2]) {
 
197
        // Just redirect stderr
 
198
        if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false;
 
199
      } else {       
 
200
        // If stdout and stderr should go to the same place, redirect stderr
 
201
        // to the FD already open for stdout.
 
202
        if (int Err = posix_spawn_file_actions_adddup2(&FileActions, 1, 2))
 
203
          return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err);
 
204
      }
 
205
    }
 
206
 
 
207
    if (!envp)
 
208
#if !defined(__APPLE__)
 
209
      envp = const_cast<const char **>(environ);
 
210
#else
 
211
      // environ is missing in dylibs.
 
212
      envp = const_cast<const char **>(*_NSGetEnviron());
 
213
#endif
 
214
 
 
215
    pid_t PID;
 
216
    int Err = posix_spawn(&PID, path.c_str(), &FileActions, /*attrp*/0,
 
217
                          const_cast<char **>(args), const_cast<char **>(envp));
 
218
                          
 
219
    posix_spawn_file_actions_destroy(&FileActions);
 
220
 
 
221
    if (Err)
 
222
     return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
 
223
      
 
224
    Data_ = reinterpret_cast<void*>(PID);
 
225
    return true;
 
226
  }
 
227
#endif
 
228
  
 
229
  if (!path.canExecute()) {
 
230
    if (ErrMsg)
 
231
      *ErrMsg = path.str() + " is not executable";
 
232
    return false;
 
233
  }
 
234
 
 
235
  // Create a child process.
 
236
  int child = fork();
 
237
  switch (child) {
 
238
    // An error occured:  Return to the caller.
 
239
    case -1:
 
240
      MakeErrMsg(ErrMsg, "Couldn't fork");
 
241
      return false;
 
242
 
 
243
    // Child process: Execute the program.
 
244
    case 0: {
 
245
      // Redirect file descriptors...
 
246
      if (redirects) {
 
247
        // Redirect stdin
 
248
        if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; }
 
249
        // Redirect stdout
 
250
        if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; }
 
251
        if (redirects[1] && redirects[2] &&
 
252
            *(redirects[1]) == *(redirects[2])) {
 
253
          // If stdout and stderr should go to the same place, redirect stderr
 
254
          // to the FD already open for stdout.
 
255
          if (-1 == dup2(1,2)) {
 
256
            MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout");
 
257
            return false;
 
258
          }
 
259
        } else {
 
260
          // Just redirect stderr
 
261
          if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; }
 
262
        }
 
263
      }
 
264
 
 
265
      // Set memory limits
 
266
      if (memoryLimit!=0) {
 
267
        SetMemoryLimits(memoryLimit);
 
268
      }
 
269
 
 
270
      // Execute!
 
271
      if (envp != 0)
 
272
        execve(path.c_str(),
 
273
               const_cast<char **>(args),
 
274
               const_cast<char **>(envp));
 
275
      else
 
276
        execv(path.c_str(),
 
277
              const_cast<char **>(args));
 
278
      // If the execve() failed, we should exit. Follow Unix protocol and
 
279
      // return 127 if the executable was not found, and 126 otherwise.
 
280
      // Use _exit rather than exit so that atexit functions and static
 
281
      // object destructors cloned from the parent process aren't
 
282
      // redundantly run, and so that any data buffered in stdio buffers
 
283
      // cloned from the parent aren't redundantly written out.
 
284
      _exit(errno == ENOENT ? 127 : 126);
 
285
    }
 
286
 
 
287
    // Parent process: Break out of the switch to do our processing.
 
288
    default:
 
289
      break;
 
290
  }
 
291
 
 
292
  Data_ = reinterpret_cast<void*>(child);
 
293
 
 
294
  return true;
 
295
}
 
296
 
 
297
int
 
298
Program::Wait(unsigned secondsToWait,
 
299
              std::string* ErrMsg)
 
300
{
 
301
#ifdef HAVE_SYS_WAIT_H
 
302
  struct sigaction Act, Old;
 
303
 
 
304
  if (Data_ == 0) {
 
305
    MakeErrMsg(ErrMsg, "Process not started!");
 
306
    return -1;
 
307
  }
 
308
 
 
309
  // Install a timeout handler.  The handler itself does nothing, but the simple
 
310
  // fact of having a handler at all causes the wait below to return with EINTR,
 
311
  // unlike if we used SIG_IGN.
 
312
  if (secondsToWait) {
 
313
    memset(&Act, 0, sizeof(Act));
 
314
    Act.sa_handler = TimeOutHandler;
 
315
    sigemptyset(&Act.sa_mask);
 
316
    sigaction(SIGALRM, &Act, &Old);
 
317
    alarm(secondsToWait);
 
318
  }
 
319
 
 
320
  // Parent process: Wait for the child process to terminate.
 
321
  int status;
 
322
  uint64_t pid = reinterpret_cast<uint64_t>(Data_);
 
323
  pid_t child = static_cast<pid_t>(pid);
 
324
  while (waitpid(pid, &status, 0) != child)
 
325
    if (secondsToWait && errno == EINTR) {
 
326
      // Kill the child.
 
327
      kill(child, SIGKILL);
 
328
 
 
329
      // Turn off the alarm and restore the signal handler
 
330
      alarm(0);
 
331
      sigaction(SIGALRM, &Old, 0);
 
332
 
 
333
      // Wait for child to die
 
334
      if (wait(&status) != child)
 
335
        MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
 
336
      else
 
337
        MakeErrMsg(ErrMsg, "Child timed out", 0);
 
338
 
 
339
      return -1;   // Timeout detected
 
340
    } else if (errno != EINTR) {
 
341
      MakeErrMsg(ErrMsg, "Error waiting for child process");
 
342
      return -1;
 
343
    }
 
344
 
 
345
  // We exited normally without timeout, so turn off the timer.
 
346
  if (secondsToWait) {
 
347
    alarm(0);
 
348
    sigaction(SIGALRM, &Old, 0);
 
349
  }
 
350
 
 
351
  // Return the proper exit status. 0=success, >0 is programs' exit status,
 
352
  // <0 means a signal was returned, -9999999 means the program dumped core.
 
353
  int result = 0;
 
354
  if (WIFEXITED(status))
 
355
    result = WEXITSTATUS(status);
 
356
  else if (WIFSIGNALED(status))
 
357
    result = 0 - WTERMSIG(status);
 
358
#ifdef WCOREDUMP
 
359
  else if (WCOREDUMP(status))
 
360
    result |= 0x01000000;
 
361
#endif
 
362
  return result;
 
363
#else
 
364
  return -99;
 
365
#endif
 
366
 
 
367
}
 
368
 
 
369
bool
 
370
Program::Kill(std::string* ErrMsg) {
 
371
  if (Data_ == 0) {
 
372
    MakeErrMsg(ErrMsg, "Process not started!");
 
373
    return true;
 
374
  }
 
375
 
 
376
  uint64_t pid64 = reinterpret_cast<uint64_t>(Data_);
 
377
  pid_t pid = static_cast<pid_t>(pid64);
 
378
 
 
379
  if (kill(pid, SIGKILL) != 0) {
 
380
    MakeErrMsg(ErrMsg, "The process couldn't be killed!");
 
381
    return true;
 
382
  }
 
383
 
 
384
  return false;
 
385
}
 
386
 
 
387
bool Program::ChangeStdinToBinary(){
 
388
  // Do nothing, as Unix doesn't differentiate between text and binary.
 
389
  return false;
 
390
}
 
391
 
 
392
bool Program::ChangeStdoutToBinary(){
 
393
  // Do nothing, as Unix doesn't differentiate between text and binary.
 
394
  return false;
 
395
}
 
396
 
 
397
bool Program::ChangeStderrToBinary(){
 
398
  // Do nothing, as Unix doesn't differentiate between text and binary.
 
399
  return false;
 
400
}
 
401
 
 
402
}