llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.89k stars 11.93k forks source link

cfi, cross-dso, wrong operation of `-fno-sanitize-cfi-cross-dso` #47979

Open 44128753-b9b6-4faf-984b-690a6ca556cf opened 3 years ago

44128753-b9b6-4faf-984b-690a6ca556cf commented 3 years ago
Bugzilla Link 48635
Version 11.0
OS Linux
Attachments Reproducible example
CC @P1119r1m

Extended Description

Clang compiler doesn't ignore cross-dso calls for the following conditions:

"Compiler-time" problem rises if one try to execute the function from the shared object (.so) from the other executable binary (main).

Instead, compiler generates binary code with undefined instruction on the place where cross-dso is used, for example:

  int exec_func_from_dso(void)
  {
      fptr_t fptr = get_fptr();
    201751:       e8 5a 00 00 00          callq  2017b0 <get_fptr@plt>
      fptr();
    201756:       0f 0b                   ud2

At the same time, there is no problem with the source code (please, see attached cfi_cross_dso_problem_report.tar).

Clang's help says:

-fno-sanitize-cfi-cross-dso
    Disable control flow integrity (CFI) checks for cross-DSO calls.

As a user of the Clang I understand that if to use -fno-sanitize-cfi-cross-dso, cross-dso places will not be taken into account during CFI operation (compilation and run-time execution).

44128753-b9b6-4faf-984b-690a6ca556cf commented 3 years ago
// shared.h

#pragma once
#define DSO_EXPORT __attribute__ ((visibility ("default")))
typedef int (*fptr_t)(void);
extern const fptr_t get_fptr(void) DSO_EXPORT;
// shared.c

#include "shared.h"

int fun(void)
{
    return 1;
}

const fptr_t get_fptr(void)
{
    return fun;
}
// main.c

#include "shared.h"

int exec_func_from_dso(void)
{
    fptr_t fptr = get_fptr();
    fptr();
}

int main()
{
    return exec_func_from_dso();
}
// Makefile

include .config

SANITIZE_CFI_CROSS_DSO = n

CC := $(PATH_HOST_CLANG_DIR)/bin/clang
LD := $(PATH_HOST_CLANG_DIR)/bin/ld.lld
OBJDUMP := objdump

CFLAGS_SWD += -O2
CFLAGS_SWD += -g

CFLAGS_SWD += -fsanitize=cfi

ifeq ($(SANITIZE_CFI_CROSS_DSO),y)
  CFLAGS_SWD += -fsanitize-cfi-cross-dso
else
  CFLAGS_SWD += -fno-sanitize-cfi-cross-dso
endif

CFLAGS_SWD += -flto
CFLAGS_SWD += -fvisibility=hidden
CFLAGS_SWD += -fsplit-lto-unit
CFLAGS_SWD += -fsanitize-undefined-trap-on-error
CFLAGS_SWD += -fno-sanitize-recover=all

.PHONY: all clean objdump
all: shared.so
    $(CC) main.c $(CFLAGS_SWD) -L. -lshared -fuse-ld=lld -o main

main.o: main.c
    $(CC) $(CFLAGS_SWD) -Wall -c main.c -o main.o

shared.o: shared.c shared.h
    $(CC) $(CFLAGS_SWD) -Wall -c shared.c -o shared.o

shared.so: shared.o
    $(LD) -shared shared.o -o libshared.so

clean:
    rm -f main.o main shared.o libshared.so

objdump:
    $(OBJDUMP) -dS main | less
// .config

PATH_HOST_CLANG_DIR=.../Programs/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-16.04