101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2015-2018 Intel Corporation
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg#undef _FILE_OFFSET_BITS /* prevent #define open open64 */
2501e04c3fSmrg
2601e04c3fSmrg#include <string.h>
2701e04c3fSmrg#include <stdlib.h>
2801e04c3fSmrg#include <stdio.h>
2901e04c3fSmrg#include <stdint.h>
3001e04c3fSmrg#include <stdarg.h>
3101e04c3fSmrg#include <fcntl.h>
3201e04c3fSmrg#include <unistd.h>
3301e04c3fSmrg#include <sys/ioctl.h>
3401e04c3fSmrg#include <sys/stat.h>
3501e04c3fSmrg#include <sys/mman.h>
3601e04c3fSmrg#include <sys/sysmacros.h>
3701e04c3fSmrg#include <dlfcn.h>
3801e04c3fSmrg#include <pthread.h>
399f464c52Smaya#include "drm-uapi/i915_drm.h"
4001e04c3fSmrg
4101e04c3fSmrg#include "util/hash_table.h"
429f464c52Smaya#include "util/u_math.h"
4301e04c3fSmrg
447ec681f3Smrg#define MESA_LOG_TAG "INTEL-SANITIZE-GPU"
457ec681f3Smrg#include "util/log.h"
467ec681f3Smrg#include "common/intel_clflush.h"
4701e04c3fSmrg
4801e04c3fSmrgstatic int (*libc_open)(const char *pathname, int flags, mode_t mode);
4901e04c3fSmrgstatic int (*libc_close)(int fd);
5001e04c3fSmrgstatic int (*libc_ioctl)(int fd, unsigned long request, void *argp);
5101e04c3fSmrgstatic int (*libc_fcntl)(int fd, int cmd, int param);
5201e04c3fSmrg
5301e04c3fSmrg#define DRM_MAJOR 226
5401e04c3fSmrg
5501e04c3fSmrg/* TODO: we want to make sure that the padding forces
5601e04c3fSmrg * the BO to take another page on the (PP)GTT; 4KB
5701e04c3fSmrg * may or may not be the page size for the BO. Indeed,
5801e04c3fSmrg * depending on GPU, kernel version and GEM size, the
5901e04c3fSmrg * page size can be one of 4KB, 64KB or 2M.
6001e04c3fSmrg */
6101e04c3fSmrg#define PADDING_SIZE 4096
6201e04c3fSmrg
6301e04c3fSmrgstruct refcnt_hash_table {
6401e04c3fSmrg   struct hash_table *t;
6501e04c3fSmrg   int refcnt;
6601e04c3fSmrg};
6701e04c3fSmrg
6801e04c3fSmrgpthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
6901e04c3fSmrg#define MUTEX_LOCK() do {                        \
7001e04c3fSmrg   if (unlikely(pthread_mutex_lock(&mutex))) {   \
717ec681f3Smrg      mesa_loge("mutex_lock failed");           \
7201e04c3fSmrg      abort();                                   \
7301e04c3fSmrg   }                                             \
7401e04c3fSmrg} while (0)
7501e04c3fSmrg#define MUTEX_UNLOCK() do {                      \
7601e04c3fSmrg   if (unlikely(pthread_mutex_unlock(&mutex))) { \
777ec681f3Smrg      mesa_loge("mutex_unlock failed");         \
7801e04c3fSmrg      abort();                                   \
7901e04c3fSmrg   }                                             \
8001e04c3fSmrg} while (0)
8101e04c3fSmrg
8201e04c3fSmrgstatic struct hash_table *fds_to_bo_sizes = NULL;
8301e04c3fSmrg
8401e04c3fSmrgstatic inline struct hash_table*
8501e04c3fSmrgbo_size_table(int fd)
8601e04c3fSmrg{
8701e04c3fSmrg   struct hash_entry *e = _mesa_hash_table_search(fds_to_bo_sizes,
8801e04c3fSmrg                                                  (void*)(uintptr_t)fd);
8901e04c3fSmrg   return e ? ((struct refcnt_hash_table*)e->data)->t : NULL;
9001e04c3fSmrg}
9101e04c3fSmrg
9201e04c3fSmrgstatic inline uint64_t
9301e04c3fSmrgbo_size(int fd, uint32_t handle)
9401e04c3fSmrg{
9501e04c3fSmrg   struct hash_table *t = bo_size_table(fd);
9601e04c3fSmrg   if (!t)
9701e04c3fSmrg      return UINT64_MAX;
9801e04c3fSmrg   struct hash_entry *e = _mesa_hash_table_search(t, (void*)(uintptr_t)handle);
997ec681f3Smrg   return e ? (uint64_t)(uintptr_t)e->data : UINT64_MAX;
10001e04c3fSmrg}
10101e04c3fSmrg
10201e04c3fSmrgstatic inline bool
10301e04c3fSmrgis_drm_fd(int fd)
10401e04c3fSmrg{
10501e04c3fSmrg   return !!bo_size_table(fd);
10601e04c3fSmrg}
10701e04c3fSmrg
10801e04c3fSmrgstatic inline void
10901e04c3fSmrgadd_drm_fd(int fd)
11001e04c3fSmrg{
11101e04c3fSmrg   struct refcnt_hash_table *r = malloc(sizeof(*r));
11201e04c3fSmrg   r->refcnt = 1;
1139f464c52Smaya   r->t = _mesa_pointer_hash_table_create(NULL);
11401e04c3fSmrg   _mesa_hash_table_insert(fds_to_bo_sizes, (void*)(uintptr_t)fd,
11501e04c3fSmrg                           (void*)(uintptr_t)r);
11601e04c3fSmrg}
11701e04c3fSmrg
11801e04c3fSmrgstatic inline void
11901e04c3fSmrgdup_drm_fd(int old_fd, int new_fd)
12001e04c3fSmrg{
12101e04c3fSmrg   struct hash_entry *e = _mesa_hash_table_search(fds_to_bo_sizes,
12201e04c3fSmrg                                                  (void*)(uintptr_t)old_fd);
12301e04c3fSmrg   struct refcnt_hash_table *r = e->data;
12401e04c3fSmrg   r->refcnt++;
12501e04c3fSmrg   _mesa_hash_table_insert(fds_to_bo_sizes, (void*)(uintptr_t)new_fd,
12601e04c3fSmrg                           (void*)(uintptr_t)r);
12701e04c3fSmrg}
12801e04c3fSmrg
12901e04c3fSmrgstatic inline void
13001e04c3fSmrgdel_drm_fd(int fd)
13101e04c3fSmrg{
13201e04c3fSmrg   struct hash_entry *e = _mesa_hash_table_search(fds_to_bo_sizes,
13301e04c3fSmrg                                                  (void*)(uintptr_t)fd);
13401e04c3fSmrg   struct refcnt_hash_table *r = e->data;
13501e04c3fSmrg   if (!--r->refcnt) {
13601e04c3fSmrg      _mesa_hash_table_remove(fds_to_bo_sizes, e);
13701e04c3fSmrg      _mesa_hash_table_destroy(r->t, NULL);
13801e04c3fSmrg      free(r);
13901e04c3fSmrg   }
14001e04c3fSmrg}
14101e04c3fSmrg
14201e04c3fSmrg/* Our goal is not to have noise good enough for cryto,
14301e04c3fSmrg * but instead values that are unique-ish enough that
14401e04c3fSmrg * it is incredibly unlikely that a buffer overwrite
14501e04c3fSmrg * will produce the exact same values.
14601e04c3fSmrg */
14701e04c3fSmrgstatic uint8_t
14801e04c3fSmrgnext_noise_value(uint8_t prev_noise)
14901e04c3fSmrg{
15001e04c3fSmrg   uint32_t v = prev_noise;
15101e04c3fSmrg   return (v * 103u + 227u) & 0xFF;
15201e04c3fSmrg}
15301e04c3fSmrg
15401e04c3fSmrgstatic void
15501e04c3fSmrgfill_noise_buffer(uint8_t *dst, uint8_t start, uint32_t length)
15601e04c3fSmrg{
15701e04c3fSmrg   for(uint32_t i = 0; i < length; ++i) {
15801e04c3fSmrg      dst[i] = start;
15901e04c3fSmrg      start = next_noise_value(start);
16001e04c3fSmrg   }
16101e04c3fSmrg}
16201e04c3fSmrg
16301e04c3fSmrgstatic bool
16401e04c3fSmrgpadding_is_good(int fd, uint32_t handle)
16501e04c3fSmrg{
16601e04c3fSmrg   struct drm_i915_gem_mmap mmap_arg = {
16701e04c3fSmrg      .handle = handle,
1689f464c52Smaya      .offset = align64(bo_size(fd, handle), 4096),
16901e04c3fSmrg      .size = PADDING_SIZE,
17001e04c3fSmrg      .flags = 0,
17101e04c3fSmrg   };
17201e04c3fSmrg
17301e04c3fSmrg   /* Unknown bo, maybe prime or userptr. Ignore */
17401e04c3fSmrg   if (mmap_arg.offset == UINT64_MAX)
17501e04c3fSmrg      return true;
17601e04c3fSmrg
17701e04c3fSmrg   uint8_t *mapped;
17801e04c3fSmrg   int ret;
17901e04c3fSmrg   uint8_t expected_value;
18001e04c3fSmrg
18101e04c3fSmrg   ret = libc_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg);
18201e04c3fSmrg   if (ret != 0) {
1837ec681f3Smrg      mesa_logd("Unable to map buffer %d for pad checking.", handle);
18401e04c3fSmrg      return false;
18501e04c3fSmrg   }
18601e04c3fSmrg
18701e04c3fSmrg   mapped = (uint8_t*) (uintptr_t) mmap_arg.addr_ptr;
18801e04c3fSmrg   /* bah-humbug, we need to see the latest contents and
18901e04c3fSmrg    * if the bo is not cache coherent we likely need to
19001e04c3fSmrg    * invalidate the cache lines to get it.
19101e04c3fSmrg    */
1927ec681f3Smrg   intel_invalidate_range(mapped, PADDING_SIZE);
19301e04c3fSmrg
19401e04c3fSmrg   expected_value = handle & 0xFF;
19501e04c3fSmrg   for (uint32_t i = 0; i < PADDING_SIZE; ++i) {
19601e04c3fSmrg      if (expected_value != mapped[i]) {
19701e04c3fSmrg         munmap(mapped, PADDING_SIZE);
19801e04c3fSmrg         return false;
19901e04c3fSmrg      }
20001e04c3fSmrg      expected_value = next_noise_value(expected_value);
20101e04c3fSmrg   }
20201e04c3fSmrg   munmap(mapped, PADDING_SIZE);
20301e04c3fSmrg
20401e04c3fSmrg   return true;
20501e04c3fSmrg}
20601e04c3fSmrg
20701e04c3fSmrgstatic int
20801e04c3fSmrgcreate_with_padding(int fd, struct drm_i915_gem_create *create)
20901e04c3fSmrg{
2109f464c52Smaya   uint64_t original_size = create->size;
2119f464c52Smaya
2129f464c52Smaya   create->size = align64(original_size, 4096) + PADDING_SIZE;
21301e04c3fSmrg   int ret = libc_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, create);
2149f464c52Smaya   create->size = original_size;
21501e04c3fSmrg
21601e04c3fSmrg   if (ret != 0)
21701e04c3fSmrg      return ret;
21801e04c3fSmrg
21901e04c3fSmrg   uint8_t *noise_values;
22001e04c3fSmrg   struct drm_i915_gem_mmap mmap_arg = {
22101e04c3fSmrg      .handle = create->handle,
2229f464c52Smaya      .offset = align64(create->size, 4096),
22301e04c3fSmrg      .size = PADDING_SIZE,
22401e04c3fSmrg      .flags = 0,
22501e04c3fSmrg   };
22601e04c3fSmrg
22701e04c3fSmrg   ret = libc_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg);
2289f464c52Smaya   if (ret != 0) {
2297ec681f3Smrg      mesa_logd("Unable to map buffer %d for pad creation.\n", create->handle);
23001e04c3fSmrg      return 0;
2319f464c52Smaya   }
23201e04c3fSmrg
23301e04c3fSmrg   noise_values = (uint8_t*) (uintptr_t) mmap_arg.addr_ptr;
23401e04c3fSmrg   fill_noise_buffer(noise_values, create->handle & 0xFF,
23501e04c3fSmrg                     PADDING_SIZE);
23601e04c3fSmrg   munmap(noise_values, PADDING_SIZE);
23701e04c3fSmrg
23801e04c3fSmrg   _mesa_hash_table_insert(bo_size_table(fd), (void*)(uintptr_t)create->handle,
23901e04c3fSmrg                           (void*)(uintptr_t)create->size);
24001e04c3fSmrg
24101e04c3fSmrg   return 0;
24201e04c3fSmrg}
24301e04c3fSmrg
24401e04c3fSmrgstatic int
24501e04c3fSmrgexec_and_check_padding(int fd, unsigned long request,
24601e04c3fSmrg                       struct drm_i915_gem_execbuffer2 *exec)
24701e04c3fSmrg{
24801e04c3fSmrg   int ret = libc_ioctl(fd, request, exec);
24901e04c3fSmrg   if (ret != 0)
25001e04c3fSmrg      return ret;
25101e04c3fSmrg
25201e04c3fSmrg   struct drm_i915_gem_exec_object2 *objects =
25301e04c3fSmrg      (void*)(uintptr_t)exec->buffers_ptr;
25401e04c3fSmrg   uint32_t batch_bo = exec->flags & I915_EXEC_BATCH_FIRST ? objects[0].handle :
25501e04c3fSmrg      objects[exec->buffer_count - 1].handle;
25601e04c3fSmrg
25701e04c3fSmrg   struct drm_i915_gem_wait wait = {
25801e04c3fSmrg      .bo_handle = batch_bo,
25901e04c3fSmrg      .timeout_ns = -1,
26001e04c3fSmrg   };
26101e04c3fSmrg   ret = libc_ioctl(fd, DRM_IOCTL_I915_GEM_WAIT, &wait);
26201e04c3fSmrg   if (ret != 0)
26301e04c3fSmrg      return ret;
26401e04c3fSmrg
26501e04c3fSmrg   bool detected_out_of_bounds_write = false;
26601e04c3fSmrg
26701e04c3fSmrg   for (int i = 0; i < exec->buffer_count; i++) {
26801e04c3fSmrg      uint32_t handle = objects[i].handle;
26901e04c3fSmrg
27001e04c3fSmrg      if (!padding_is_good(fd, handle)) {
27101e04c3fSmrg         detected_out_of_bounds_write = true;
2727ec681f3Smrg         mesa_loge("Detected buffer out-of-bounds write in bo %d", handle);
27301e04c3fSmrg      }
27401e04c3fSmrg   }
27501e04c3fSmrg
27601e04c3fSmrg   if (unlikely(detected_out_of_bounds_write)) {
27701e04c3fSmrg      abort();
27801e04c3fSmrg   }
27901e04c3fSmrg
28001e04c3fSmrg   return 0;
28101e04c3fSmrg}
28201e04c3fSmrg
28301e04c3fSmrgstatic int
28401e04c3fSmrggem_close(int fd, struct drm_gem_close *close)
28501e04c3fSmrg{
28601e04c3fSmrg   int ret = libc_ioctl(fd, DRM_IOCTL_GEM_CLOSE, close);
28701e04c3fSmrg   if (ret != 0)
28801e04c3fSmrg      return ret;
28901e04c3fSmrg
29001e04c3fSmrg   struct hash_table *t = bo_size_table(fd);
29101e04c3fSmrg   struct hash_entry *e =
29201e04c3fSmrg      _mesa_hash_table_search(t, (void*)(uintptr_t)close->handle);
29301e04c3fSmrg
29401e04c3fSmrg   if (e)
29501e04c3fSmrg      _mesa_hash_table_remove(t, e);
29601e04c3fSmrg
29701e04c3fSmrg   return 0;
29801e04c3fSmrg}
29901e04c3fSmrg
30001e04c3fSmrgstatic bool
30101e04c3fSmrgis_i915(int fd) {
30201e04c3fSmrg   struct stat stat;
30301e04c3fSmrg   if (fstat(fd, &stat))
30401e04c3fSmrg      return false;
30501e04c3fSmrg
30601e04c3fSmrg   if (!S_ISCHR(stat.st_mode) || major(stat.st_rdev) != DRM_MAJOR)
30701e04c3fSmrg      return false;
30801e04c3fSmrg
30901e04c3fSmrg   char name[5] = "";
31001e04c3fSmrg   drm_version_t version = {
31101e04c3fSmrg      .name = name,
31201e04c3fSmrg      .name_len = sizeof(name) - 1,
31301e04c3fSmrg   };
31401e04c3fSmrg   if (libc_ioctl(fd, DRM_IOCTL_VERSION, &version))
31501e04c3fSmrg      return false;
31601e04c3fSmrg
31701e04c3fSmrg   return strcmp("i915", name) == 0;
31801e04c3fSmrg}
31901e04c3fSmrg
32001e04c3fSmrg__attribute__ ((visibility ("default"))) int
32101e04c3fSmrgopen(const char *path, int flags, ...)
32201e04c3fSmrg{
32301e04c3fSmrg   va_list args;
32401e04c3fSmrg   mode_t mode;
32501e04c3fSmrg
32601e04c3fSmrg   va_start(args, flags);
32701e04c3fSmrg   mode = va_arg(args, int);
32801e04c3fSmrg   va_end(args);
32901e04c3fSmrg
33001e04c3fSmrg   int fd = libc_open(path, flags, mode);
33101e04c3fSmrg
33201e04c3fSmrg   MUTEX_LOCK();
33301e04c3fSmrg
33401e04c3fSmrg   if (fd >= 0 && is_i915(fd))
33501e04c3fSmrg      add_drm_fd(fd);
33601e04c3fSmrg
33701e04c3fSmrg   MUTEX_UNLOCK();
33801e04c3fSmrg
33901e04c3fSmrg   return fd;
34001e04c3fSmrg}
34101e04c3fSmrg
34201e04c3fSmrg__attribute__ ((visibility ("default"), alias ("open"))) int
34301e04c3fSmrgopen64(const char *path, int flags, ...);
34401e04c3fSmrg
34501e04c3fSmrg__attribute__ ((visibility ("default"))) int
34601e04c3fSmrgclose(int fd)
34701e04c3fSmrg{
34801e04c3fSmrg   MUTEX_LOCK();
34901e04c3fSmrg
35001e04c3fSmrg   if (is_drm_fd(fd))
35101e04c3fSmrg      del_drm_fd(fd);
35201e04c3fSmrg
35301e04c3fSmrg   MUTEX_UNLOCK();
35401e04c3fSmrg
35501e04c3fSmrg   return libc_close(fd);
35601e04c3fSmrg}
35701e04c3fSmrg
35801e04c3fSmrg__attribute__ ((visibility ("default"))) int
35901e04c3fSmrgfcntl(int fd, int cmd, ...)
36001e04c3fSmrg{
36101e04c3fSmrg   va_list args;
36201e04c3fSmrg   int param;
36301e04c3fSmrg
36401e04c3fSmrg   va_start(args, cmd);
36501e04c3fSmrg   param = va_arg(args, int);
36601e04c3fSmrg   va_end(args);
36701e04c3fSmrg
36801e04c3fSmrg   int res = libc_fcntl(fd, cmd, param);
36901e04c3fSmrg
37001e04c3fSmrg   MUTEX_LOCK();
37101e04c3fSmrg
37201e04c3fSmrg   if (is_drm_fd(fd) && cmd == F_DUPFD_CLOEXEC)
37301e04c3fSmrg      dup_drm_fd(fd, res);
37401e04c3fSmrg
37501e04c3fSmrg   MUTEX_UNLOCK();
37601e04c3fSmrg
37701e04c3fSmrg   return res;
37801e04c3fSmrg}
37901e04c3fSmrg
38001e04c3fSmrg__attribute__ ((visibility ("default"))) int
38101e04c3fSmrgioctl(int fd, unsigned long request, ...)
38201e04c3fSmrg{
38301e04c3fSmrg   int res;
38401e04c3fSmrg   va_list args;
38501e04c3fSmrg   void *argp;
38601e04c3fSmrg
38701e04c3fSmrg   MUTEX_LOCK();
38801e04c3fSmrg
38901e04c3fSmrg   va_start(args, request);
39001e04c3fSmrg   argp = va_arg(args, void *);
39101e04c3fSmrg   va_end(args);
39201e04c3fSmrg
39301e04c3fSmrg   if (_IOC_TYPE(request) == DRM_IOCTL_BASE && !is_drm_fd(fd) && is_i915(fd)) {
3947ec681f3Smrg      mesa_loge("missed drm fd %d", fd);
39501e04c3fSmrg      add_drm_fd(fd);
39601e04c3fSmrg   }
39701e04c3fSmrg
39801e04c3fSmrg   if (is_drm_fd(fd)) {
39901e04c3fSmrg      switch (request) {
40001e04c3fSmrg      case DRM_IOCTL_GEM_CLOSE:
40101e04c3fSmrg         res = gem_close(fd, (struct drm_gem_close*)argp);
40201e04c3fSmrg         goto out;
40301e04c3fSmrg
40401e04c3fSmrg      case DRM_IOCTL_I915_GEM_CREATE:
40501e04c3fSmrg         res = create_with_padding(fd, (struct drm_i915_gem_create*)argp);
40601e04c3fSmrg         goto out;
40701e04c3fSmrg
40801e04c3fSmrg      case DRM_IOCTL_I915_GEM_EXECBUFFER2:
40901e04c3fSmrg      case DRM_IOCTL_I915_GEM_EXECBUFFER2_WR:
41001e04c3fSmrg         res = exec_and_check_padding(fd, request,
41101e04c3fSmrg                                      (struct drm_i915_gem_execbuffer2*)argp);
41201e04c3fSmrg         goto out;
41301e04c3fSmrg
41401e04c3fSmrg      default:
41501e04c3fSmrg         break;
41601e04c3fSmrg      }
41701e04c3fSmrg   }
41801e04c3fSmrg   res = libc_ioctl(fd, request, argp);
41901e04c3fSmrg
42001e04c3fSmrg out:
42101e04c3fSmrg   MUTEX_UNLOCK();
42201e04c3fSmrg   return res;
42301e04c3fSmrg}
42401e04c3fSmrg
42501e04c3fSmrgstatic void __attribute__ ((constructor))
42601e04c3fSmrginit(void)
42701e04c3fSmrg{
4289f464c52Smaya   fds_to_bo_sizes = _mesa_pointer_hash_table_create(NULL);
42901e04c3fSmrg   libc_open = dlsym(RTLD_NEXT, "open");
43001e04c3fSmrg   libc_close = dlsym(RTLD_NEXT, "close");
43101e04c3fSmrg   libc_fcntl = dlsym(RTLD_NEXT, "fcntl");
43201e04c3fSmrg   libc_ioctl = dlsym(RTLD_NEXT, "ioctl");
43301e04c3fSmrg}
434