rpm  5.2.1
legacy.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #if defined(HAVE_GELF_H)
8 #if LIBELF_H_LFS_CONFLICT
9 /* some gelf.h/libelf.h implementations (Solaris) are
10  * incompatible with the Large File API
11  */
12 # undef _LARGEFILE64_SOURCE
13 # undef _LARGEFILE_SOURCE
14 # undef _FILE_OFFSET_BITS
15 # define _FILE_OFFSET_BITS 32
16 #endif
17 #if defined(__LCLINT__)
18 /*@-incondefs@*/
19 typedef long long loff_t;
20 /*@=incondefs@*/
21 #endif
22 #include <gelf.h>
23 
24 #if !defined(DT_GNU_PRELINKED)
25 #define DT_GNU_PRELINKED 0x6ffffdf5
26 #endif
27 #if !defined(DT_GNU_LIBLIST)
28 #define DT_GNU_LIBLIST 0x6ffffef9
29 #endif
30 
31 #endif
32 
33 #include "rpmio_internal.h"
34 #include <rpmmacro.h>
35 #include "misc.h"
36 #include "legacy.h"
37 #include "debug.h"
38 
39 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
40 
48 /*@-compdef -moduncon -noeffectuncon @*/
49 static int open_dso(const char * path, /*@null@*/ pid_t * pidp, /*@null@*/ size_t *fsizep)
50  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
51  /*@modifies *pidp, *fsizep, rpmGlobalMacroContext,
52  fileSystem, internalState @*/
53 {
54 /*@only@*/
55  static const char * cmd = NULL;
56  static int oneshot = 0;
57  int fdno;
58 
59  if (!oneshot) {
60  cmd = rpmExpand("%{?__prelink_undo_cmd}", NULL);
61  oneshot++;
62  }
63 
64  if (pidp) *pidp = 0;
65 
66  if (fsizep) {
67  struct stat sb, * st = &sb;
68  if (stat(path, st) < 0)
69  return -1;
70  *fsizep = (size_t)st->st_size;
71  }
72 
73  fdno = open(path, O_RDONLY);
74  if (fdno < 0)
75  return fdno;
76 
77  if (!(cmd && *cmd))
78  return fdno;
79 
80 #if defined(HAVE_GELF_H) && defined(HAVE_LIBELF)
81  { Elf *elf = NULL;
82  Elf_Scn *scn = NULL;
83  Elf_Data *data = NULL;
84  GElf_Ehdr ehdr;
85  GElf_Shdr shdr;
86  GElf_Dyn dyn;
87  int bingo;
88 
89  (void) elf_version(EV_CURRENT);
90 
91 /*@-evalorder@*/
92  if ((elf = elf_begin (fdno, ELF_C_READ, NULL)) == NULL
93  || elf_kind(elf) != ELF_K_ELF
94  || gelf_getehdr(elf, &ehdr) == NULL
95  || !(ehdr.e_type == ET_DYN || ehdr.e_type == ET_EXEC))
96  goto exit;
97 /*@=evalorder@*/
98 
99  bingo = 0;
100  while (!bingo && (scn = elf_nextscn(elf, scn)) != NULL) {
101  (void) gelf_getshdr(scn, &shdr);
102  if (shdr.sh_type != SHT_DYNAMIC)
103  continue;
104  while (!bingo && (data = elf_getdata (scn, data)) != NULL) {
105  unsigned maxndx = (unsigned) (data->d_size / shdr.sh_entsize);
106  unsigned ndx;
107 
108  for (ndx = 0; ndx < maxndx; ++ndx) {
109 /*@-uniondef@*/
110  (void) gelf_getdyn (data, ndx, &dyn);
111 /*@=uniondef@*/
112  if (!(dyn.d_tag == DT_GNU_PRELINKED || dyn.d_tag == DT_GNU_LIBLIST))
113  /*@innercontinue@*/ continue;
114  bingo = 1;
115  /*@innerbreak@*/ break;
116  }
117  }
118  }
119 
120  if (pidp != NULL && bingo) {
121  int pipes[2];
122  pid_t pid;
123  int xx;
124 
125  xx = close(fdno);
126  pipes[0] = pipes[1] = -1;
127  xx = pipe(pipes);
128  if (!(pid = fork())) {
129  const char ** av;
130  int ac;
131  xx = close(pipes[0]);
132  xx = dup2(pipes[1], STDOUT_FILENO);
133  xx = close(pipes[1]);
134  if (!poptParseArgvString(cmd, &ac, &av)) {
135  av[ac-1] = path;
136  av[ac] = NULL;
137  unsetenv("MALLOC_CHECK_");
138  xx = execve(av[0], (char *const *)av+1, environ);
139  }
140  _exit(127);
141  }
142  *pidp = pid;
143  fdno = pipes[0];
144  xx = close(pipes[1]);
145  }
146 
147 exit:
148  if (elf) (void) elf_end(elf);
149  }
150 #endif
151 
152  return fdno;
153 }
154 /*@=compdef =moduncon =noeffectuncon @*/
155 
156 int dodigest(int digestalgo, const char * fn, unsigned char * digest, int asAscii, size_t *fsizep)
157 {
158  const char * path;
159  urltype ut = urlPath(fn, &path);
160  unsigned char * dsum = NULL;
161  size_t dlen;
162  unsigned char buf[32*BUFSIZ];
163  FD_t fd;
164  size_t fsize = 0;
165  pid_t pid = 0;
166  int use_mmap;
167  int rc = 0;
168  int fdno;
169 #if defined(HAVE_MMAP)
170  int xx;
171 #endif
172 
173 /*@-globs -internalglobs -mods @*/
174  fdno = open_dso(path, &pid, &fsize);
175 /*@=globs =internalglobs =mods @*/
176  if (fdno < 0) {
177  rc = 1;
178  goto exit;
179  }
180 
181  /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_SEQUENTIAL better. */
182  use_mmap = (pid == 0 && fsize <= 0x07ffffff);
183 
184  switch(ut) {
185  case URL_IS_PATH:
186  case URL_IS_UNKNOWN:
187 #if defined(HAVE_MMAP)
188  if (use_mmap) {
189  DIGEST_CTX ctx;
190  void * mapped = NULL;
191 
192  if (fsize) {
193  mapped = mmap(NULL, fsize, PROT_READ, MAP_SHARED, fdno, 0);
194  if (mapped == (void *)-1) {
195  xx = close(fdno);
196  rc = 1;
197  break;
198  }
199 
200 #if defined(HAVE_MADVISE) && defined(MADV_SEQUENTIAL)
201  xx = madvise(mapped, fsize, MADV_SEQUENTIAL);
202 #endif
203  }
204 
205  ctx = rpmDigestInit(digestalgo, RPMDIGEST_NONE);
206  if (fsize)
207  xx = rpmDigestUpdate(ctx, mapped, fsize);
208  xx = rpmDigestFinal(ctx, &dsum, &dlen, asAscii);
209  if (fsize)
210  xx = munmap(mapped, fsize);
211  xx = close(fdno);
212  break;
213  } /*@fallthrough@*/
214 #endif
215  case URL_IS_HTTPS:
216  case URL_IS_HTTP:
217  case URL_IS_FTP:
218  case URL_IS_HKP:
219  case URL_IS_DASH:
220  default:
221  /* Either use the pipe to prelink -y or open the URL. */
222  fd = (pid != 0) ? fdDup(fdno) : Fopen(fn, "r.fdio");
223  (void) close(fdno);
224  if (fd == NULL || Ferror(fd)) {
225  rc = 1;
226  if (fd != NULL)
227  (void) Fclose(fd);
228  break;
229  }
230 
231  fdInitDigest(fd, digestalgo, 0);
232  fsize = 0;
233  while ((rc = (int) Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
234  fsize += rc;
235  fdFiniDigest(fd, digestalgo, &dsum, &dlen, asAscii);
236  if (Ferror(fd))
237  rc = 1;
238 
239  (void) Fclose(fd);
240  break;
241  }
242 
243  /* Reap the prelink -y helper. */
244  if (pid) {
245  int status;
246 /*@+longunsignedintegral@*/
247  (void) waitpid(pid, &status, 0);
248 /*@=longunsignedintegral@*/
249  if (!WIFEXITED(status) || WEXITSTATUS(status))
250  rc = 1;
251  }
252 
253 exit:
254  if (fsizep)
255  *fsizep = fsize;
256  if (!rc)
257  memcpy(digest, dsum, dlen);
258  dsum = _free(dsum);
259 
260  return rc;
261 }