The UAPI references Kconfig's CONFIG_* macros (variables)

From: Michael Witten
Date: Sat May 11 2019 - 00:28:50 EST


The UAPI headers contain references to Kconfig's `CONFIG_'
macros. Either this is a bug, or there needs to be some standard
way for users to provide definitions for these macros, in order
to complete Linux's user-space API. Consider:

#!/bin/sh
cd "${linux_repo}"

# Careful!
#git reset --hard HEAD
#git clean -fdx

git checkout v5.1
#zcat /proc/config.gz >.config

mkdir -p /tmp/uapi/include
make INSTALL_HDR_PATH=/tmp/uapi headers_install

printf >/tmp/uapi/raw.c '%s\n%s\n' \
'#include <linux/raw.h>' \
'int main() { return MAX_RAW_MINORS; }'

Then:

$ gcc -c -I/tmp/uapi/include /tmp/uapi/raw.c
In file included from /tmp/uapi/raw.c:1:0:
/tmp/uapi/raw.c: In function â??mainâ??:
/tmp/uapi/include/linux/raw.h:17:24: error: â??CONFIG_MAX_RAW_DEVSâ?? undeclared (first use in this function)
#define MAX_RAW_MINORS CONFIG_MAX_RAW_DEVS
^
/tmp/uapi/raw.c:2:21: note: in expansion of macro â??MAX_RAW_MINORSâ??
int main() { return MAX_RAW_MINORS; }
^~~~~~~~~~~~~~
/tmp/uapi/include/linux/raw.h:17:24: note: each undeclared identifier is reported only once for each function it appears in
#define MAX_RAW_MINORS CONFIG_MAX_RAW_DEVS
^
/tmp/uapi/raw.c:2:21: note: in expansion of macro â??MAX_RAW_MINORSâ??
int main() { return MAX_RAW_MINORS; }
^~~~~~~~~~~~~~

As you can see, the UAPI is actually incomplete; there is not a
valid definition for `MAX_RAW_MINORS'. Indeed, on my system,
`CONFIG_MAX_RAW_DEVS' isn't ever defined anywhere, because
`CONFIG_RAW_DRIVER' is not set:

$ git show v5.1:drivers/char/Kconfig | sed -n 467,469p
config MAX_RAW_DEVS
int "Maximum number of RAW devices to support (1-65536)"
depends on RAW_DRIVER
$ zcat /proc/config.gz | grep RAW_DRIVER
# CONFIG_RAW_DRIVER is not set

Even if `CONFIG_RAW_DRIVER' were set, the desired definition for
the macro `CONFIG_MAX_RAW_DEVS' would only be found in the
following header (generated at built-time), which is neither
officially nor likely available to user space:

"${linux_repo}"/include/generated/autoconf.h

Other such references to `CONFIG_*' macros are seen in the
following (some appear only in comments, but perhaps that's
conceptually a mistake, too):

$ (cd /tmp/uapi/include && grep -R . -e \\bCONFIG_)
./asm/mman.h:#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
./asm/auxvec.h:#if defined(CONFIG_IA32_EMULATION) || !defined(CONFIG_X86_64)
./asm/e820.h: * kernel was built: MAX_NUMNODES == (1 << CONFIG_NODES_SHIFT),
./asm/e820.h: * unless the CONFIG_X86_PMEM_LEGACY option is set.
./asm/e820.h: * if CONFIG_INTEL_TXT is enabled, memory of this type will be
./mtd/ubi-user.h: * default kernel value of %CONFIG_MTD_UBI_BEB_LIMIT will be used.
./linux/pkt_cls.h: TCA_FW_INDEV, /* used by CONFIG_NET_CLS_IND */
./linux/pkt_cls.h: TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */
./linux/cm4000_cs.h: * member sizes. This leads to CONFIG_COMPAT breakage, since 32bit userspace
./linux/eventpoll.h:#ifdef CONFIG_PM_SLEEP
./linux/hw_breakpoint.h:#ifdef CONFIG_HAVE_MIXED_BREAKPOINTS_REGS
./linux/bpf.h: * has been built with CONFIG_EFFICIENT_UNALIGNED_ACCESS not set,
./linux/bpf.h: * the **CONFIG_CGROUP_NET_CLASSID** configuration option set to
./linux/bpf.h: * **CONFIG_IP_ROUTE_CLASSID** configuration option.
./linux/bpf.h: * with the **CONFIG_BPF_KPROBE_OVERRIDE** configuration
./linux/bpf.h: * the CONFIG_FUNCTION_ERROR_INJECTION option. As of this writing,
./linux/bpf.h: * **CONFIG_XFRM** configuration option.
./linux/bpf.h: * the **CONFIG_BPF_LIRC_MODE2** configuration option set to
./linux/bpf.h: * the **CONFIG_BPF_LIRC_MODE2** configuration option set to
./linux/bpf.h: * **CONFIG_SOCK_CGROUP_DATA** configuration option.
./linux/bpf.h: * **CONFIG_NET** configuration option.
./linux/bpf.h: * **CONFIG_NET** configuration option.
./linux/bpf.h: * the **CONFIG_BPF_LIRC_MODE2** configuration option set to
./linux/raw.h:#define MAX_RAW_MINORS CONFIG_MAX_RAW_DEVS
./linux/pktcdvd.h:#if defined(CONFIG_CDROM_PKTCDVD_WCACHE)
./linux/flat.h:#ifdef CONFIG_BINFMT_SHARED_FLAT
./linux/videodev2.h: * Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
./linux/elfcore.h:#ifdef CONFIG_BINFMT_ELF_FDPIC
./linux/atmdev.h:#ifdef CONFIG_COMPAT
./asm-generic/bitsperlong.h: * both 32 and 64 bit user space must not rely on CONFIG_64BIT
./asm-generic/unistd.h:/* mm/, CONFIG_MMU only */
./asm-generic/mman-common.h:#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED
./asm-generic/fcntl.h:#ifndef CONFIG_64BIT

What is the correct way to think about this?

* Should the UAPI make no reference to build-time configurations?
* Should the UAPI headers include sanity checks on behalf of the user?
* Should there be a `/proc/config.h.gz' facility?

Sincerely,
Michael Witten