src/preload.c

download
#define open real_open
#define open64 real_open64
#define openat real_openat
#define openat64 real_openat64
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <zip.h>
#include <stdlib.h>
#include <string.h>
#undef open
#undef open64
#undef openat
#undef openat64

#define JNDI_LOOKUP_CLASS \
  "org/apache/logging/log4j/core/lookup/JndiLookup.class"

typedef int (*openat_t)(int dirfd, const char *pathname,
                        int flags, mode_t mode);
typedef int (*open_t)(const char *pathname, int flags, mode_t mode);

static int
check_load_file(int dirfd, const char *pathname, int flags, mode_t mode) {
  static openat_t real_openat64 = NULL;
  if (!real_openat64) { real_openat64 = dlsym(RTLD_NEXT, "openat64"); }

  int fd = real_openat64(dirfd, pathname, flags, mode);

  printf("Checking file %s\n", pathname);
  if (fd < 0) { return fd; }
  int fd2 = real_openat64(dirfd, pathname, O_RDONLY, mode);
  zip_t *zip = zip_fdopen(fd2, 0, NULL);
  if (!zip) { close(fd2); return fd; }
  zip_int64_t loc = zip_name_locate(zip, JNDI_LOOKUP_CLASS, 0);
  if (loc < 0) { goto done_close_zip; }
  /* we do need to modify */
  close(fd); fd = -1;
  if (dirfd != AT_FDCWD && pathname[0] != '/') {
    fprintf(stderr, "TODO: Can't inspect readdirat() paths yet (libzip...)\n");
    goto done_close_zip;
  }
  zip_close(zip);
  zip = zip_open(pathname, 0, NULL);
  if (!zip) { fprintf(stderr, "Reopen failed\n"); goto done_close_zip; }
  loc = zip_name_locate(zip, JNDI_LOOKUP_CLASS, 0);
  if (loc < 0) {
    printf("JndiLookup disappeared?\n");
    goto done_close_zip;
  }
  if (zip_delete(zip, loc) < 0) {
    fprintf(stderr, "Zip modification failed: %s\n", zip_strerror(zip));
    goto done_close_zip;
  }
  if (zip_close(zip) < 0) {
    fprintf(stderr,"Could not save zip: %s\n", zip_strerror(zip));
    return fd;
  }
  return real_openat64(dirfd, pathname, flags, mode);

done_close_zip:
  if (zip_close(zip) < 0) {
    fprintf(stderr,"Could not save zip: %s\n", zip_strerror(zip));
  }
ret:
  return fd;
}

int openat(int dirfd, const char *pathname, int flags, mode_t mode) {
  printf("openat intercepted %d %s\n", dirfd, pathname);
  return check_load_file(dirfd, pathname, flags, mode);
}
int openat64(int dirfd, const char *pathname, int flags, mode_t mode) {
  printf("openat64 intercepted %d %s\n", dirfd, pathname);
  return check_load_file(dirfd, pathname, flags, mode);
}
int open(const char *pathname, int flags, mode_t mode) {
  /* check if the call is coming from ourselves */
  Dl_info info1, info2;
  if (dladdr(__builtin_return_address(0), &info1) &&
      dladdr(&open, &info2) &&
      info1.dli_fname == info2.dli_fname) {
    static open_t real_open = NULL;
    if (!real_open) { real_open = dlsym(RTLD_NEXT, "open"); }
    printf("skipping self call %s\n", info1.dli_sname);
    return real_open(pathname, flags, mode);
  }
  printf("open intercepted %s\n", pathname);
  return check_load_file(AT_FDCWD, pathname, flags, mode);
}
int open64(const char *pathname, int flags, mode_t mode) {
  printf("open64 intercepted %s\n", pathname);
  return check_load_file(AT_FDCWD, pathname, flags, mode);
}