Re: [PATCH 1/3] exporting capability code/name pairs (try #3)

Serge E. Hallyn
2008-02-04T16:21:19Z

Quoting Kohei KaiGai (kaigai@ak.jp.nec.com):
> >> All that being said, the friendliness factor of this is somewhat
> >> undeniable, and so I can see why folk might want it in the kernel
> >> anyway. If so, would it possible to move this code into
> >> security/capability.c and not in the main kernel per-se - protected with
> >> a configuration option? If it does appear in the kernel, we'll obviously
> >> add your libcap changes too. If it doesn't, then perhaps we can meet
> >> your needs with a slight modification to your libcap patch to read the
> >> capabilities from an optional /etc/XXX file - and make text visibility
> >> of 'late breaking' capabilities something that the admin can tweak as
> >> needed?
> >
> > I think optional configuration file is not a good idea.
> > It can make unneeded confusion.
> >
> > If necessary, I'll move this features into security/capability.c and
> > add a Kconfig option to select it.
>
> The following patch enables to export the list of capabilities supported
> on the running kernel, under /sys/kernel/capability .
>
> Changelog from the previous version:
> - Implementation is moved into security/capability.c from kernel/capability.c
> - A Kconfig option SECURITY_CAPABILITIES_EXPORT is added to tuen on/off this feature.

can you explain one more time exactly what this lets you do that you
absolutely can't do with the current api?

I for one don't really object even if it is "duplicated" since it is far
easier to use, and I frequently have systems where kernel and userspace
are out of sync so /usr/include/sys/capabilities is worthless... Though
I'm a little worried that b/scripts/mkcapnames.sh is the kind of thing
that'll eventually break, but I suppose that's my fault for objecting
two duplicated list of capability definitions :)

-serge

>
> [kaigai@saba ~]$ for x in /sys/kernel/capability/*
> > do
> > echo "$x --> `cat $x`"
> > done
> /sys/kernel/capability/cap_audit_control --> 30
> /sys/kernel/capability/cap_audit_write --> 29
> - snip -
> /sys/kernel/capability/cap_sys_time --> 25
> /sys/kernel/capability/cap_sys_tty_config --> 26
> /sys/kernel/capability/index --> 31
> /sys/kernel/capability/version --> 0x19980330
> [kaigai@saba ~]$
>
> Thanks,
>
> Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
> ----
> scripts/mkcapnames.sh | 50 +++++++++++++++++++++++++++++++++++++++++++++++++
> security/Kconfig | 9 ++++++++
> security/Makefile | 11 ++++++++++
> security/capability.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 119 insertions(+), 0 deletions(-)
>
> diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
> index e69de29..262478e 100644
> --- a/scripts/mkcapnames.sh
> +++ b/scripts/mkcapnames.sh
> @@ -0,0 +1,50 @@
> +#!/bin/sh
> +
> +#
> +# generate a cap_names.h file from include/linux/capability.h
> +#
> +
> +BASEDIR=`dirname $0`
> +
> +echo '#ifndef CAP_NAMES_H'
> +echo '#define CAP_NAMES_H'
> +echo
> +echo '/*'
> +echo ' * Do NOT edit this file directly.'
> +echo ' * This file is generated from include/linux/capability.h automatically'
> +echo ' */'
> +echo
> +echo '#ifndef SYSFS_CAPABILITY_ENTRY'
> +echo '#error cap_names.h should be included from kernel/capability.c'
> +echo '#else'
> +
> +echo 'SYSFS_CAPABILITY_ENTRY(version, "0x%08x\n", _LINUX_CAPABILITY_VERSION);'
> +
> +cat ${BASEDIR}/../include/linux/capability.h \
> + | egrep '^#define CAP_[A-Z_]+[ ]+[0-9]+$' \
> + | awk 'BEGIN {
> + max_code = -1;
> + }
> + {
> + if ($3 > max_code)
> + max_code = $3;
> + printf("SYSFS_CAPABILITY_ENTRY(%s, \"%%u\\n\", %s);\n", tolower($2), $2);
> + }
> + END {
> + printf("SYSFS_CAPABILITY_ENTRY(index, \"%%u\\n\", %u);\n", max_code);
> + }'
> +
> +echo
> +echo 'static struct attribute *capability_attrs[] = {'
> +echo ' &version_attr.attr,'
> +echo ' &index_attr.attr,'
> +
> +cat ${BASEDIR}/../include/linux/capability.h \
> + | egrep '^#define CAP_[A-Z_]+[ ]+[0-9]+$' \
> + | awk '{ printf (" &%s_attr.attr,\n", tolower($2)); }'
> +
> +echo ' NULL,'
> +echo '};'
> +
> +echo '#endif /* SYSFS_CAPABILITY_ENTRY */'
> +echo '#endif /* CAP_NAMES_H */'
> diff --git a/security/Kconfig b/security/Kconfig
> index 8086e61..e4d330c 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -90,6 +90,15 @@ config SECURITY_FILE_CAPABILITIES
>
> If in doubt, answer N.
>
> +config SECURITY_CAPABILITIES_EXPORT
> + bool "Exporting capabilities kernel supported"
> + depends on SECURITY_CAPABILITIES && SYSFS
> + help
> + This enables to export any capabilities which are supported
> + in the running kernel.
> +
> + If you are unsure how to answer this question, answer Y.
> +
> config SECURITY_ROOTPLUG
> bool "Root Plug Support"
> depends on USB=y && SECURITY
> diff --git a/security/Makefile b/security/Makefile
> index ef87df2..90a856d 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -16,3 +16,14 @@ obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
> obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
> obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
> obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
> +
> +ifeq ($(CONFIG_SECURITY_CAPABILITIES_EXPORT),y)
> +# cap_names.h contains the code/name pair of capabilities.
> +# It is generated using include/linux/capability.h automatically.
> +$(obj)/capability.o: $(obj)/cap_names.h
> +quiet_cmd_cap_names = CAPS $@
> + cmd_cap_names = /bin/sh $(src)/../scripts/mkcapnames.sh > $@
> +targets += cap_names.h
> +$(obj)/cap_names.h: $(src)/../scripts/mkcapnames.sh $(src)/../include/linux/capability.h FORCE
> + $(call if_changed,cap_names)
> +endif
> diff --git a/security/capability.c b/security/capability.c
> index 9e99f36..06e0f0a 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -20,6 +20,8 @@
> #include <linux/netlink.h>
> #include <linux/ptrace.h>
> #include <linux/moduleparam.h>
> +#include <linux/kobject.h>
> +#include <linux/sysfs.h>
>
> static struct security_operations capability_ops = {
> .ptrace = cap_ptrace,
> @@ -58,6 +60,53 @@ static int secondary;
> static int capability_disable;
> module_param_named(disable, capability_disable, int, 0);
>
> +#ifdef CONFIG_SECURITY_CAPABILITIES_EXPORT
> +/*
> + * Export the list of capabilities on /sys/kernel/capability
> + */
> +struct capability_attribute {
> + struct attribute attr;
> + ssize_t (*show)(struct kobject *kobj,
> + struct capability_attribute *attr,
> + char *buffer);
> + ssize_t (*store)(struct kobject *kobj,
> + struct capability_attribute *attr,
> + const char *buffer, size_t count);
> +};
> +
> +#define SYSFS_CAPABILITY_ENTRY(_name, _fmt, ...) \
> + static ssize_t _name##_show(struct kobject *kobj, \
> + struct capability_attribute *attr, \
> + char *buffer) \
> + { \
> + return scnprintf(buffer, PAGE_SIZE, _fmt, __VA_ARGS__); \
> + } \
> + static struct capability_attribute _name##_attr = __ATTR_RO(_name)
> +/*
> + * capability_attrs[] is generated automatically by scripts/mkcapnames.sh
> + * This script parses include/linux/capability.h
> + */
> +#include "cap_names.h"
> +
> +static struct attribute_group capability_attr_group = {
> + .name = "capability",
> + .attrs = capability_attrs,
> +};
> +
> +static int __init capability_export_names(void)
> +{
> + int rc;
> +
> + rc = sysfs_create_group(kernel_kobj, &capability_attr_group);
> + if (rc) {
> + printk(KERN_ERR "Unable to export capabilities\n");
> + return rc;
> + }
> + return 0;
> +}
> +__initcall(capability_export_names);
> +#endif
> +
> static int __init capability_init (void)
> {
> if (capability_disable) {
>
> --
> OSS Platform Development Division, NEC
> KaiGai Kohei <kaigai@ak.jp.nec.com>