2008-01-25 05:19:48

by Kohei KaiGai

[permalink] [raw]
Subject: [PATCH 1/3] exporting capability code/name pairs (try 2nd)

We can apply this patch to kernel-2.6.24.
It enables to export code/name pairs of capabilities
at /sys/kernel/capability/, as follows:

--------
[root@saba ~]# ls /sys/kernel/capability/
cap_audit_control cap_kill cap_setgid cap_sys_ptrace
cap_audit_write cap_lease cap_setpcap cap_sys_rawio
cap_chown cap_linux_immutable cap_setuid cap_sys_resource
cap_dac_override cap_mknod cap_sys_admin cap_sys_time
cap_dac_read_search cap_net_admin cap_sys_boot cap_sys_tty_config
cap_fowner cap_net_bind_service cap_sys_chroot index
cap_fsetid cap_net_broadcast cap_sys_module version
cap_ipc_lock cap_net_raw cap_sys_nice
cap_ipc_owner cap_setfcap cap_sys_pacct
[root@saba ~]# cat /sys/kernel/capability/cap_setfcap
31
[root@saba ~]# cat /sys/kernel/capability/version
0x19980330
[root@saba ~]#
--------

In the previous version of kernel, we have no way to obtain
what capabilities are supported in this running kernel.

The libcap is a library to provide fundamental facilities
to handle capabilities. It has to be rebuilt when new
capabilities are added, because it statically holds the
list of all capabilities generated from kernel header
automatically on its build environment.

This patch enables libcap to obtain these infomation dynamically,
and improves userspace portability.

Please consider to apply these patches.
Thanks,
----
Signed-off-by: KaiGai Kohei <[email protected]>

kernel/Makefile | 9 ++++++++
kernel/capability.c | 36 +++++++++++++++++++++++++++++++++++
scripts/mkcapnames.sh | 50 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 95 insertions(+), 0 deletions(-)

diff --git a/kernel/Makefile b/kernel/Makefile
index dfa9695..29cd3ac 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -80,3 +80,12 @@ quiet_cmd_ikconfiggz = IKCFG $@
targets += config_data.h
$(obj)/config_data.h: $(obj)/config_data.gz FORCE
$(call if_changed,ikconfiggz)
+
+# 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)
diff --git a/kernel/capability.c b/kernel/capability.c
index efbd9cd..14b4f4b 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -245,3 +245,39 @@ int capable(int cap)
return __capable(current, cap);
}
EXPORT_SYMBOL(capable);
+
+/*
+ * Export the list of capabilities on /sys/kernel/capability
+ */
+#define SYSFS_CAPABILITY_ENTRY(_name, _fmt, ...) \
+ static ssize_t _name##_show(struct kset *kset, char *buffer) \
+ { \
+ return scnprintf(buffer, PAGE_SIZE, _fmt, __VA_ARGS__); \
+ } \
+ static struct subsys_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_subsys.kobj,
+ &capability_attr_group);
+ if (rc) {
+ printk(KERN_ERR "Unable to export capabilities\n");
+ return rc;
+ }
+
+ return 0;
+}
+__initcall(capability_export_names);
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 */'


--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>


2008-01-25 07:46:52

by Andrew G. Morgan

[permalink] [raw]
Subject: Re: [PATCH 1/3] exporting capability code/name pairs (try 2nd)

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

KaiGai,

While this is cute :-), I guess I'm still not all that convinced that
this is needed.

libcap already had some (admittedly not quite working) support for
numeric values of capabilities not currently defined (which I believe is
now fixed in top of trunk):

# ./setcap 35=i ./setcap
# ./getcap ./setcap
./setcap = 35+i

Although, I obviously can't argue that this is as readable as your
approach, it does seem unlikely that the rate of addition of new
capabilities will be all that great, and you can recompile everything
capability related in user-space on a live system without a reboot.
Further, if anyone ever wants to translate the capabilities into another
language, it seems like user-space is a much better place for that than
in the kernel.

This patch also requires that /sys be mounted. How does that work for
code operating early in the boot process or in a chroot environment
(where an incapable uid=0 account being able to read/write /sys & /proc
files can do more than a little damage)?

None of this touches on the fact that most utility applications that
will support capabilities "the right way"(TM), will need the #define's
at compile time for each of the capabilities they require (so they can
pepper critical regions with cap_set_flag()/cap_set_proc() code.

When I mentioned this last time, you said you felt this feature was more
aimed at admin applications like {get,set,pam_}cap. This is fine, but
none of these admin applications 'use' capabilities, they just make them
available/visible for other utility applications to use - which gets us
back to my point; the utility apps can't use them (properly) without
having compiled-in support to use them appropriately, which requires the
#define's at compile time or an appropriate vintage of sys/capability.h
which comes with an appropriately modern version of libcap. So,
practically speaking all the capabilities the applications on a system
should need should be present in the libcap on the system.

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?

Cheers

Andrew

Kohei KaiGai wrote:
| We can apply this patch to kernel-2.6.24.
| It enables to export code/name pairs of capabilities
| at /sys/kernel/capability/, as follows:
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)

iD8DBQFHmZCh+bHCR3gb8jsRArf8AJ0QK/c54cvOp7Uo3FksZL1OHM3SEQCfdQ02
kOkmExkYjcpdF4xs0hcgrTI=
=rZNg
-----END PGP SIGNATURE-----

2008-01-25 11:43:57

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH 1/3] exporting capability code/name pairs (try 2nd)

Andrew,

Thanks for your comments.

Andrew G. Morgan wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> KaiGai,
>
> While this is cute :-), I guess I'm still not all that convinced that
> this is needed.
>
> libcap already had some (admittedly not quite working) support for
> numeric values of capabilities not currently defined (which I believe is
> now fixed in top of trunk):
>
> # ./setcap 35=i ./setcap
> # ./getcap ./setcap
> ./setcap = 35+i
>
> Although, I obviously can't argue that this is as readable as your
> approach, it does seem unlikely that the rate of addition of new
> capabilities will be all that great, and you can recompile everything
> capability related in user-space on a live system without a reboot.

cap_set_flag() and cap_from_text() checks whether required capability
code is in between 0 and __CAP_BITS, or not.
I don't think it works correctly. Is it necessary to obtain this bound
dynamically?

> Further, if anyone ever wants to translate the capabilities into another
> language, it seems like user-space is a much better place for that than
> in the kernel.

Are you intend to translate "cap_net_admin" into native language
representation, for example?
I want to see how Chinese represents it :), but I think it is different
issue with kernel dose not expose its suporing capabilities.

> This patch also requires that /sys be mounted. How does that work for
> code operating early in the boot process or in a chroot environment
> (where an incapable uid=0 account being able to read/write /sys & /proc
> files can do more than a little damage)?

When this patch cannot access /sys, it does not provide dynamically
collected code/name pairs, and it works with statically constructed
table as current libcap doing.

The patched libcap never switch to the dynamic table without successes
in all steps of initialization. Thus, there is no major regression on
this facilitiy.

> None of this touches on the fact that most utility applications that
> will support capabilities "the right way"(TM), will need the #define's
> at compile time for each of the capabilities they require (so they can
> pepper critical regions with cap_set_flag()/cap_set_proc() code.
>
> When I mentioned this last time, you said you felt this feature was more
> aimed at admin applications like {get,set,pam_}cap. This is fine, but
> none of these admin applications 'use' capabilities, they just make them
> available/visible for other utility applications to use - which gets us
> back to my point; the utility apps can't use them (properly) without
> having compiled-in support to use them appropriately, which requires the
> #define's at compile time or an appropriate vintage of sys/capability.h
> which comes with an appropriately modern version of libcap. So,
> practically speaking all the capabilities the applications on a system
> should need should be present in the libcap on the system.

Hmm, you are correct. Indeed, applications using capabilities have to
be built with the new libcap which provides fresh sys/capabilitity.h.
It is like a chicken and egg argument.

However, all applications are always built on its running environment,
like RPM packages. These can be delivered as pre-built packages.

> 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.

Thanks,
--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-01 05:18:47

by Kohei KaiGai

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

>> 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.

[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 <[email protected]>
----
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 <[email protected]>

2008-02-04 16:21:19

by Serge E. Hallyn

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

Quoting Kohei KaiGai ([email protected]):
> >> 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 <[email protected]>
> ----
> 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 <[email protected]>

2008-02-06 02:28:24

by Kohei KaiGai

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

Serge E. Hallyn wrote:
> Quoting Kohei KaiGai ([email protected]):
>>>> 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?

Please consider the following situation:

A user intend to run an application which use a new capability supported
at new kernel without synced libcap. In this case, the application cannot
work well, because libcap prevent to use new capability.

When the kernel and libcap are not synced, the header files provided by
libcap pacakge is not reliable. Typically, kernel developer sometimes
faces such a situation. :)

This feature can fill the gap with providing a new interface to collect
capabilities supported by the running kernel collectly.

> 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 :)

Are you worried about "mkcapnames.sh" get broken in the future version?

If so, we can add a code to check whether this script works correctly, or not

like:
-- at security/capability.c
#include <linux/capability.h>
:
#if CAP_LAST_CAP != ARRAY_SIZE(capability_attrs)
#error "mkcapnames.sh added fewer or more entries than expected!"
#endif

Thanks,

> -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 <[email protected]>
>> ----
>> 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 <[email protected]>
>
>


--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-06 05:08:23

by Serge E. Hallyn

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

Quoting Kohei KaiGai ([email protected]):
> Serge E. Hallyn wrote:
>> Quoting Kohei KaiGai ([email protected]):
>>>>> 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?
>
> Please consider the following situation:
>
> A user intend to run an application which use a new capability supported
> at new kernel without synced libcap. In this case, the application cannot
> work well, because libcap prevent to use new capability.

(Though we don't want to encourage application writers to not use
libcap...)

> When the kernel and libcap are not synced, the header files provided by
> libcap pacakge is not reliable. Typically, kernel developer sometimes
> faces such a situation. :)

Yeah it would definately be nice for me.

> This feature can fill the gap with providing a new interface to collect
> capabilities supported by the running kernel collectly.
>
>> 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 :)
>
> Are you worried about "mkcapnames.sh" get broken in the future version?
>
> If so, we can add a code to check whether this script works correctly, or
> not
>
> like:
> -- at security/capability.c
> #include <linux/capability.h>
> :
> #if CAP_LAST_CAP != ARRAY_SIZE(capability_attrs)
> #error "mkcapnames.sh added fewer or more entries than expected!"
> #endif

Yeah, the regexp misfiring was my biggest concern so this should help.

thanks,
-serge

2008-02-08 09:44:47

by Kohei KaiGai

[permalink] [raw]
Subject: [PATCH] exporting capability code/name pairs (try #4)

This patch enables to export code/name pair of capabilities supported
on the running kernel, under the /sys/kernel/capability .
We can apply it onto the latest Linus's git tree.

Changes from the previous version:
- I added "names/" ans "codes/" directories, and we can use them
to lookup capability code or name non-sequentially.
In the previous version, we had to scan whole of entries to lookup
capability name by its code.
(required by Andrew Morgan)
- I added an assertion when "mkcapname.sh" works incorrectly.
(required by Serge E.Hallyn)

In addition, Andrew suggested me to export these translation by symlinks
to reduce the number of invocation of system call.
However, current sysfs interface does not allows to create symlinks with
invalid indication.
Thus, this patch exports them as regular files.

--------------------------------------------------------
[kaigai@saba ~]$ ls -R /sys/kernel/capability/
/sys/kernel/capability/:
codes names version

/sys/kernel/capability/codes:
0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9

/sys/kernel/capability/names:
cap_audit_control cap_kill cap_net_raw cap_sys_nice
cap_audit_write cap_lease cap_setfcap cap_sys_pacct
cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
cap_fowner cap_mknod cap_sys_admin cap_sys_time
cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
cap_ipc_lock cap_net_bind_service cap_sys_chroot
cap_ipc_owner cap_net_broadcast cap_sys_module
[kaigai@saba ~]$ cat /sys/kernel/capability/codes/20
cap_sys_pacct
[kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_mknod
27
[kaigai@saba ~]$
--------------------------------------------------------
Any comment please.

Thanks,

Signed-off-by: KaiGai Kohei <[email protected]>
----
scripts/mkcapnames.sh | 44 +++++++++++++++++++
security/Kconfig | 9 ++++
security/Makefile | 11 +++++
security/capability.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 179 insertions(+), 0 deletions(-)

diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
index e69de29..9e7290f 100644
--- a/scripts/mkcapnames.sh
+++ b/scripts/mkcapnames.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+#
+# generate a cap_names.h file from include/linux/capability.h
+#
+
+CAPHEAD="`dirname $0`/../include/linux/capability.h"
+REGEXP='^#define CAP_[A-Z_]+[ ]+[0-9]+$'
+NUMCAP=`cat "$CAPHEAD" | egrep -c "$REGEXP"`
+
+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 '#if !defined(SYSFS_CAP_NAME_ENTRY) || !defined(SYSFS_CAP_CODE_ENTRY)'
+echo '#error cap_names.h should be included from security/capability.c'
+echo '#else'
+echo "#if $NUMCAP != CAP_LAST_CAP + 1"
+echo '#error mkcapnames.sh cannot collect capabilities correctly'
+echo '#else'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_NAME_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_name_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_name_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_CODE_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_code_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_code_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo '#endif'
+echo '#endif'
+echo '#endif'
diff --git a/security/Kconfig b/security/Kconfig
index 25ffe1b..b79e830 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -91,6 +91,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 9e8b025..0e80903 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -18,3 +18,14 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/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
\ No newline at end of file
diff --git a/security/capability.c b/security/capability.c
index 9e99f36..ca30a17 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,119 @@ 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
+ */
+static struct kobject *capability_kobj;
+
+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);
+ union {
+ int code;
+ char *name;
+ } c;
+};
+
+static ssize_t capability_name_show(struct kobject *kobj,
+ struct capability_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "%d\n", attr->c.code);
+}
+
+static ssize_t capability_code_show(struct kobject *kobj,
+ struct capability_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "%s\n", attr->c.name);
+}
+
+static ssize_t capability_version_show(struct kobject *kobj,
+ struct capability_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "0x%08x\n",
+ _LINUX_CAPABILITY_VERSION);
+}
+
+#define SYSFS_CAP_NAME_ENTRY(_name,_code) \
+ static struct capability_attribute _name##_name_attr = { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .show = capability_name_show, \
+ .c.code = (_code), \
+ }
+
+#define SYSFS_CAP_CODE_ENTRY(_name,_code) \
+ static struct capability_attribute _name##_code_attr = { \
+ .attr = { .name = __stringify(_code), .mode = 0444 }, \
+ .show = capability_code_show, \
+ .c.name = __stringify(_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_name_attr_group = {
+ .name = "names",
+ .attrs = capability_name_attrs,
+};
+
+static struct attribute_group capability_code_attr_group = {
+ .name = "codes",
+ .attrs = capability_code_attrs,
+};
+
+static struct capability_attribute cap_version_attr = {
+ .attr = { .name = "version", .mode = 0444 },
+ .show = capability_version_show,
+};
+
+static int __init capability_export_names(void)
+{
+ /* make /sys/kernel/capability */
+ capability_kobj = kobject_create_and_add("capability", kernel_kobj);
+ if (!capability_kobj)
+ goto error0;
+
+ /* make /sys/kernel/capability/names */
+ if (sysfs_create_group(capability_kobj,
+ &capability_name_attr_group))
+ goto error1;
+
+ /* make /sys/kernel/capability/codes */
+ if (sysfs_create_group(capability_kobj,
+ &capability_code_attr_group))
+ goto error2;
+
+ if (sysfs_create_file(capability_kobj,
+ &cap_version_attr.attr))
+ goto error3;
+
+ return 0;
+
+error3:
+ sysfs_remove_group(capability_kobj, &capability_code_attr_group);
+error2:
+ sysfs_remove_group(capability_kobj, &capability_name_attr_group);
+error1:
+ kobject_put(capability_kobj);
+error0:
+ printk(KERN_ERR "Unable to export capabilities\n");
+
+ return 0;
+}
+__initcall(capability_export_names);
+#endif
+
static int __init capability_init (void)
{
if (capability_disable) {

--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-08 16:49:14

by Andrew G. Morgan

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #4)

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

KaiGai,

Thanks for trying to accommodate me :-)

Kohei KaiGai wrote:
| In addition, Andrew suggested me to export these translation by symlinks
| to reduce the number of invocation of system call.

Yes, I wanted to make use of readlink() instead of open()/read()/close()
to access each unknown capability.

| However, current sysfs interface does not allows to create symlinks with
| invalid indication.

:-(

| Thus, this patch exports them as regular files.

What about using symlinks for the name files and text content for the
numeric ones? You could even drop the names/ and codes/ subdirectories too:

$ cat /sys/kernel/capability/20
cap_sys_pacct
$ ls -l /sys/kernel/capability/cap_mknod
lr--r--r-- 1 root root 64 Feb 8 08:26 cap_mknod -> 27
$ cat /sys/kernel/capability/names/cap_mknod
cap_mknod

Cheers

Andrew
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)

iD8DBQFHrIfh+bHCR3gb8jsRAkueAKDYMu+so+YCJD9klNentiWlwZJXlQCgrzSa
tWr1XM1nKcvST1ScAfO27j4=
=w5N/
-----END PGP SIGNATURE-----

2008-02-08 19:24:33

by Alexey Dobriyan

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #4)

On Fri, Feb 08, 2008 at 06:42:09PM +0900, Kohei KaiGai wrote:
> [kaigai@saba ~]$ ls -R /sys/kernel/capability/
> /sys/kernel/capability/:
> codes names version
>
> /sys/kernel/capability/codes:
> 0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
> 1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9
>
> /sys/kernel/capability/names:
> cap_audit_control cap_kill cap_net_raw cap_sys_nice
> cap_audit_write cap_lease cap_setfcap cap_sys_pacct
> cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
> cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
> cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
> cap_fowner cap_mknod cap_sys_admin cap_sys_time
> cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
> cap_ipc_lock cap_net_bind_service cap_sys_chroot
> cap_ipc_owner cap_net_broadcast cap_sys_module
> [kaigai@saba ~]$ cat /sys/kernel/capability/codes/20
> cap_sys_pacct
> [kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_mknod
> 27
> [kaigai@saba ~]$
> --------------------------------------------------------
> Any comment please.

You don't like 1 (one) /proc/capabilities, why?

2008-02-12 01:01:20

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #4)

Andrew G. Morgan wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> KaiGai,
>
> Thanks for trying to accommodate me :-)
>
> Kohei KaiGai wrote:
> | In addition, Andrew suggested me to export these translation by symlinks
> | to reduce the number of invocation of system call.
>
> Yes, I wanted to make use of readlink() instead of open()/read()/close()
> to access each unknown capability.
>
> | However, current sysfs interface does not allows to create symlinks with
> | invalid indication.
>
> :-(
>
> | Thus, this patch exports them as regular files.
>
> What about using symlinks for the name files and text content for the
> numeric ones? You could even drop the names/ and codes/ subdirectories too:
>
> $ cat /sys/kernel/capability/20
> cap_sys_pacct
> $ ls -l /sys/kernel/capability/cap_mknod
> lr--r--r-- 1 root root 64 Feb 8 08:26 cap_mknod -> 27
> $ cat /sys/kernel/capability/names/cap_mknod
> cap_mknod

Sysfs does not support to create symbolic links to regular files now.

The sysfs_create_link() is a function to create a symbolic link on sysfs.
However, it requires two kobjects as its arguments. One is to specify its
parent directory, the other is to specify the target of indirection.
It means the indicated target have to be a directory.

At include/linux/sysfs.h:
int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target,
const char *name);

Please tell me, if I have any misunderstandings.

Thanks,
--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-12 01:14:32

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #4)

Alexey Dobriyan wrote:
> On Fri, Feb 08, 2008 at 06:42:09PM +0900, Kohei KaiGai wrote:
>> [kaigai@saba ~]$ ls -R /sys/kernel/capability/
>> /sys/kernel/capability/:
>> codes names version
>>
>> /sys/kernel/capability/codes:
>> 0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
>> 1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9
>>
>> /sys/kernel/capability/names:
>> cap_audit_control cap_kill cap_net_raw cap_sys_nice
>> cap_audit_write cap_lease cap_setfcap cap_sys_pacct
>> cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
>> cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
>> cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
>> cap_fowner cap_mknod cap_sys_admin cap_sys_time
>> cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
>> cap_ipc_lock cap_net_bind_service cap_sys_chroot
>> cap_ipc_owner cap_net_broadcast cap_sys_module
>> [kaigai@saba ~]$ cat /sys/kernel/capability/codes/20
>> cap_sys_pacct
>> [kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_mknod
>> 27
>> [kaigai@saba ~]$
>> --------------------------------------------------------
>> Any comment please.
>
> You don't like 1 (one) /proc/capabilities, why?

I have no preference whether a single /proc/capabilities, or the current approach.
However, this idea requires a bit more cost to lookup a capability not sequencially.

Thank,
--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-12 18:09:25

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #4)

Quoting Kohei KaiGai ([email protected]):
> This patch enables to export code/name pair of capabilities supported
> on the running kernel, under the /sys/kernel/capability .
> We can apply it onto the latest Linus's git tree.
>
> Changes from the previous version:
> - I added "names/" ans "codes/" directories, and we can use them
> to lookup capability code or name non-sequentially.
> In the previous version, we had to scan whole of entries to lookup
> capability name by its code.
> (required by Andrew Morgan)
> - I added an assertion when "mkcapname.sh" works incorrectly.
> (required by Serge E.Hallyn)
>
> In addition, Andrew suggested me to export these translation by symlinks
> to reduce the number of invocation of system call.
> However, current sysfs interface does not allows to create symlinks with
> invalid indication.
> Thus, this patch exports them as regular files.
>
> --------------------------------------------------------
> [kaigai@saba ~]$ ls -R /sys/kernel/capability/
> /sys/kernel/capability/:
> codes names version
>
> /sys/kernel/capability/codes:
> 0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
> 1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9
>
> /sys/kernel/capability/names:
> cap_audit_control cap_kill cap_net_raw cap_sys_nice
> cap_audit_write cap_lease cap_setfcap cap_sys_pacct
> cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
> cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
> cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
> cap_fowner cap_mknod cap_sys_admin cap_sys_time
> cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
> cap_ipc_lock cap_net_bind_service cap_sys_chroot
> cap_ipc_owner cap_net_broadcast cap_sys_module
> [kaigai@saba ~]$ cat /sys/kernel/capability/codes/20
> cap_sys_pacct
> [kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_mknod
> 27
> [kaigai@saba ~]$
> --------------------------------------------------------
> Any comment please.
>
> Thanks,
>
> Signed-off-by: KaiGai Kohei <[email protected]>
> ----
> scripts/mkcapnames.sh | 44 +++++++++++++++++++
> security/Kconfig | 9 ++++
> security/Makefile | 11 +++++
> security/capability.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 179 insertions(+), 0 deletions(-)
>
> diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
> index e69de29..9e7290f 100644
> --- a/scripts/mkcapnames.sh
> +++ b/scripts/mkcapnames.sh
> @@ -0,0 +1,44 @@
> +#!/bin/sh
> +
> +#
> +# generate a cap_names.h file from include/linux/capability.h
> +#
> +
> +CAPHEAD="`dirname $0`/../include/linux/capability.h"
> +REGEXP='^#define CAP_[A-Z_]+[ ]+[0-9]+$'
> +NUMCAP=`cat "$CAPHEAD" | egrep -c "$REGEXP"`
> +
> +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 '#if !defined(SYSFS_CAP_NAME_ENTRY) || !defined(SYSFS_CAP_CODE_ENTRY)'
> +echo '#error cap_names.h should be included from security/capability.c'
> +echo '#else'
> +echo "#if $NUMCAP != CAP_LAST_CAP + 1"
> +echo '#error mkcapnames.sh cannot collect capabilities correctly'
> +echo '#else'
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("SYSFS_CAP_NAME_ENTRY(%s,%s);\n", tolower($2), $2); }'
> +echo
> +echo 'static struct attribute *capability_name_attrs[] = {'
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("\t&%s_name_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
> +echo '};'
> +
> +echo
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("SYSFS_CAP_CODE_ENTRY(%s,%s);\n", tolower($2), $2); }'
> +echo
> +echo 'static struct attribute *capability_code_attrs[] = {'
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("\t&%s_code_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
> +echo '};'
> +
> +echo '#endif'
> +echo '#endif'
> +echo '#endif'
> diff --git a/security/Kconfig b/security/Kconfig
> index 25ffe1b..b79e830 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -91,6 +91,15 @@ config SECURITY_FILE_CAPABILITIES
>
> If in doubt, answer N.
>
> +config SECURITY_CAPABILITIES_EXPORT
> + bool "Exporting capabilities kernel supported"
> + depends on SECURITY_CAPABILITIES && SYSFS

Oh no, we're being bit by this again... When SECURITY=n, capabilities
are compiled in but SECURITY_CAPABILITIES=n.

Months ago I floated the following patch so we'd have a CONFIG variable
to let us know whether commoncap is compiled in. You might want to use
this and depend on CONFIG_COMMONCAP? (Though really I personally don't
think you need your own config variable for this)

Other than that, this tested fine for me.

thanks,
-serge

>From 54c70ca7671750fe8986451fae91d42107d0ca90 Mon Sep 17 00:00:00 2001
From: Serge E. Hallyn <[email protected]>
Date: Fri, 28 Sep 2007 10:33:33 -0500
Subject: [PATCH 1/2] capabilities: define CONFIG_COMMONCAP

currently the compilation of commoncap.c is determined
through Makefile logic. So there is no single CONFIG
variable which can be relied upon to know whether it
will be compiled.

Define CONFIG_COMMONCAP to be true when lsm is not
compiled in, or when the capability or rootplug modules
are compiled. These are the cases when commoncap is
currently compiled. Use this variable in security/Makefile
to determine commoncap.c's compilation.

Apart from being a logic cleanup, this is needed by the
upcoming cap_bset patch so that prctl can know whether
PR_SET_BSET should be allowed.

Signed-off-by: Serge E. Hallyn <[email protected]>
---
security/Kconfig | 4 ++++
security/Makefile | 9 +++------
2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/security/Kconfig b/security/Kconfig
index 8086e61..02b33fa 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -103,6 +103,10 @@ config SECURITY_ROOTPLUG

If you are unsure how to answer this question, answer N.

+config COMMONCAP
+ bool
+ default !SECURITY || SECURITY_CAPABILITIES || SECURITY_ROOTPLUG
+
source security/selinux/Kconfig

endmenu
diff --git a/security/Makefile b/security/Makefile
index ef87df2..7cccc81 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -5,14 +5,11 @@
obj-$(CONFIG_KEYS) += keys/
subdir-$(CONFIG_SECURITY_SELINUX) += selinux

-# if we don't select a security model, use the default capabilities
-ifneq ($(CONFIG_SECURITY),y)
-obj-y += commoncap.o
-endif
+obj-$(CONFIG_COMMONCAP) += commoncap.o

# Object file lists
obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
# Must precede capability.o in order to stack properly.
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
+obj-$(CONFIG_SECURITY_CAPABILITIES) += capability.o
+obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o
--
1.5.1.1.GIT

2008-02-12 21:58:45

by Alexey Dobriyan

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #4)

On Tue, Feb 12, 2008 at 10:10:06AM +0900, Kohei KaiGai wrote:
> Alexey Dobriyan wrote:
> >On Fri, Feb 08, 2008 at 06:42:09PM +0900, Kohei KaiGai wrote:
> >>[kaigai@saba ~]$ ls -R /sys/kernel/capability/
> >>/sys/kernel/capability/:
> >>codes names version
> >>
> >>/sys/kernel/capability/codes:
> >>0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
> >>1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9
> >>
> >>/sys/kernel/capability/names:
> >>cap_audit_control cap_kill cap_net_raw cap_sys_nice
> >>cap_audit_write cap_lease cap_setfcap cap_sys_pacct
> >>cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
> >>cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
> >>cap_dac_read_search cap_mac_override cap_setuid
> >>cap_sys_resource
> >>cap_fowner cap_mknod cap_sys_admin cap_sys_time
> >>cap_fsetid cap_net_admin cap_sys_boot
> >>cap_sys_tty_config
> >>cap_ipc_lock cap_net_bind_service cap_sys_chroot
> >>cap_ipc_owner cap_net_broadcast cap_sys_module
> >>[kaigai@saba ~]$ cat /sys/kernel/capability/codes/20
> >>cap_sys_pacct
> >>[kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_mknod
> >>27
> >>[kaigai@saba ~]$
> >>--------------------------------------------------------
> >>Any comment please.
> >
> >You don't like 1 (one) /proc/capabilities, why?
>
> I have no preference whether a single /proc/capabilities, or the current
> approach.
> However, this idea requires a bit more cost to lookup a capability not
> sequencially.

And I'm sure far less memory wasted at runtime.

Also, adding config option for one file/directory seems ridiculous to
me. And changelog completely fails to mention why it is useful to lookup
capabilities by name and number -- CAP_SYS_* numbers are part of ABI,
they won't change.

2008-02-13 08:08:50

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #4)

Serge E. Hallyn wrote:
> Quoting Kohei KaiGai ([email protected]):
>> diff --git a/security/Kconfig b/security/Kconfig
>> index 25ffe1b..b79e830 100644
>> --- a/security/Kconfig
>> +++ b/security/Kconfig
>> @@ -91,6 +91,15 @@ config SECURITY_FILE_CAPABILITIES
>>
>> If in doubt, answer N.
>>
>> +config SECURITY_CAPABILITIES_EXPORT
>> + bool "Exporting capabilities kernel supported"
>> + depends on SECURITY_CAPABILITIES && SYSFS
>
> Oh no, we're being bit by this again... When SECURITY=n, capabilities
> are compiled in but SECURITY_CAPABILITIES=n.
>
> Months ago I floated the following patch so we'd have a CONFIG variable
> to let us know whether commoncap is compiled in. You might want to use
> this and depend on CONFIG_COMMONCAP? (Though really I personally don't
> think you need your own config variable for this)

I also think its own config variable is not necessary to turn on/off
exporting the list of capabilities in actually.
Do you want this feture to be moved into security/commoncap.c and
enabled unconditionally? I can agree this suggestion.

Is there any complaint for this idea?

Thanks,

> Other than that, this tested fine for me.
>
> thanks,
> -serge
>
>>From 54c70ca7671750fe8986451fae91d42107d0ca90 Mon Sep 17 00:00:00 2001
> From: Serge E. Hallyn <[email protected]>
> Date: Fri, 28 Sep 2007 10:33:33 -0500
> Subject: [PATCH 1/2] capabilities: define CONFIG_COMMONCAP
>
> currently the compilation of commoncap.c is determined
> through Makefile logic. So there is no single CONFIG
> variable which can be relied upon to know whether it
> will be compiled.
>
> Define CONFIG_COMMONCAP to be true when lsm is not
> compiled in, or when the capability or rootplug modules
> are compiled. These are the cases when commoncap is
> currently compiled. Use this variable in security/Makefile
> to determine commoncap.c's compilation.
>
> Apart from being a logic cleanup, this is needed by the
> upcoming cap_bset patch so that prctl can know whether
> PR_SET_BSET should be allowed.
>
> Signed-off-by: Serge E. Hallyn <[email protected]>
> ---
> security/Kconfig | 4 ++++
> security/Makefile | 9 +++------
> 2 files changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/security/Kconfig b/security/Kconfig
> index 8086e61..02b33fa 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -103,6 +103,10 @@ config SECURITY_ROOTPLUG
>
> If you are unsure how to answer this question, answer N.
>
> +config COMMONCAP
> + bool
> + default !SECURITY || SECURITY_CAPABILITIES || SECURITY_ROOTPLUG
> +
> source security/selinux/Kconfig
>
> endmenu
> diff --git a/security/Makefile b/security/Makefile
> index ef87df2..7cccc81 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -5,14 +5,11 @@
> obj-$(CONFIG_KEYS) += keys/
> subdir-$(CONFIG_SECURITY_SELINUX) += selinux
>
> -# if we don't select a security model, use the default capabilities
> -ifneq ($(CONFIG_SECURITY),y)
> -obj-y += commoncap.o
> -endif
> +obj-$(CONFIG_COMMONCAP) += commoncap.o
>
> # Object file lists
> obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
> # Must precede capability.o in order to stack properly.
> 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
> +obj-$(CONFIG_SECURITY_CAPABILITIES) += capability.o
> +obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o


--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-13 08:16:45

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #4)

Alexey Dobriyan wrote:
> On Tue, Feb 12, 2008 at 10:10:06AM +0900, Kohei KaiGai wrote:
>> Alexey Dobriyan wrote:
>>> On Fri, Feb 08, 2008 at 06:42:09PM +0900, Kohei KaiGai wrote:
>>>> [kaigai@saba ~]$ ls -R /sys/kernel/capability/
>>>> /sys/kernel/capability/:
>>>> codes names version
>>>>
>>>> /sys/kernel/capability/codes:
>>>> 0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
>>>> 1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9
>>>>
>>>> /sys/kernel/capability/names:
>>>> cap_audit_control cap_kill cap_net_raw cap_sys_nice
>>>> cap_audit_write cap_lease cap_setfcap cap_sys_pacct
>>>> cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
>>>> cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
>>>> cap_dac_read_search cap_mac_override cap_setuid
>>>> cap_sys_resource
>>>> cap_fowner cap_mknod cap_sys_admin cap_sys_time
>>>> cap_fsetid cap_net_admin cap_sys_boot
>>>> cap_sys_tty_config
>>>> cap_ipc_lock cap_net_bind_service cap_sys_chroot
>>>> cap_ipc_owner cap_net_broadcast cap_sys_module
>>>> [kaigai@saba ~]$ cat /sys/kernel/capability/codes/20
>>>> cap_sys_pacct
>>>> [kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_mknod
>>>> 27
>>>> [kaigai@saba ~]$
>>>> --------------------------------------------------------
>>>> Any comment please.
>>> You don't like 1 (one) /proc/capabilities, why?
>> I have no preference whether a single /proc/capabilities, or the current
>> approach.
>> However, this idea requires a bit more cost to lookup a capability not
>> sequencially.
>
> And I'm sure far less memory wasted at runtime.
>
> Also, adding config option for one file/directory seems ridiculous to
> me. And changelog completely fails to mention why it is useful to lookup
> capabilities by name and number -- CAP_SYS_* numbers are part of ABI,
> they won't change.

The codes of capabilities are not removed/modified, but a new one
may be added. In actually, two capabilities will be added at 2.6.25.
If we don't have dynamic interface to obtain the list of capabilities,
libcap built on older kernel cannot work enough on the latest one.

I'll add a description to make clear its purpose in the next patch.
Please wait for a while.

Thanks,
--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-15 01:41:04

by Kohei KaiGai

[permalink] [raw]
Subject: [PATCH] exporting capability code/name pairs (try #5)

This patch enables to export code/name of capabilities supported
on the running kernel.

A newer kernel sometimes adds new capabilities, like CAP_MAC_ADMIN
at 2.6.25. However, we have no interface to disclose what capabilities
are supported on this kernel. Thus, we have to maintain libcap version
in appropriate one synchronously.

This patch enables libcap to collect the list of capabilities on
run time, and provide them for users.
It helps to improve portability of library.

It exports these information as regular files under /sys/kernel/capability.
The numeric node exports its name, the symbolic node exports its code.

Please consider to put this patch on the queue of 2.6.25.

Thanks,
===================================================
[kaigai@saba ~]$ ls -R /sys/kernel/capability/
/sys/kernel/capability/:
codes names version

/sys/kernel/capability/codes:
0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9

/sys/kernel/capability/names:
cap_audit_control cap_kill cap_net_raw cap_sys_nice
cap_audit_write cap_lease cap_setfcap cap_sys_pacct
cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
cap_fowner cap_mknod cap_sys_admin cap_sys_time
cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
cap_ipc_lock cap_net_bind_service cap_sys_chroot
cap_ipc_owner cap_net_broadcast cap_sys_module
[kaigai@saba ~]$ cat /sys/kernel/capability/version
0x20071026
[kaigai@saba ~]$ cat /sys/kernel/capability/codes/30
cap_audit_control
[kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_sys_pacct
20
[kaigai@saba ~]$
===================================================

Signed-off-by: KaiGai Kohei <[email protected]>
--
scripts/mkcapnames.sh | 44 +++++++++++++++++++
security/Makefile | 9 ++++
security/commoncap.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 165 insertions(+), 0 deletions(-)

diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
index e69de29..5d36d52 100644
--- a/scripts/mkcapnames.sh
+++ b/scripts/mkcapnames.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+#
+# generate a cap_names.h file from include/linux/capability.h
+#
+
+CAPHEAD="`dirname $0`/../include/linux/capability.h"
+REGEXP='^#define CAP_[A-Z_]+[ ]+[0-9]+$'
+NUMCAP=`cat "$CAPHEAD" | egrep -c "$REGEXP"`
+
+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 '#if !defined(SYSFS_CAP_NAME_ENTRY) || !defined(SYSFS_CAP_CODE_ENTRY)'
+echo '#error cap_names.h should be included from security/capability.c'
+echo '#else'
+echo "#if $NUMCAP != CAP_LAST_CAP + 1"
+echo '#error mkcapnames.sh cannot collect capabilities correctly'
+echo '#else'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_NAME_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_name_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_name_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_CODE_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_code_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_code_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo '#endif'
+echo '#endif'
+echo '#endif'
diff --git a/security/Makefile b/security/Makefile
index 9e8b025..c1ffc00 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -18,3 +18,12 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+
+# cap_names.h contains the code/name pair of capabilities.
+# It is generated using include/linux/capability.h automatically.
+$(obj)/commoncap.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)
diff --git a/security/commoncap.c b/security/commoncap.c
index 5aba826..896b080 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -24,6 +24,8 @@
#include <linux/hugetlb.h>
#include <linux/mount.h>
#include <linux/sched.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>

/* Global security state */

@@ -637,3 +639,113 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
return __vm_enough_memory(mm, pages, cap_sys_admin);
}

+/*
+ * Export the list of capabilities on /sys/kernel/capability
+ */
+static struct kobject *capability_kobj;
+
+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);
+ union {
+ int code;
+ char *name;
+ } c;
+};
+
+static ssize_t capability_name_show(struct kobject *kobj,
+ struct capability_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "%d\n", attr->c.code);
+}
+
+static ssize_t capability_code_show(struct kobject *kobj,
+ struct capability_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "%s\n", attr->c.name);
+}
+
+static ssize_t capability_version_show(struct kobject *kobj,
+ struct capability_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "0x%08x\n",
+ _LINUX_CAPABILITY_VERSION);
+}
+
+#define SYSFS_CAP_NAME_ENTRY(_name,_code) \
+ static struct capability_attribute _name##_name_attr = { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .show = capability_name_show, \
+ .c.code = (_code), \
+ }
+
+#define SYSFS_CAP_CODE_ENTRY(_name,_code) \
+ static struct capability_attribute _name##_code_attr = { \
+ .attr = { .name = __stringify(_code), .mode = 0444 }, \
+ .show = capability_code_show, \
+ .c.name = __stringify(_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_name_attr_group = {
+ .name = "names",
+ .attrs = capability_name_attrs,
+};
+
+static struct attribute_group capability_code_attr_group = {
+ .name = "codes",
+ .attrs = capability_code_attrs,
+};
+
+static struct capability_attribute cap_version_attr = {
+ .attr = { .name = "version", .mode = 0444 },
+ .show = capability_version_show,
+};
+
+static int __init capability_export_names(void)
+{
+ /* make /sys/kernel/capability */
+ capability_kobj = kobject_create_and_add("capability", kernel_kobj);
+ if (!capability_kobj)
+ goto error0;
+
+ /* make /sys/kernel/capability/names */
+ if (sysfs_create_group(capability_kobj,
+ &capability_name_attr_group))
+ goto error1;
+
+ /* make /sys/kernel/capability/codes */
+ if (sysfs_create_group(capability_kobj,
+ &capability_code_attr_group))
+ goto error2;
+
+ if (sysfs_create_file(capability_kobj,
+ &cap_version_attr.attr))
+ goto error3;
+
+ return 0;
+
+error3:
+ sysfs_remove_group(capability_kobj, &capability_code_attr_group);
+error2:
+ sysfs_remove_group(capability_kobj, &capability_name_attr_group);
+error1:
+ kobject_put(capability_kobj);
+error0:
+ printk(KERN_ERR "Unable to export capabilities\n");
+
+ return 0;
+}
+__initcall(capability_export_names);

--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-15 02:00:17

by Li Zefan

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #5)

Kohei KaiGai wrote:

<...snip...>

> +static int __init capability_export_names(void)
> +{
> + /* make /sys/kernel/capability */
> + capability_kobj = kobject_create_and_add("capability", kernel_kobj);
> + if (!capability_kobj)
> + goto error0;
> +
> + /* make /sys/kernel/capability/names */
> + if (sysfs_create_group(capability_kobj,
> + &capability_name_attr_group))
> + goto error1;
> +
> + /* make /sys/kernel/capability/codes */
> + if (sysfs_create_group(capability_kobj,
> + &capability_code_attr_group))
> + goto error2;
> +
> + if (sysfs_create_file(capability_kobj,
> + &cap_version_attr.attr))
> + goto error3;
> +
> + return 0;
> +
> +error3:
> + sysfs_remove_group(capability_kobj, &capability_code_attr_group);
> +error2:
> + sysfs_remove_group(capability_kobj, &capability_name_attr_group);
> +error1:
> + kobject_put(capability_kobj);
> +error0:
> + printk(KERN_ERR "Unable to export capabilities\n");
> +
> + return 0;

Should return -EFXXX ..

> +}
> +__initcall(capability_export_names);
>

2008-02-15 03:00:38

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #5.1)

Li Zefan wrote:
- snip -
>> +error1:
>> + kobject_put(capability_kobj);
>> +error0:
>> + printk(KERN_ERR "Unable to export capabilities\n");
>> +
>> + return 0;
>
> Should return -EFXXX ..

Oops,
I fixed it as follows. Thanks for your pointed out.

--------
This patch enables to export code/name of capabilities supported
on the running kernel.

A newer kernel sometimes adds new capabilities, like CAP_MAC_ADMIN
at 2.6.25. However, we have no interface to disclose what capabilities
are supported on this kernel. Thus, we have to maintain libcap version
in appropriate one synchronously.

This patch enables libcap to collect the list of capabilities on
run time, and provide them for users.
It helps to improve portability of library.

It exports these information as regular files under /sys/kernel/capability.
The numeric node exports its name, the symbolic node exports its code.

Please consider to put this patch on the queue of 2.6.25.

Thanks,
===================================================
[kaigai@saba ~]$ ls -R /sys/kernel/capability/
/sys/kernel/capability/:
codes names version

/sys/kernel/capability/codes:
0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9

/sys/kernel/capability/names:
cap_audit_control cap_kill cap_net_raw cap_sys_nice
cap_audit_write cap_lease cap_setfcap cap_sys_pacct
cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
cap_fowner cap_mknod cap_sys_admin cap_sys_time
cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
cap_ipc_lock cap_net_bind_service cap_sys_chroot
cap_ipc_owner cap_net_broadcast cap_sys_module
[kaigai@saba ~]$ cat /sys/kernel/capability/version
0x20071026
[kaigai@saba ~]$ cat /sys/kernel/capability/codes/30
cap_audit_control
[kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_sys_pacct
20
[kaigai@saba ~]$
===================================================

Signed-off-by: KaiGai Kohei <[email protected]>
--
scripts/mkcapnames.sh | 44 ++++++++++++++++++
security/Makefile | 9 ++++
security/commoncap.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 171 insertions(+), 0 deletions(-)

diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
index e69de29..5d36d52 100644
--- a/scripts/mkcapnames.sh
+++ b/scripts/mkcapnames.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+#
+# generate a cap_names.h file from include/linux/capability.h
+#
+
+CAPHEAD="`dirname $0`/../include/linux/capability.h"
+REGEXP='^#define CAP_[A-Z_]+[ ]+[0-9]+$'
+NUMCAP=`cat "$CAPHEAD" | egrep -c "$REGEXP"`
+
+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 '#if !defined(SYSFS_CAP_NAME_ENTRY) || !defined(SYSFS_CAP_CODE_ENTRY)'
+echo '#error cap_names.h should be included from security/capability.c'
+echo '#else'
+echo "#if $NUMCAP != CAP_LAST_CAP + 1"
+echo '#error mkcapnames.sh cannot collect capabilities correctly'
+echo '#else'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_NAME_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_name_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_name_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_CODE_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_code_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_code_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo '#endif'
+echo '#endif'
+echo '#endif'
diff --git a/security/Makefile b/security/Makefile
index 9e8b025..c1ffc00 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -18,3 +18,12 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+
+# cap_names.h contains the code/name pair of capabilities.
+# It is generated using include/linux/capability.h automatically.
+$(obj)/commoncap.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)
diff --git a/security/commoncap.c b/security/commoncap.c
index 5aba826..9e5665e 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -24,6 +24,8 @@
#include <linux/hugetlb.h>
#include <linux/mount.h>
#include <linux/sched.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>

/* Global security state */

@@ -637,3 +639,119 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
return __vm_enough_memory(mm, pages, cap_sys_admin);
}

+/*
+ * Export the list of capabilities on /sys/kernel/capability
+ */
+static struct kobject *capability_kobj;
+
+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);
+ union {
+ int code;
+ char *name;
+ } c;
+};
+
+static ssize_t capability_name_show(struct kobject *kobj,
+ struct capability_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "%d\n", attr->c.code);
+}
+
+static ssize_t capability_code_show(struct kobject *kobj,
+ struct capability_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "%s\n", attr->c.name);
+}
+
+static ssize_t capability_version_show(struct kobject *kobj,
+ struct capability_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "0x%08x\n",
+ _LINUX_CAPABILITY_VERSION);
+}
+
+#define SYSFS_CAP_NAME_ENTRY(_name,_code) \
+ static struct capability_attribute _name##_name_attr = { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .show = capability_name_show, \
+ .c.code = (_code), \
+ }
+
+#define SYSFS_CAP_CODE_ENTRY(_name,_code) \
+ static struct capability_attribute _name##_code_attr = { \
+ .attr = { .name = __stringify(_code), .mode = 0444 }, \
+ .show = capability_code_show, \
+ .c.name = __stringify(_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_name_attr_group = {
+ .name = "names",
+ .attrs = capability_name_attrs,
+};
+
+static struct attribute_group capability_code_attr_group = {
+ .name = "codes",
+ .attrs = capability_code_attrs,
+};
+
+static struct capability_attribute cap_version_attr = {
+ .attr = { .name = "version", .mode = 0444 },
+ .show = capability_version_show,
+};
+
+static int __init capability_export_names(void)
+{
+ int rc = -ENOMEM;
+
+ /* make /sys/kernel/capability */
+ capability_kobj = kobject_create_and_add("capability", kernel_kobj);
+ if (!capability_kobj)
+ goto error0;
+
+ /* make /sys/kernel/capability/names */
+ rc = sysfs_create_group(capability_kobj,
+ &capability_name_attr_group);
+ if (rc)
+ goto error1;
+
+ /* make /sys/kernel/capability/codes */
+ rc = sysfs_create_group(capability_kobj,
+ &capability_code_attr_group);
+ if (rc)
+ goto error2;
+
+ /* make /sys/kernel/capability/version */
+ rc = sysfs_create_file(capability_kobj,
+ &cap_version_attr.attr);
+ if (rc)
+ goto error3;
+
+ return 0;
+
+error3:
+ sysfs_remove_group(capability_kobj, &capability_code_attr_group);
+error2:
+ sysfs_remove_group(capability_kobj, &capability_name_attr_group);
+error1:
+ kobject_put(capability_kobj);
+error0:
+ printk(KERN_ERR "Unable to export capabilities\n");
+
+ return rc;
+}
+__initcall(capability_export_names);

--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-15 18:38:40

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #5.1)

Quoting Kohei KaiGai ([email protected]):
> Li Zefan wrote:
> - snip -
> >> +error1:
> >> + kobject_put(capability_kobj);
> >> +error0:
> >> + printk(KERN_ERR "Unable to export capabilities\n");
> >> +
> >> + return 0;
> >
> > Should return -EFXXX ..
>
> Oops,
> I fixed it as follows. Thanks for your pointed out.
>
> --------
> This patch enables to export code/name of capabilities supported
> on the running kernel.
>
> A newer kernel sometimes adds new capabilities, like CAP_MAC_ADMIN
> at 2.6.25. However, we have no interface to disclose what capabilities
> are supported on this kernel. Thus, we have to maintain libcap version
> in appropriate one synchronously.
>
> This patch enables libcap to collect the list of capabilities on
> run time, and provide them for users.
> It helps to improve portability of library.
>
> It exports these information as regular files under /sys/kernel/capability.
> The numeric node exports its name, the symbolic node exports its code.
>
> Please consider to put this patch on the queue of 2.6.25.

Looks good, except don't you need to put the code in commoncap.c under a
#ifdef SYSFS?

thanks,
-serge

>
> Thanks,
> ===================================================
> [kaigai@saba ~]$ ls -R /sys/kernel/capability/
> /sys/kernel/capability/:
> codes names version
>
> /sys/kernel/capability/codes:
> 0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
> 1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9
>
> /sys/kernel/capability/names:
> cap_audit_control cap_kill cap_net_raw cap_sys_nice
> cap_audit_write cap_lease cap_setfcap cap_sys_pacct
> cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
> cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
> cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
> cap_fowner cap_mknod cap_sys_admin cap_sys_time
> cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
> cap_ipc_lock cap_net_bind_service cap_sys_chroot
> cap_ipc_owner cap_net_broadcast cap_sys_module
> [kaigai@saba ~]$ cat /sys/kernel/capability/version
> 0x20071026
> [kaigai@saba ~]$ cat /sys/kernel/capability/codes/30
> cap_audit_control
> [kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_sys_pacct
> 20
> [kaigai@saba ~]$
> ===================================================
>
> Signed-off-by: KaiGai Kohei <[email protected]>
> --
> scripts/mkcapnames.sh | 44 ++++++++++++++++++
> security/Makefile | 9 ++++
> security/commoncap.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 171 insertions(+), 0 deletions(-)
>
> diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
> index e69de29..5d36d52 100644
> --- a/scripts/mkcapnames.sh
> +++ b/scripts/mkcapnames.sh
> @@ -0,0 +1,44 @@
> +#!/bin/sh
> +
> +#
> +# generate a cap_names.h file from include/linux/capability.h
> +#
> +
> +CAPHEAD="`dirname $0`/../include/linux/capability.h"
> +REGEXP='^#define CAP_[A-Z_]+[ ]+[0-9]+$'
> +NUMCAP=`cat "$CAPHEAD" | egrep -c "$REGEXP"`
> +
> +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 '#if !defined(SYSFS_CAP_NAME_ENTRY) || !defined(SYSFS_CAP_CODE_ENTRY)'
> +echo '#error cap_names.h should be included from security/capability.c'
> +echo '#else'
> +echo "#if $NUMCAP != CAP_LAST_CAP + 1"
> +echo '#error mkcapnames.sh cannot collect capabilities correctly'
> +echo '#else'
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("SYSFS_CAP_NAME_ENTRY(%s,%s);\n", tolower($2), $2); }'
> +echo
> +echo 'static struct attribute *capability_name_attrs[] = {'
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("\t&%s_name_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
> +echo '};'
> +
> +echo
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("SYSFS_CAP_CODE_ENTRY(%s,%s);\n", tolower($2), $2); }'
> +echo
> +echo 'static struct attribute *capability_code_attrs[] = {'
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("\t&%s_code_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
> +echo '};'
> +
> +echo '#endif'
> +echo '#endif'
> +echo '#endif'
> diff --git a/security/Makefile b/security/Makefile
> index 9e8b025..c1ffc00 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -18,3 +18,12 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
> obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
> obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
> obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
> +
> +# cap_names.h contains the code/name pair of capabilities.
> +# It is generated using include/linux/capability.h automatically.
> +$(obj)/commoncap.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)
> diff --git a/security/commoncap.c b/security/commoncap.c
> index 5aba826..9e5665e 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -24,6 +24,8 @@
> #include <linux/hugetlb.h>
> #include <linux/mount.h>
> #include <linux/sched.h>
> +#include <linux/kobject.h>
> +#include <linux/sysfs.h>
>
> /* Global security state */
>
> @@ -637,3 +639,119 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
> return __vm_enough_memory(mm, pages, cap_sys_admin);
> }
>
> +/*
> + * Export the list of capabilities on /sys/kernel/capability
> + */
> +static struct kobject *capability_kobj;
> +
> +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);
> + union {
> + int code;
> + char *name;
> + } c;
> +};
> +
> +static ssize_t capability_name_show(struct kobject *kobj,
> + struct capability_attribute *attr,
> + char *buffer)
> +{
> + return scnprintf(buffer, PAGE_SIZE, "%d\n", attr->c.code);
> +}
> +
> +static ssize_t capability_code_show(struct kobject *kobj,
> + struct capability_attribute *attr,
> + char *buffer)
> +{
> + return scnprintf(buffer, PAGE_SIZE, "%s\n", attr->c.name);
> +}
> +
> +static ssize_t capability_version_show(struct kobject *kobj,
> + struct capability_attribute *attr,
> + char *buffer)
> +{
> + return scnprintf(buffer, PAGE_SIZE, "0x%08x\n",
> + _LINUX_CAPABILITY_VERSION);
> +}
> +
> +#define SYSFS_CAP_NAME_ENTRY(_name,_code) \
> + static struct capability_attribute _name##_name_attr = { \
> + .attr = { .name = __stringify(_name), .mode = 0444 }, \
> + .show = capability_name_show, \
> + .c.code = (_code), \
> + }
> +
> +#define SYSFS_CAP_CODE_ENTRY(_name,_code) \
> + static struct capability_attribute _name##_code_attr = { \
> + .attr = { .name = __stringify(_code), .mode = 0444 }, \
> + .show = capability_code_show, \
> + .c.name = __stringify(_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_name_attr_group = {
> + .name = "names",
> + .attrs = capability_name_attrs,
> +};
> +
> +static struct attribute_group capability_code_attr_group = {
> + .name = "codes",
> + .attrs = capability_code_attrs,
> +};
> +
> +static struct capability_attribute cap_version_attr = {
> + .attr = { .name = "version", .mode = 0444 },
> + .show = capability_version_show,
> +};
> +
> +static int __init capability_export_names(void)
> +{
> + int rc = -ENOMEM;
> +
> + /* make /sys/kernel/capability */
> + capability_kobj = kobject_create_and_add("capability", kernel_kobj);
> + if (!capability_kobj)
> + goto error0;
> +
> + /* make /sys/kernel/capability/names */
> + rc = sysfs_create_group(capability_kobj,
> + &capability_name_attr_group);
> + if (rc)
> + goto error1;
> +
> + /* make /sys/kernel/capability/codes */
> + rc = sysfs_create_group(capability_kobj,
> + &capability_code_attr_group);
> + if (rc)
> + goto error2;
> +
> + /* make /sys/kernel/capability/version */
> + rc = sysfs_create_file(capability_kobj,
> + &cap_version_attr.attr);
> + if (rc)
> + goto error3;
> +
> + return 0;
> +
> +error3:
> + sysfs_remove_group(capability_kobj, &capability_code_attr_group);
> +error2:
> + sysfs_remove_group(capability_kobj, &capability_name_attr_group);
> +error1:
> + kobject_put(capability_kobj);
> +error0:
> + printk(KERN_ERR "Unable to export capabilities\n");
> +
> + return rc;
> +}
> +__initcall(capability_export_names);
>
> --
> OSS Platform Development Division, NEC
> KaiGai Kohei <[email protected]>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2008-02-15 19:38:58

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #5.1)

On Fri, Feb 15, 2008 at 12:38:02PM -0600, Serge E. Hallyn wrote:
> Quoting Kohei KaiGai ([email protected]):
> > Li Zefan wrote:
> > - snip -
> > >> +error1:
> > >> + kobject_put(capability_kobj);
> > >> +error0:
> > >> + printk(KERN_ERR "Unable to export capabilities\n");
> > >> +
> > >> + return 0;
> > >
> > > Should return -EFXXX ..
> >
> > Oops,
> > I fixed it as follows. Thanks for your pointed out.
> >
> > --------
> > This patch enables to export code/name of capabilities supported
> > on the running kernel.
> >
> > A newer kernel sometimes adds new capabilities, like CAP_MAC_ADMIN
> > at 2.6.25. However, we have no interface to disclose what capabilities
> > are supported on this kernel. Thus, we have to maintain libcap version
> > in appropriate one synchronously.
> >
> > This patch enables libcap to collect the list of capabilities on
> > run time, and provide them for users.
> > It helps to improve portability of library.
> >
> > It exports these information as regular files under /sys/kernel/capability.
> > The numeric node exports its name, the symbolic node exports its code.
> >
> > Please consider to put this patch on the queue of 2.6.25.
>
> Looks good, except don't you need to put the code in commoncap.c under a
> #ifdef SYSFS?
>
> thanks,
> -serge
>
> >
> > Thanks,
> > ===================================================
> > [kaigai@saba ~]$ ls -R /sys/kernel/capability/
> > /sys/kernel/capability/:
> > codes names version
> >
> > /sys/kernel/capability/codes:
> > 0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
> > 1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9
> >
> > /sys/kernel/capability/names:
> > cap_audit_control cap_kill cap_net_raw cap_sys_nice
> > cap_audit_write cap_lease cap_setfcap cap_sys_pacct
> > cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
> > cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
> > cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
> > cap_fowner cap_mknod cap_sys_admin cap_sys_time
> > cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
> > cap_ipc_lock cap_net_bind_service cap_sys_chroot
> > cap_ipc_owner cap_net_broadcast cap_sys_module
> > [kaigai@saba ~]$ cat /sys/kernel/capability/version
> > 0x20071026
> > [kaigai@saba ~]$ cat /sys/kernel/capability/codes/30
> > cap_audit_control
> > [kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_sys_pacct
> > 20
> > [kaigai@saba ~]$
> > ===================================================

As you are adding new sysfs entries, please also add the needed
Documentation/ABI/ entries as well.

Also, this code can be cleaned up a lot by just using the basic kobject
attributes, and not rolling your own types here.

thanks,

greg k-h

2008-02-18 07:13:54

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #5.1)

Greg KH wrote:
> On Fri, Feb 15, 2008 at 12:38:02PM -0600, Serge E. Hallyn wrote:
>>> --------
>>> This patch enables to export code/name of capabilities supported
>>> on the running kernel.
>>>
>>> A newer kernel sometimes adds new capabilities, like CAP_MAC_ADMIN
>>> at 2.6.25. However, we have no interface to disclose what capabilities
>>> are supported on this kernel. Thus, we have to maintain libcap version
>>> in appropriate one synchronously.
>>>
>>> This patch enables libcap to collect the list of capabilities on
>>> run time, and provide them for users.
>>> It helps to improve portability of library.
>>>
>>> It exports these information as regular files under /sys/kernel/capability.
>>> The numeric node exports its name, the symbolic node exports its code.
>>>
>>> Please consider to put this patch on the queue of 2.6.25.
>> Looks good, except don't you need to put the code in commoncap.c under a
>> #ifdef SYSFS?

Fair enough.
I added the #ifdef - #endif block in this patch.

>>> ===================================================
>>> [kaigai@saba ~]$ ls -R /sys/kernel/capability/
>>> /sys/kernel/capability/:
>>> codes names version
>>>
>>> /sys/kernel/capability/codes:
>>> 0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
>>> 1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9
>>>
>>> /sys/kernel/capability/names:
>>> cap_audit_control cap_kill cap_net_raw cap_sys_nice
>>> cap_audit_write cap_lease cap_setfcap cap_sys_pacct
>>> cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
>>> cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
>>> cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
>>> cap_fowner cap_mknod cap_sys_admin cap_sys_time
>>> cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
>>> cap_ipc_lock cap_net_bind_service cap_sys_chroot
>>> cap_ipc_owner cap_net_broadcast cap_sys_module
>>> [kaigai@saba ~]$ cat /sys/kernel/capability/version
>>> 0x20071026
>>> [kaigai@saba ~]$ cat /sys/kernel/capability/codes/30
>>> cap_audit_control
>>> [kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_sys_pacct
>>> 20
>>> [kaigai@saba ~]$
>>> ===================================================
>
> As you are adding new sysfs entries, please also add the needed
> Documentation/ABI/ entries as well.

OK, I'll add a short description at Documentation/ABI/sysfs-kernel-capability .

> Also, this code can be cleaned up a lot by just using the basic kobject
> attributes, and not rolling your own types here.

I replaced my own defined capability_attribute by kobj_attribute.

It made the patch cleaned up, however, it also impossible to share a single
_show() method instance, because kobj_attribute does not have any private member.
Is there any reason why kobj_attribute does not have "void *private;"?

Thanks,
Signed-off-by: KaiGai Kohei <[email protected]>
--
Documentation/ABI/testing/sysfs-kernel-capability | 23 +++++
scripts/mkcapnames.sh | 44 +++++++++
security/Makefile | 9 ++
security/commoncap.c | 102 +++++++++++++++++++++
4 files changed, 178 insertions(+), 0 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-kernel-capability b/Documentation/ABI/testing/sysfs-kernel-capability
index e69de29..402ef06 100644
--- a/Documentation/ABI/testing/sysfs-kernel-capability
+++ b/Documentation/ABI/testing/sysfs-kernel-capability
@@ -0,0 +1,23 @@
+What: /sys/kernel/capability
+Date: Feb 2008
+Contact: KaiGai Kohei <[email protected]>
+Description:
+ The entries under /sys/kernel/capability are used to export
+ the list of capabilities the running kernel supported.
+
+ - /sys/kernel/capability/version
+ returns the most preferable version number for the
+ running kernel.
+ e.g) $ cat /sys/kernel/capability/version
+ 0x20071026
+
+ - /sys/kernel/capability/code/<numerical representation>
+ returns its symbolic representation, on reading.
+ e.g) $ cat /sys/kernel/capability/codes/30
+ cap_audit_control
+
+ - /sys/kernel/capability/name/<symbolic representation>
+ returns its numerical representation, on reading.
+ e.g) $ cat /sys/kernel/capability/names/cap_sys_pacct
+ 20
+
diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
index e69de29..5d36d52 100644
--- a/scripts/mkcapnames.sh
+++ b/scripts/mkcapnames.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+#
+# generate a cap_names.h file from include/linux/capability.h
+#
+
+CAPHEAD="`dirname $0`/../include/linux/capability.h"
+REGEXP='^#define CAP_[A-Z_]+[ ]+[0-9]+$'
+NUMCAP=`cat "$CAPHEAD" | egrep -c "$REGEXP"`
+
+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 '#if !defined(SYSFS_CAP_NAME_ENTRY) || !defined(SYSFS_CAP_CODE_ENTRY)'
+echo '#error cap_names.h should be included from security/capability.c'
+echo '#else'
+echo "#if $NUMCAP != CAP_LAST_CAP + 1"
+echo '#error mkcapnames.sh cannot collect capabilities correctly'
+echo '#else'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_NAME_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_name_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_name_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_CODE_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_code_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_code_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo '#endif'
+echo '#endif'
+echo '#endif'
diff --git a/security/Makefile b/security/Makefile
index 9e8b025..c1ffc00 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -18,3 +18,12 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+
+# cap_names.h contains the code/name pair of capabilities.
+# It is generated using include/linux/capability.h automatically.
+$(obj)/commoncap.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)
diff --git a/security/commoncap.c b/security/commoncap.c
index 5aba826..0f2f778 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -24,6 +24,8 @@
#include <linux/hugetlb.h>
#include <linux/mount.h>
#include <linux/sched.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>

/* Global security state */

@@ -637,3 +639,103 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
return __vm_enough_memory(mm, pages, cap_sys_admin);
}

+#ifdef CONFIG_SYSFS
+/*
+ * Export the list of capabilities on /sys/kernel/capability
+ */
+static struct kobject *capability_kobj;
+
+#define SYSFS_CAP_NAME_ENTRY(_name,_code) \
+ static ssize_t capname_##_name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ char *buffer) \
+ { \
+ return scnprintf(buffer, PAGE_SIZE, "%d\n", _code); \
+ } \
+ static struct kobj_attribute _name##_name_attr = { \
+ .attr = { .name = __stringify(_name), .mode = 0444, }, \
+ .show = capname_##_name##_show, \
+ }
+
+#define SYSFS_CAP_CODE_ENTRY(_name,_code) \
+ static ssize_t capcode_##_name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ char *buffer) \
+ { \
+ return scnprintf(buffer, PAGE_SIZE, "%s\n", __stringify(_name)); \
+ } \
+ static struct kobj_attribute _name##_code_attr = { \
+ .attr = { .name = __stringify(_code), .mode = 0444, }, \
+ .show = capcode_##_name##_show, \
+ }
+
+/*
+ * 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_name_attr_group = {
+ .name = "names",
+ .attrs = capability_name_attrs,
+};
+
+static struct attribute_group capability_code_attr_group = {
+ .name = "codes",
+ .attrs = capability_code_attrs,
+};
+
+static ssize_t capability_version_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "0x%08x\n",
+ _LINUX_CAPABILITY_VERSION);
+}
+static struct kobj_attribute cap_version_attr = {
+ .attr = { .name = "version", .mode = 0444 },
+ .show = capability_version_show,
+};
+
+static int __init capability_export_names(void)
+{
+ int rc = -ENOMEM;
+
+ /* make /sys/kernel/capability */
+ capability_kobj = kobject_create_and_add("capability", kernel_kobj);
+ if (!capability_kobj)
+ goto error0;
+
+ /* make /sys/kernel/capability/names */
+ rc = sysfs_create_group(capability_kobj,
+ &capability_name_attr_group);
+ if (rc)
+ goto error1;
+
+ /* make /sys/kernel/capability/codes */
+ rc = sysfs_create_group(capability_kobj,
+ &capability_code_attr_group);
+ if (rc)
+ goto error2;
+
+ /* make /sys/kernel/capability/version */
+ rc = sysfs_create_file(capability_kobj,
+ &cap_version_attr.attr);
+ if (rc)
+ goto error3;
+
+ return 0;
+
+error3:
+ sysfs_remove_group(capability_kobj, &capability_code_attr_group);
+error2:
+ sysfs_remove_group(capability_kobj, &capability_name_attr_group);
+error1:
+ kobject_put(capability_kobj);
+error0:
+ printk(KERN_ERR "Unable to export capabilities\n");
+
+ return rc;
+}
+__initcall(capability_export_names);
+#endif /* CONFIG_SYSFS */

--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-18 07:37:39

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #5.1)

On Mon, Feb 18, 2008 at 04:12:53PM +0900, Kohei KaiGai wrote:
> Greg KH wrote:
> > On Fri, Feb 15, 2008 at 12:38:02PM -0600, Serge E. Hallyn wrote:
> >>> --------
> >>> This patch enables to export code/name of capabilities supported
> >>> on the running kernel.
> >>>
> >>> A newer kernel sometimes adds new capabilities, like CAP_MAC_ADMIN
> >>> at 2.6.25. However, we have no interface to disclose what capabilities
> >>> are supported on this kernel. Thus, we have to maintain libcap version
> >>> in appropriate one synchronously.
> >>>
> >>> This patch enables libcap to collect the list of capabilities on
> >>> run time, and provide them for users.
> >>> It helps to improve portability of library.
> >>>
> >>> It exports these information as regular files under /sys/kernel/capability.
> >>> The numeric node exports its name, the symbolic node exports its code.
> >>>
> >>> Please consider to put this patch on the queue of 2.6.25.
> >> Looks good, except don't you need to put the code in commoncap.c under a
> >> #ifdef SYSFS?
>
> Fair enough.
> I added the #ifdef - #endif block in this patch.

Not needed, if SYSFS is not build in, all of that code pretty much
compiles away to nothing. So you can drop that.

>
> >>> ===================================================
> >>> [kaigai@saba ~]$ ls -R /sys/kernel/capability/
> >>> /sys/kernel/capability/:
> >>> codes names version
> >>>
> >>> /sys/kernel/capability/codes:
> >>> 0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
> >>> 1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9
> >>>
> >>> /sys/kernel/capability/names:
> >>> cap_audit_control cap_kill cap_net_raw cap_sys_nice
> >>> cap_audit_write cap_lease cap_setfcap cap_sys_pacct
> >>> cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
> >>> cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
> >>> cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
> >>> cap_fowner cap_mknod cap_sys_admin cap_sys_time
> >>> cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
> >>> cap_ipc_lock cap_net_bind_service cap_sys_chroot
> >>> cap_ipc_owner cap_net_broadcast cap_sys_module
> >>> [kaigai@saba ~]$ cat /sys/kernel/capability/version
> >>> 0x20071026
> >>> [kaigai@saba ~]$ cat /sys/kernel/capability/codes/30
> >>> cap_audit_control
> >>> [kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_sys_pacct
> >>> 20
> >>> [kaigai@saba ~]$
> >>> ===================================================
> >
> > As you are adding new sysfs entries, please also add the needed
> > Documentation/ABI/ entries as well.
>
> OK, I'll add a short description at Documentation/ABI/sysfs-kernel-capability .

Thank you.

> > Also, this code can be cleaned up a lot by just using the basic kobject
> > attributes, and not rolling your own types here.
>
> I replaced my own defined capability_attribute by kobj_attribute.
>
> It made the patch cleaned up, however, it also impossible to share a single
> _show() method instance, because kobj_attribute does not have any private member.
> Is there any reason why kobj_attribute does not have "void *private;"?

Because no one has asked for it? :)

Or you can just do as the example in samples/kobject/ does it, no need
for the void pointer as that code shows.



>
> Thanks,
> Signed-off-by: KaiGai Kohei <[email protected]>
> --
> Documentation/ABI/testing/sysfs-kernel-capability | 23 +++++
> scripts/mkcapnames.sh | 44 +++++++++
> security/Makefile | 9 ++
> security/commoncap.c | 102 +++++++++++++++++++++
> 4 files changed, 178 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-kernel-capability b/Documentation/ABI/testing/sysfs-kernel-capability
> index e69de29..402ef06 100644
> --- a/Documentation/ABI/testing/sysfs-kernel-capability
> +++ b/Documentation/ABI/testing/sysfs-kernel-capability
> @@ -0,0 +1,23 @@
> +What: /sys/kernel/capability
> +Date: Feb 2008
> +Contact: KaiGai Kohei <[email protected]>
> +Description:
> + The entries under /sys/kernel/capability are used to export
> + the list of capabilities the running kernel supported.
> +
> + - /sys/kernel/capability/version
> + returns the most preferable version number for the
> + running kernel.
> + e.g) $ cat /sys/kernel/capability/version
> + 0x20071026
> +
> + - /sys/kernel/capability/code/<numerical representation>
> + returns its symbolic representation, on reading.
> + e.g) $ cat /sys/kernel/capability/codes/30
> + cap_audit_control
> +
> + - /sys/kernel/capability/name/<symbolic representation>
> + returns its numerical representation, on reading.
> + e.g) $ cat /sys/kernel/capability/names/cap_sys_pacct
> + 20
> +
> diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
> index e69de29..5d36d52 100644
> --- a/scripts/mkcapnames.sh
> +++ b/scripts/mkcapnames.sh
> @@ -0,0 +1,44 @@
> +#!/bin/sh
> +
> +#
> +# generate a cap_names.h file from include/linux/capability.h
> +#
> +
> +CAPHEAD="`dirname $0`/../include/linux/capability.h"
> +REGEXP='^#define CAP_[A-Z_]+[ ]+[0-9]+$'
> +NUMCAP=`cat "$CAPHEAD" | egrep -c "$REGEXP"`
> +
> +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 '#if !defined(SYSFS_CAP_NAME_ENTRY) || !defined(SYSFS_CAP_CODE_ENTRY)'
> +echo '#error cap_names.h should be included from security/capability.c'
> +echo '#else'
> +echo "#if $NUMCAP != CAP_LAST_CAP + 1"
> +echo '#error mkcapnames.sh cannot collect capabilities correctly'
> +echo '#else'
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("SYSFS_CAP_NAME_ENTRY(%s,%s);\n", tolower($2), $2); }'
> +echo
> +echo 'static struct attribute *capability_name_attrs[] = {'
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("\t&%s_name_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
> +echo '};'
> +
> +echo
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("SYSFS_CAP_CODE_ENTRY(%s,%s);\n", tolower($2), $2); }'
> +echo
> +echo 'static struct attribute *capability_code_attrs[] = {'
> +cat "$CAPHEAD" | egrep "$REGEXP" \
> + | awk '{ printf("\t&%s_code_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
> +echo '};'
> +
> +echo '#endif'
> +echo '#endif'
> +echo '#endif'
> diff --git a/security/Makefile b/security/Makefile
> index 9e8b025..c1ffc00 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -18,3 +18,12 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
> obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
> obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
> obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
> +
> +# cap_names.h contains the code/name pair of capabilities.
> +# It is generated using include/linux/capability.h automatically.
> +$(obj)/commoncap.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)
> diff --git a/security/commoncap.c b/security/commoncap.c
> index 5aba826..0f2f778 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -24,6 +24,8 @@
> #include <linux/hugetlb.h>
> #include <linux/mount.h>
> #include <linux/sched.h>
> +#include <linux/kobject.h>
> +#include <linux/sysfs.h>
>
> /* Global security state */
>
> @@ -637,3 +639,103 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
> return __vm_enough_memory(mm, pages, cap_sys_admin);
> }
>
> +#ifdef CONFIG_SYSFS
> +/*
> + * Export the list of capabilities on /sys/kernel/capability
> + */
> +static struct kobject *capability_kobj;
> +
> +#define SYSFS_CAP_NAME_ENTRY(_name,_code) \
> + static ssize_t capname_##_name##_show(struct kobject *kobj, \
> + struct kobj_attribute *attr, \
> + char *buffer) \
> + { \
> + return scnprintf(buffer, PAGE_SIZE, "%d\n", _code); \
> + } \
> + static struct kobj_attribute _name##_name_attr = { \
> + .attr = { .name = __stringify(_name), .mode = 0444, }, \
> + .show = capname_##_name##_show, \
> + }
> +
> +#define SYSFS_CAP_CODE_ENTRY(_name,_code) \
> + static ssize_t capcode_##_name##_show(struct kobject *kobj, \
> + struct kobj_attribute *attr, \
> + char *buffer) \
> + { \
> + return scnprintf(buffer, PAGE_SIZE, "%s\n", __stringify(_name)); \
> + } \
> + static struct kobj_attribute _name##_code_attr = { \
> + .attr = { .name = __stringify(_code), .mode = 0444, }, \
> + .show = capcode_##_name##_show, \
> + }
> +
> +/*
> + * 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_name_attr_group = {
> + .name = "names",
> + .attrs = capability_name_attrs,
> +};
> +
> +static struct attribute_group capability_code_attr_group = {
> + .name = "codes",
> + .attrs = capability_code_attrs,
> +};
> +
> +static ssize_t capability_version_show(struct kobject *kobj,
> + struct kobj_attribute *attr,
> + char *buffer)
> +{
> + return scnprintf(buffer, PAGE_SIZE, "0x%08x\n",
> + _LINUX_CAPABILITY_VERSION);
> +}
> +static struct kobj_attribute cap_version_attr = {
> + .attr = { .name = "version", .mode = 0444 },
> + .show = capability_version_show,
> +};

We do have macros for these kinds of things :)

Look at ATTR() and friends.

> +
> +static int __init capability_export_names(void)
> +{
> + int rc = -ENOMEM;
> +
> + /* make /sys/kernel/capability */
> + capability_kobj = kobject_create_and_add("capability", kernel_kobj);
> + if (!capability_kobj)
> + goto error0;
> +
> + /* make /sys/kernel/capability/names */
> + rc = sysfs_create_group(capability_kobj,
> + &capability_name_attr_group);
> + if (rc)
> + goto error1;
> +
> + /* make /sys/kernel/capability/codes */
> + rc = sysfs_create_group(capability_kobj,
> + &capability_code_attr_group);
> + if (rc)
> + goto error2;
> +
> + /* make /sys/kernel/capability/version */
> + rc = sysfs_create_file(capability_kobj,
> + &cap_version_attr.attr);
> + if (rc)
> + goto error3;
> +
> + return 0;
> +
> +error3:
> + sysfs_remove_group(capability_kobj, &capability_code_attr_group);
> +error2:
> + sysfs_remove_group(capability_kobj, &capability_name_attr_group);
> +error1:
> + kobject_put(capability_kobj);
> +error0:
> + printk(KERN_ERR "Unable to export capabilities\n");
> +
> + return rc;
> +}
> +__initcall(capability_export_names);
> +#endif /* CONFIG_SYSFS */

Where do you remove these files? Or will that never happen?

thanks,

greg k-h

2008-02-18 08:46:37

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #5.1)

Greg KH wrote:
> On Mon, Feb 18, 2008 at 04:12:53PM +0900, Kohei KaiGai wrote:
>> Greg KH wrote:
>>> On Fri, Feb 15, 2008 at 12:38:02PM -0600, Serge E. Hallyn wrote:
>>>>> --------
>>>>> This patch enables to export code/name of capabilities supported
>>>>> on the running kernel.
>>>>>
>>>>> A newer kernel sometimes adds new capabilities, like CAP_MAC_ADMIN
>>>>> at 2.6.25. However, we have no interface to disclose what capabilities
>>>>> are supported on this kernel. Thus, we have to maintain libcap version
>>>>> in appropriate one synchronously.
>>>>>
>>>>> This patch enables libcap to collect the list of capabilities on
>>>>> run time, and provide them for users.
>>>>> It helps to improve portability of library.
>>>>>
>>>>> It exports these information as regular files under /sys/kernel/capability.
>>>>> The numeric node exports its name, the symbolic node exports its code.
>>>>>
>>>>> Please consider to put this patch on the queue of 2.6.25.
>>>> Looks good, except don't you need to put the code in commoncap.c under a
>>>> #ifdef SYSFS?
>> Fair enough.
>> I added the #ifdef - #endif block in this patch.
>
> Not needed, if SYSFS is not build in, all of that code pretty much
> compiles away to nothing. So you can drop that.

Hmm..., I reverted these #ifdef and #endif in this version.

>>> Also, this code can be cleaned up a lot by just using the basic kobject
>>> attributes, and not rolling your own types here.
>> I replaced my own defined capability_attribute by kobj_attribute.
>>
>> It made the patch cleaned up, however, it also impossible to share a single
>> _show() method instance, because kobj_attribute does not have any private member.
>> Is there any reason why kobj_attribute does not have "void *private;"?
>
> Because no one has asked for it? :)
>
> Or you can just do as the example in samples/kobject/ does it, no need
> for the void pointer as that code shows.

It shows us a good example in samples/kobject.

However, it is unsuitable to export the list of capabilities.
The shared _show() method (b_show) calls strcmp() once with the name of kobject
attribute to switch its returning string.
If we have 34 of candidates to be returned, like the capability case, we have
to call strcmp() 33 times in maximum.

If we can have a private member in kobj_attribute, we can found the content
to be returned in a single step.

>> +static struct kobj_attribute cap_version_attr = {
>> + .attr = { .name = "version", .mode = 0444 },
>> + .show = capability_version_show,
>> +};
>
> We do have macros for these kinds of things :)
>
> Look at ATTR() and friends.

OK, fixed.
I applied __ATTR() instead.

>> +static int __init capability_export_names(void)
>> +{
>> + int rc = -ENOMEM;
>> +
>> + /* make /sys/kernel/capability */
>> + capability_kobj = kobject_create_and_add("capability", kernel_kobj);
>> + if (!capability_kobj)
>> + goto error0;
>> +
>> + /* make /sys/kernel/capability/names */
>> + rc = sysfs_create_group(capability_kobj,
>> + &capability_name_attr_group);
>> + if (rc)
>> + goto error1;
>> +
>> + /* make /sys/kernel/capability/codes */
>> + rc = sysfs_create_group(capability_kobj,
>> + &capability_code_attr_group);
>> + if (rc)
>> + goto error2;
>> +
>> + /* make /sys/kernel/capability/version */
>> + rc = sysfs_create_file(capability_kobj,
>> + &cap_version_attr.attr);
>> + if (rc)
>> + goto error3;
>> +
>> + return 0;
>> +
>> +error3:
>> + sysfs_remove_group(capability_kobj, &capability_code_attr_group);
>> +error2:
>> + sysfs_remove_group(capability_kobj, &capability_name_attr_group);
>> +error1:
>> + kobject_put(capability_kobj);
>> +error0:
>> + printk(KERN_ERR "Unable to export capabilities\n");
>> +
>> + return rc;
>> +}
>> +__initcall(capability_export_names);
>> +#endif /* CONFIG_SYSFS */
>
> Where do you remove these files? Or will that never happen?

Removing these files are never happen.

Thanks,

Signed-off-by: KaiGai Kohei <[email protected]>
--
Documentation/ABI/testing/sysfs-kernel-capability | 23 +++++
scripts/mkcapnames.sh | 44 ++++++++++
security/Makefile | 9 ++
security/commoncap.c | 94 +++++++++++++++++++++
4 files changed, 170 insertions(+), 0 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-kernel-capability b/Documentation/ABI/testing/sysfs-kernel-capability
index e69de29..402ef06 100644
--- a/Documentation/ABI/testing/sysfs-kernel-capability
+++ b/Documentation/ABI/testing/sysfs-kernel-capability
@@ -0,0 +1,23 @@
+What: /sys/kernel/capability
+Date: Feb 2008
+Contact: KaiGai Kohei <[email protected]>
+Description:
+ The entries under /sys/kernel/capability are used to export
+ the list of capabilities the running kernel supported.
+
+ - /sys/kernel/capability/version
+ returns the most preferable version number for the
+ running kernel.
+ e.g) $ cat /sys/kernel/capability/version
+ 0x20071026
+
+ - /sys/kernel/capability/code/<numerical representation>
+ returns its symbolic representation, on reading.
+ e.g) $ cat /sys/kernel/capability/codes/30
+ cap_audit_control
+
+ - /sys/kernel/capability/name/<symbolic representation>
+ returns its numerical representation, on reading.
+ e.g) $ cat /sys/kernel/capability/names/cap_sys_pacct
+ 20
+
diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
index e69de29..5d36d52 100644
--- a/scripts/mkcapnames.sh
+++ b/scripts/mkcapnames.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+#
+# generate a cap_names.h file from include/linux/capability.h
+#
+
+CAPHEAD="`dirname $0`/../include/linux/capability.h"
+REGEXP='^#define CAP_[A-Z_]+[ ]+[0-9]+$'
+NUMCAP=`cat "$CAPHEAD" | egrep -c "$REGEXP"`
+
+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 '#if !defined(SYSFS_CAP_NAME_ENTRY) || !defined(SYSFS_CAP_CODE_ENTRY)'
+echo '#error cap_names.h should be included from security/capability.c'
+echo '#else'
+echo "#if $NUMCAP != CAP_LAST_CAP + 1"
+echo '#error mkcapnames.sh cannot collect capabilities correctly'
+echo '#else'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_NAME_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_name_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_name_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_CODE_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_code_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_code_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo '#endif'
+echo '#endif'
+echo '#endif'
diff --git a/security/Makefile b/security/Makefile
index 9e8b025..c1ffc00 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -18,3 +18,12 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+
+# cap_names.h contains the code/name pair of capabilities.
+# It is generated using include/linux/capability.h automatically.
+$(obj)/commoncap.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)
diff --git a/security/commoncap.c b/security/commoncap.c
index 5aba826..8e8fbd9 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -24,6 +24,8 @@
#include <linux/hugetlb.h>
#include <linux/mount.h>
#include <linux/sched.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>

/* Global security state */

@@ -637,3 +639,95 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
return __vm_enough_memory(mm, pages, cap_sys_admin);
}

+/*
+ * Export the list of capabilities on /sys/kernel/capability
+ */
+static struct kobject *capability_kobj;
+
+#define SYSFS_CAP_NAME_ENTRY(_name,_code) \
+ static ssize_t capname_##_name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ char *buffer) \
+ { \
+ return scnprintf(buffer, PAGE_SIZE, "%d\n", _code); \
+ } \
+ static struct kobj_attribute _name##_name_attr = \
+ __ATTR(_name, 0444, capname_##_name##_show, NULL)
+
+#define SYSFS_CAP_CODE_ENTRY(_name,_code) \
+ static ssize_t capcode_##_name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ char *buffer) \
+ { \
+ return scnprintf(buffer, PAGE_SIZE, "%s\n", __stringify(_name)); \
+ } \
+ static struct kobj_attribute _name##_code_attr = \
+ __ATTR(_code, 0444, capcode_##_name##_show, NULL)
+
+/*
+ * 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_name_attr_group = {
+ .name = "names",
+ .attrs = capability_name_attrs,
+};
+
+static struct attribute_group capability_code_attr_group = {
+ .name = "codes",
+ .attrs = capability_code_attrs,
+};
+
+static ssize_t capability_version_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "0x%08x\n",
+ _LINUX_CAPABILITY_VERSION);
+}
+static struct kobj_attribute cap_version_attr =
+ __ATTR(version, 0444, capability_version_show, NULL);
+
+static int __init capability_export_names(void)
+{
+ int rc = -ENOMEM;
+
+ /* make /sys/kernel/capability */
+ capability_kobj = kobject_create_and_add("capability", kernel_kobj);
+ if (!capability_kobj)
+ goto error0;
+
+ /* make /sys/kernel/capability/names */
+ rc = sysfs_create_group(capability_kobj,
+ &capability_name_attr_group);
+ if (rc)
+ goto error1;
+
+ /* make /sys/kernel/capability/codes */
+ rc = sysfs_create_group(capability_kobj,
+ &capability_code_attr_group);
+ if (rc)
+ goto error2;
+
+ /* make /sys/kernel/capability/version */
+ rc = sysfs_create_file(capability_kobj,
+ &cap_version_attr.attr);
+ if (rc)
+ goto error3;
+
+ return 0;
+
+error3:
+ sysfs_remove_group(capability_kobj, &capability_code_attr_group);
+error2:
+ sysfs_remove_group(capability_kobj, &capability_name_attr_group);
+error1:
+ kobject_put(capability_kobj);
+error0:
+ printk(KERN_ERR "Unable to export capabilities\n");
+
+ return rc;
+}
+__initcall(capability_export_names);

--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-18 15:16:08

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #5.1)

Quoting Greg KH ([email protected]):
> On Mon, Feb 18, 2008 at 04:12:53PM +0900, Kohei KaiGai wrote:
> > Greg KH wrote:
> > > On Fri, Feb 15, 2008 at 12:38:02PM -0600, Serge E. Hallyn wrote:
> > >>> --------
> > >>> This patch enables to export code/name of capabilities supported
> > >>> on the running kernel.
> > >>>
> > >>> A newer kernel sometimes adds new capabilities, like CAP_MAC_ADMIN
> > >>> at 2.6.25. However, we have no interface to disclose what capabilities
> > >>> are supported on this kernel. Thus, we have to maintain libcap version
> > >>> in appropriate one synchronously.
> > >>>
> > >>> This patch enables libcap to collect the list of capabilities on
> > >>> run time, and provide them for users.
> > >>> It helps to improve portability of library.
> > >>>
> > >>> It exports these information as regular files under /sys/kernel/capability.
> > >>> The numeric node exports its name, the symbolic node exports its code.
> > >>>
> > >>> Please consider to put this patch on the queue of 2.6.25.
> > >> Looks good, except don't you need to put the code in commoncap.c under a
> > >> #ifdef SYSFS?
> >
> > Fair enough.
> > I added the #ifdef - #endif block in this patch.
>
> Not needed, if SYSFS is not build in, all of that code pretty much
> compiles away to nothing. So you can drop that.

Oops. Sorry.

-serge

2008-02-19 16:23:29

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #5.1)

On Mon, Feb 18, 2008 at 05:45:46PM +0900, Kohei KaiGai wrote:
> Greg KH wrote:
> >>> Also, this code can be cleaned up a lot by just using the basic kobject
> >>> attributes, and not rolling your own types here.
> >> I replaced my own defined capability_attribute by kobj_attribute.
> >>
> >> It made the patch cleaned up, however, it also impossible to share a single
> >> _show() method instance, because kobj_attribute does not have any private member.
> >> Is there any reason why kobj_attribute does not have "void *private;"?
> >
> > Because no one has asked for it? :)
> >
> > Or you can just do as the example in samples/kobject/ does it, no need
> > for the void pointer as that code shows.
>
> It shows us a good example in samples/kobject.
>
> However, it is unsuitable to export the list of capabilities.
> The shared _show() method (b_show) calls strcmp() once with the name of kobject
> attribute to switch its returning string.
> If we have 34 of candidates to be returned, like the capability case, we have
> to call strcmp() 33 times in maximum.
>
> If we can have a private member in kobj_attribute, we can found the content
> to be returned in a single step.

Ok, again, just send me a patch that adds this functionality and we will
be very glad to consider it.

thnaks,

greg k-h

2008-02-20 04:39:41

by Kohei KaiGai

[permalink] [raw]
Subject: [PATCH] exporting capability code/name pairs (try #6)

>> If we can have a private member in kobj_attribute, we can found the content
>> to be returned in a single step.
>
> Ok, again, just send me a patch that adds this functionality and we will
> be very glad to consider it.

[1/2] Add a private data field within kobj_attribute structure.

This patch add a private data field, declared as void *, within kobj_attribute
structure. Anyone wants to use sysfs can store their private data to refer at
_show() and _store() method.
It enables to share a single method function with several similar entries,
like ones to export the list of capabilities the running kernel supported.

Signed-off-by: KaiGai Kohei <[email protected]>
--
include/linux/kobject.h | 1 +
include/linux/sysfs.h | 7 +++++++
2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index caa3f41..57d5bf1 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -130,6 +130,7 @@ struct kobj_attribute {
char *buf);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count);
+ void *data; /* a private field */
};

extern struct sysfs_ops kobj_sysfs_ops;
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 8027104..6f40ff9 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -50,6 +50,13 @@ struct attribute_group {
.store = _store, \
}

+#define __ATTR_DATA(_name,_mode,_show,_store,_data) { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+ .data = (void *)(_data), \
+}
+
#define __ATTR_RO(_name) { \
.attr = { .name = __stringify(_name), .mode = 0444 }, \
.show = _name##_show, \

--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-20 04:41:55

by Kohei KaiGai

[permalink] [raw]
Subject: [PATCH] exporting capability code/name pairs (try #6)

Greg KH wrote:
> On Mon, Feb 18, 2008 at 05:45:46PM +0900, Kohei KaiGai wrote:
>> Greg KH wrote:
>>>>> Also, this code can be cleaned up a lot by just using the basic kobject
>>>>> attributes, and not rolling your own types here.
>>>> I replaced my own defined capability_attribute by kobj_attribute.
>>>>
>>>> It made the patch cleaned up, however, it also impossible to share a single
>>>> _show() method instance, because kobj_attribute does not have any private member.
>>>> Is there any reason why kobj_attribute does not have "void *private;"?
>>> Because no one has asked for it? :)
>>>
>>> Or you can just do as the example in samples/kobject/ does it, no need
>>> for the void pointer as that code shows.
>> It shows us a good example in samples/kobject.
>>
>> However, it is unsuitable to export the list of capabilities.
>> The shared _show() method (b_show) calls strcmp() once with the name of kobject
>> attribute to switch its returning string.
>> If we have 34 of candidates to be returned, like the capability case, we have
>> to call strcmp() 33 times in maximum.
>>
>> If we can have a private member in kobj_attribute, we can found the content
>> to be returned in a single step.
>
> Ok, again, just send me a patch that adds this functionality and we will
> be very glad to consider it.

In the attached patch, every attribute entry stores its capability
identifier in numerical or symbolic representation within private
data field of kobj_attribute structure.
The rest of them are unchanged.

----
[2/2] Exporting capability code/name pairs

This patch enables to export code/name of capabilities supported
on the running kernel.

A newer kernel sometimes adds new capabilities, like CAP_MAC_ADMIN
at 2.6.25. However, we have no interface to disclose what capabilities
are supported on this kernel. Thus, we have to maintain libcap version
in appropriate one synchronously.

This patch enables libcap to collect the list of capabilities on
run time, and provide them for users.
It helps to improve portability of library.

It exports these information as regular files under /sys/kernel/capability.
The numeric node exports its name, the symbolic node exports its code.

Please consider to put this patch on the queue of 2.6.25.

Thanks,
===================================================
[kaigai@saba ~]$ ls -R /sys/kernel/capability/
/sys/kernel/capability/:
codes names version

/sys/kernel/capability/codes:
0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9

/sys/kernel/capability/names:
cap_audit_control cap_kill cap_net_raw cap_sys_nice
cap_audit_write cap_lease cap_setfcap cap_sys_pacct
cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
cap_fowner cap_mknod cap_sys_admin cap_sys_time
cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
cap_ipc_lock cap_net_bind_service cap_sys_chroot
cap_ipc_owner cap_net_broadcast cap_sys_module
[kaigai@saba ~]$ cat /sys/kernel/capability/version
0x20071026
[kaigai@saba ~]$ cat /sys/kernel/capability/codes/30
cap_audit_control
[kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_sys_pacct
20
[kaigai@saba ~]$
===================================================

Signed-off-by: KaiGai Kohei <[email protected]>

--
Documentation/ABI/testing/sysfs-kernel-capability | 23 +++++
scripts/mkcapnames.sh | 44 +++++++++
security/Makefile | 9 ++
security/commoncap.c | 99 +++++++++++++++++++++
4 files changed, 175 insertions(+), 0 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-kernel-capability b/Documentation/ABI/testing/sysfs-kernel-capability
index e69de29..402ef06 100644
--- a/Documentation/ABI/testing/sysfs-kernel-capability
+++ b/Documentation/ABI/testing/sysfs-kernel-capability
@@ -0,0 +1,23 @@
+What: /sys/kernel/capability
+Date: Feb 2008
+Contact: KaiGai Kohei <[email protected]>
+Description:
+ The entries under /sys/kernel/capability are used to export
+ the list of capabilities the running kernel supported.
+
+ - /sys/kernel/capability/version
+ returns the most preferable version number for the
+ running kernel.
+ e.g) $ cat /sys/kernel/capability/version
+ 0x20071026
+
+ - /sys/kernel/capability/code/<numerical representation>
+ returns its symbolic representation, on reading.
+ e.g) $ cat /sys/kernel/capability/codes/30
+ cap_audit_control
+
+ - /sys/kernel/capability/name/<symbolic representation>
+ returns its numerical representation, on reading.
+ e.g) $ cat /sys/kernel/capability/names/cap_sys_pacct
+ 20
+
diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
index e69de29..5d36d52 100644
--- a/scripts/mkcapnames.sh
+++ b/scripts/mkcapnames.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+#
+# generate a cap_names.h file from include/linux/capability.h
+#
+
+CAPHEAD="`dirname $0`/../include/linux/capability.h"
+REGEXP='^#define CAP_[A-Z_]+[ ]+[0-9]+$'
+NUMCAP=`cat "$CAPHEAD" | egrep -c "$REGEXP"`
+
+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 '#if !defined(SYSFS_CAP_NAME_ENTRY) || !defined(SYSFS_CAP_CODE_ENTRY)'
+echo '#error cap_names.h should be included from security/capability.c'
+echo '#else'
+echo "#if $NUMCAP != CAP_LAST_CAP + 1"
+echo '#error mkcapnames.sh cannot collect capabilities correctly'
+echo '#else'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_NAME_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_name_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_name_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_CODE_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_code_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_code_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo '#endif'
+echo '#endif'
+echo '#endif'
diff --git a/security/Makefile b/security/Makefile
index 9e8b025..c1ffc00 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -18,3 +18,12 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+
+# cap_names.h contains the code/name pair of capabilities.
+# It is generated using include/linux/capability.h automatically.
+$(obj)/commoncap.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)
diff --git a/security/commoncap.c b/security/commoncap.c
index 5aba826..2f3b49a 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -24,6 +24,8 @@
#include <linux/hugetlb.h>
#include <linux/mount.h>
#include <linux/sched.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>

/* Global security state */

@@ -637,3 +639,100 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
return __vm_enough_memory(mm, pages, cap_sys_admin);
}

+/*
+ * Export the list of capabilities on /sys/kernel/capability
+ */
+static struct kobject *capability_kobj;
+
+static ssize_t capability_name_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buffer)
+{
+ /* It returns numerical representation of capability. */
+ return scnprintf(buffer, PAGE_SIZE, "%d\n", (int) attr->data);
+}
+
+static ssize_t capability_code_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buffer)
+{
+ /* It returns symbolic representation of capability. */
+ return scnprintf(buffer, PAGE_SIZE, "%s\n", (char *) attr->data);
+}
+
+static ssize_t capability_version_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "0x%08x\n",
+ _LINUX_CAPABILITY_VERSION);
+}
+
+#define SYSFS_CAP_NAME_ENTRY(_name,_code) \
+ static struct kobj_attribute _name##_name_attr = \
+ __ATTR_DATA(_name, 0444, capability_name_show, NULL, (int)(_code))
+
+#define SYSFS_CAP_CODE_ENTRY(_name,_code) \
+ static struct kobj_attribute _name##_code_attr = \
+ __ATTR_DATA(_code, 0444, capability_code_show, NULL, __stringify(_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_name_attr_group = {
+ .name = "names",
+ .attrs = capability_name_attrs,
+};
+
+static struct attribute_group capability_code_attr_group = {
+ .name = "codes",
+ .attrs = capability_code_attrs,
+};
+
+static struct kobj_attribute cap_version_attr =
+ __ATTR(version, 0444, capability_version_show, NULL);
+
+static int __init capability_export_names(void)
+{
+ int rc = -ENOMEM;
+
+ /* make /sys/kernel/capability */
+ capability_kobj = kobject_create_and_add("capability", kernel_kobj);
+ if (!capability_kobj)
+ goto error0;
+
+ /* make /sys/kernel/capability/names */
+ rc = sysfs_create_group(capability_kobj,
+ &capability_name_attr_group);
+ if (rc)
+ goto error1;
+
+ /* make /sys/kernel/capability/codes */
+ rc = sysfs_create_group(capability_kobj,
+ &capability_code_attr_group);
+ if (rc)
+ goto error2;
+
+ /* make /sys/kernel/capability/version */
+ rc = sysfs_create_file(capability_kobj,
+ &cap_version_attr.attr);
+ if (rc)
+ goto error3;
+
+ return 0;
+
+error3:
+ sysfs_remove_group(capability_kobj, &capability_code_attr_group);
+error2:
+ sysfs_remove_group(capability_kobj, &capability_name_attr_group);
+error1:
+ kobject_put(capability_kobj);
+error0:
+ printk(KERN_ERR "Unable to export capabilities\n");
+
+ return rc;
+}
+__initcall(capability_export_names);

--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-20 04:58:34

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #6)

On Wed, Feb 20, 2008 at 01:38:59PM +0900, Kohei KaiGai wrote:
> >> If we can have a private member in kobj_attribute, we can found the
> content
> >> to be returned in a single step.
> >
> > Ok, again, just send me a patch that adds this functionality and we will
> > be very glad to consider it.
>
> [1/2] Add a private data field within kobj_attribute structure.
>
> This patch add a private data field, declared as void *, within
> kobj_attribute
> structure. Anyone wants to use sysfs can store their private data to refer
> at
> _show() and _store() method.
> It enables to share a single method function with several similar entries,
> like ones to export the list of capabilities the running kernel supported.

But your patch 2/2 doesn't use this interface, why not?

> include/linux/kobject.h | 1 +
> include/linux/sysfs.h | 7 +++++++
> 2 files changed, 8 insertions(+), 0 deletions(-)
>
> diff --git a/include/linux/kobject.h b/include/linux/kobject.h
> index caa3f41..57d5bf1 100644
> --- a/include/linux/kobject.h
> +++ b/include/linux/kobject.h
> @@ -130,6 +130,7 @@ struct kobj_attribute {
> char *buf);
> ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
> const char *buf, size_t count);
> + void *data; /* a private field */

Hm, can you really use this?

> extern struct sysfs_ops kobj_sysfs_ops;
> diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
> index 8027104..6f40ff9 100644
> --- a/include/linux/sysfs.h
> +++ b/include/linux/sysfs.h
> @@ -50,6 +50,13 @@ struct attribute_group {
> .store = _store, \
> }
>
> +#define __ATTR_DATA(_name,_mode,_show,_store,_data) { \
> + .attr = {.name = __stringify(_name), .mode = _mode }, \
> + .show = _show, \
> + .store = _store, \
> + .data = (void *)(_data), \
> +}

I don't see how this would be any different from the original? You are
always passed a kobject, which can be embedded in anything else.

Could you also modify the documentation and the sample code to use this
new field, showing how it is to be used, and testing that it works
properly at the same time?

thanks,

greg k-h

2008-02-20 05:39:26

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #6)

Greg KH wrote:
> On Wed, Feb 20, 2008 at 01:38:59PM +0900, Kohei KaiGai wrote:
>>>> If we can have a private member in kobj_attribute, we can found the
>> content
>>>> to be returned in a single step.
>>> Ok, again, just send me a patch that adds this functionality and we will
>>> be very glad to consider it.
>> [1/2] Add a private data field within kobj_attribute structure.
>>
>> This patch add a private data field, declared as void *, within
>> kobj_attribute
>> structure. Anyone wants to use sysfs can store their private data to refer
>> at
>> _show() and _store() method.
>> It enables to share a single method function with several similar entries,
>> like ones to export the list of capabilities the running kernel supported.
>
> But your patch 2/2 doesn't use this interface, why not?

Really?
The following two _show() methods shared by every capabilities refer
the private member of kobj_attribute.

| +static ssize_t capability_name_show(struct kobject *kobj,
| + struct kobj_attribute *attr,
| + char *buffer)
| +{
| + /* It returns numerical representation of capability. */
| + return scnprintf(buffer, PAGE_SIZE, "%d\n", (int) attr->data);
| +}
| +
| +static ssize_t capability_code_show(struct kobject *kobj,
| + struct kobj_attribute *attr,
| + char *buffer)
| +{
| + /* It returns symbolic representation of capability. */
| + return scnprintf(buffer, PAGE_SIZE, "%s\n", (char *) attr->data);
| +}

>> include/linux/kobject.h | 1 +
>> include/linux/sysfs.h | 7 +++++++
>> 2 files changed, 8 insertions(+), 0 deletions(-)
>>
>> diff --git a/include/linux/kobject.h b/include/linux/kobject.h
>> index caa3f41..57d5bf1 100644
>> --- a/include/linux/kobject.h
>> +++ b/include/linux/kobject.h
>> @@ -130,6 +130,7 @@ struct kobj_attribute {
>> char *buf);
>> ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
>> const char *buf, size_t count);
>> + void *data; /* a private field */
>
> Hm, can you really use this?

Yes,

>> extern struct sysfs_ops kobj_sysfs_ops;
>> diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
>> index 8027104..6f40ff9 100644
>> --- a/include/linux/sysfs.h
>> +++ b/include/linux/sysfs.h
>> @@ -50,6 +50,13 @@ struct attribute_group {
>> .store = _store, \
>> }
>>
>> +#define __ATTR_DATA(_name,_mode,_show,_store,_data) { \
>> + .attr = {.name = __stringify(_name), .mode = _mode }, \
>> + .show = _show, \
>> + .store = _store, \
>> + .data = (void *)(_data), \
>> +}
>
> I don't see how this would be any different from the original? You are
> always passed a kobject, which can be embedded in anything else.

The intension of the latest patch is same as the version which uses
capability_attribute structure.
It enables to store the content to be returned in the expanded field.
Applying kobj_attribute killed needs to declare my own structure.

However, every entries had its own _show() method, generated by macros
automatically, in the previous version. It fundamentally differ from
the latest one.

> Could you also modify the documentation and the sample code to use this
> new field, showing how it is to be used, and testing that it works
> properly at the same time?

OK, Please wait for a while.

Thanks,
--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-20 06:00:19

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #6)

On Wed, Feb 20, 2008 at 02:38:16PM +0900, Kohei KaiGai wrote:
> Greg KH wrote:
>> On Wed, Feb 20, 2008 at 01:38:59PM +0900, Kohei KaiGai wrote:
>>>>> If we can have a private member in kobj_attribute, we can found the
>>> content
>>>>> to be returned in a single step.
>>>> Ok, again, just send me a patch that adds this functionality and we will
>>>> be very glad to consider it.
>>> [1/2] Add a private data field within kobj_attribute structure.
>>>
>>> This patch add a private data field, declared as void *, within
>>> kobj_attribute
>>> structure. Anyone wants to use sysfs can store their private data to
>>> refer at
>>> _show() and _store() method.
>>> It enables to share a single method function with several similar
>>> entries,
>>> like ones to export the list of capabilities the running kernel
>>> supported.
>> But your patch 2/2 doesn't use this interface, why not?
>
> Really?
> The following two _show() methods shared by every capabilities refer
> the private member of kobj_attribute.
>
> | +static ssize_t capability_name_show(struct kobject *kobj,
> | + struct kobj_attribute *attr,
> | + char *buffer)
> | +{
> | + /* It returns numerical representation of capability. */
> | + return scnprintf(buffer, PAGE_SIZE, "%d\n", (int) attr->data);
> | +}
> | +
> | +static ssize_t capability_code_show(struct kobject *kobj,
> | + struct kobj_attribute *attr,
> | + char *buffer)
> | +{
> | + /* It returns symbolic representation of capability. */
> | + return scnprintf(buffer, PAGE_SIZE, "%s\n", (char *) attr->data);
> | +}

Ah, sorry, missed that. I also missed where this was set up as well :(

thanks,

greg k-h

2008-02-20 06:18:50

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #6.1)

[Sorry, I sent a patch with TABs translated into spaces.]

[1/3] Add a private data field within kobj_attribute structure.

This patch add a private data field, declared as void *, within kobj_attribute
structure. Anyone wants to use sysfs can store their private data to refer at
_show() and _store() method.
It enables to share a single method function with several similar entries,
like ones to export the list of capabilities the running kernel supported.

Signed-off-by: KaiGai Kohei <[email protected]>
--
include/linux/kobject.h | 1 +
include/linux/sysfs.h | 7 +++++++
2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index caa3f41..57d5bf1 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -130,6 +130,7 @@ struct kobj_attribute {
char *buf);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count);
+ void *data; /* a private field */
};

extern struct sysfs_ops kobj_sysfs_ops;
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 8027104..6f40ff9 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -50,6 +50,13 @@ struct attribute_group {
.store = _store, \
}

+#define __ATTR_DATA(_name,_mode,_show,_store,_data) { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+ .data = (void *)(_data), \
+}
+
#define __ATTR_RO(_name) { \
.attr = { .name = __stringify(_name), .mode = 0444 }, \
.show = _name##_show, \

--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-20 06:19:12

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #6.1)

[Sorry, I sent a patch with TABs translated into spaces.]

In the attached patch, every attribute entry stores its capability
identifier in numerical or symbolic representation within private
data field of kobj_attribute structure.
The rest of them are unchanged.

----
[2/3] Exporting capability code/name pairs

This patch enables to export code/name of capabilities supported
on the running kernel.

A newer kernel sometimes adds new capabilities, like CAP_MAC_ADMIN
at 2.6.25. However, we have no interface to disclose what capabilities
are supported on this kernel. Thus, we have to maintain libcap version
in appropriate one synchronously.

This patch enables libcap to collect the list of capabilities on
run time, and provide them for users.
It helps to improve portability of library.

It exports these information as regular files under /sys/kernel/capability.
The numeric node exports its name, the symbolic node exports its code.

Please consider to put this patch on the queue of 2.6.25.

Thanks,
===================================================
[kaigai@saba ~]$ ls -R /sys/kernel/capability/
/sys/kernel/capability/:
codes names version

/sys/kernel/capability/codes:
0 10 12 14 16 18 2 21 23 25 27 29 30 32 4 6 8
1 11 13 15 17 19 20 22 24 26 28 3 31 33 5 7 9

/sys/kernel/capability/names:
cap_audit_control cap_kill cap_net_raw cap_sys_nice
cap_audit_write cap_lease cap_setfcap cap_sys_pacct
cap_chown cap_linux_immutable cap_setgid cap_sys_ptrace
cap_dac_override cap_mac_admin cap_setpcap cap_sys_rawio
cap_dac_read_search cap_mac_override cap_setuid cap_sys_resource
cap_fowner cap_mknod cap_sys_admin cap_sys_time
cap_fsetid cap_net_admin cap_sys_boot cap_sys_tty_config
cap_ipc_lock cap_net_bind_service cap_sys_chroot
cap_ipc_owner cap_net_broadcast cap_sys_module
[kaigai@saba ~]$ cat /sys/kernel/capability/version
0x20071026
[kaigai@saba ~]$ cat /sys/kernel/capability/codes/30
cap_audit_control
[kaigai@saba ~]$ cat /sys/kernel/capability/names/cap_sys_pacct
20
[kaigai@saba ~]$
===================================================

Signed-off-by: KaiGai Kohei <[email protected]>
--
Documentation/ABI/testing/sysfs-kernel-capability | 23 +++++
scripts/mkcapnames.sh | 44 +++++++++
security/Makefile | 9 ++
security/commoncap.c | 99 +++++++++++++++++++++
4 files changed, 175 insertions(+), 0 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-kernel-capability b/Documentation/ABI/testing/sysfs-kernel-capability
index e69de29..402ef06 100644
--- a/Documentation/ABI/testing/sysfs-kernel-capability
+++ b/Documentation/ABI/testing/sysfs-kernel-capability
@@ -0,0 +1,23 @@
+What: /sys/kernel/capability
+Date: Feb 2008
+Contact: KaiGai Kohei <[email protected]>
+Description:
+ The entries under /sys/kernel/capability are used to export
+ the list of capabilities the running kernel supported.
+
+ - /sys/kernel/capability/version
+ returns the most preferable version number for the
+ running kernel.
+ e.g) $ cat /sys/kernel/capability/version
+ 0x20071026
+
+ - /sys/kernel/capability/code/<numerical representation>
+ returns its symbolic representation, on reading.
+ e.g) $ cat /sys/kernel/capability/codes/30
+ cap_audit_control
+
+ - /sys/kernel/capability/name/<symbolic representation>
+ returns its numerical representation, on reading.
+ e.g) $ cat /sys/kernel/capability/names/cap_sys_pacct
+ 20
+
diff --git a/scripts/mkcapnames.sh b/scripts/mkcapnames.sh
index e69de29..5d36d52 100644
--- a/scripts/mkcapnames.sh
+++ b/scripts/mkcapnames.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+#
+# generate a cap_names.h file from include/linux/capability.h
+#
+
+CAPHEAD="`dirname $0`/../include/linux/capability.h"
+REGEXP='^#define CAP_[A-Z_]+[ ]+[0-9]+$'
+NUMCAP=`cat "$CAPHEAD" | egrep -c "$REGEXP"`
+
+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 '#if !defined(SYSFS_CAP_NAME_ENTRY) || !defined(SYSFS_CAP_CODE_ENTRY)'
+echo '#error cap_names.h should be included from security/capability.c'
+echo '#else'
+echo "#if $NUMCAP != CAP_LAST_CAP + 1"
+echo '#error mkcapnames.sh cannot collect capabilities correctly'
+echo '#else'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_NAME_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_name_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_name_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("SYSFS_CAP_CODE_ENTRY(%s,%s);\n", tolower($2), $2); }'
+echo
+echo 'static struct attribute *capability_code_attrs[] = {'
+cat "$CAPHEAD" | egrep "$REGEXP" \
+ | awk '{ printf("\t&%s_code_attr.attr,\n", tolower($2)); } END { print "\tNULL," }'
+echo '};'
+
+echo '#endif'
+echo '#endif'
+echo '#endif'
diff --git a/security/Makefile b/security/Makefile
index 9e8b025..c1ffc00 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -18,3 +18,12 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+
+# cap_names.h contains the code/name pair of capabilities.
+# It is generated using include/linux/capability.h automatically.
+$(obj)/commoncap.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)
diff --git a/security/commoncap.c b/security/commoncap.c
index 5aba826..2f3b49a 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -24,6 +24,8 @@
#include <linux/hugetlb.h>
#include <linux/mount.h>
#include <linux/sched.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>

/* Global security state */

@@ -637,3 +639,100 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
return __vm_enough_memory(mm, pages, cap_sys_admin);
}

+/*
+ * Export the list of capabilities on /sys/kernel/capability
+ */
+static struct kobject *capability_kobj;
+
+static ssize_t capability_name_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buffer)
+{
+ /* It returns numerical representation of capability. */
+ return scnprintf(buffer, PAGE_SIZE, "%d\n", (int) attr->data);
+}
+
+static ssize_t capability_code_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buffer)
+{
+ /* It returns symbolic representation of capability. */
+ return scnprintf(buffer, PAGE_SIZE, "%s\n", (char *) attr->data);
+}
+
+static ssize_t capability_version_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buffer)
+{
+ return scnprintf(buffer, PAGE_SIZE, "0x%08x\n",
+ _LINUX_CAPABILITY_VERSION);
+}
+
+#define SYSFS_CAP_NAME_ENTRY(_name,_code) \
+ static struct kobj_attribute _name##_name_attr = \
+ __ATTR_DATA(_name, 0444, capability_name_show, NULL, (int)(_code))
+
+#define SYSFS_CAP_CODE_ENTRY(_name,_code) \
+ static struct kobj_attribute _name##_code_attr = \
+ __ATTR_DATA(_code, 0444, capability_code_show, NULL, __stringify(_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_name_attr_group = {
+ .name = "names",
+ .attrs = capability_name_attrs,
+};
+
+static struct attribute_group capability_code_attr_group = {
+ .name = "codes",
+ .attrs = capability_code_attrs,
+};
+
+static struct kobj_attribute cap_version_attr =
+ __ATTR(version, 0444, capability_version_show, NULL);
+
+static int __init capability_export_names(void)
+{
+ int rc = -ENOMEM;
+
+ /* make /sys/kernel/capability */
+ capability_kobj = kobject_create_and_add("capability", kernel_kobj);
+ if (!capability_kobj)
+ goto error0;
+
+ /* make /sys/kernel/capability/names */
+ rc = sysfs_create_group(capability_kobj,
+ &capability_name_attr_group);
+ if (rc)
+ goto error1;
+
+ /* make /sys/kernel/capability/codes */
+ rc = sysfs_create_group(capability_kobj,
+ &capability_code_attr_group);
+ if (rc)
+ goto error2;
+
+ /* make /sys/kernel/capability/version */
+ rc = sysfs_create_file(capability_kobj,
+ &cap_version_attr.attr);
+ if (rc)
+ goto error3;
+
+ return 0;
+
+error3:
+ sysfs_remove_group(capability_kobj, &capability_code_attr_group);
+error2:
+ sysfs_remove_group(capability_kobj, &capability_name_attr_group);
+error1:
+ kobject_put(capability_kobj);
+error0:
+ printk(KERN_ERR "Unable to export capabilities\n");
+
+ return rc;
+}
+__initcall(capability_export_names);

--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

2008-02-20 06:20:59

by Kohei KaiGai

[permalink] [raw]
Subject: Re: [PATCH] exporting capability code/name pairs (try #6.1)

>> Could you also modify the documentation and the sample code to use this
>> new field, showing how it is to be used, and testing that it works
>> properly at the same time?
>
> OK, Please wait for a while.

[3/3] Add a new example of kobject/attribute

The attached patch can provide a new exmple to use kobject and attribute.
The _show() and _store() method can refer/store the private data field of
kobj_attribute structure to know what entries are refered by users.
It will make easier to share a single _show()/_store() method with several
entries.

Signed-off-by: KaiGai Kohei <[email protected]>
--
samples/kobject/kobject-example.c | 32 ++++++++++++++++++++++++++++++++
1 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/samples/kobject/kobject-example.c b/samples/kobject/kobject-example.c
index 08d0d3f..f99d734 100644
--- a/samples/kobject/kobject-example.c
+++ b/samples/kobject/kobject-example.c
@@ -77,6 +77,35 @@ static struct kobj_attribute baz_attribute =
static struct kobj_attribute bar_attribute =
__ATTR(bar, 0666, b_show, b_store);

+/*
+ * You can store a private data within 'data' field of kobj_attribute.
+ * It enables to share a single _show() or _store() method with several
+ * entries.
+ */
+static ssize_t integer_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (int) attr->data);
+}
+
+static ssize_t integer_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int code;
+
+ sscanf(buf, "%du", &code);
+ attr->data = (void *) code;
+ return count;
+}
+
+static struct kobj_attribute hoge_attribute =
+ __ATTR_DATA(hoge, 0666, integer_show, integer_store, 123);
+static struct kobj_attribute piyo_attribute =
+ __ATTR_DATA(piyo, 0666, integer_show, integer_store, 456);
+static struct kobj_attribute fuga_attribute =
+ __ATTR_DATA(fuga, 0444, integer_show, NULL, 789);

/*
* Create a group of attributes so that we can create and destory them all
@@ -86,6 +115,9 @@ static struct attribute *attrs[] = {
&foo_attribute.attr,
&baz_attribute.attr,
&bar_attribute.attr,
+ &hoge_attribute.attr,
+ &piyo_attribute.attr,
+ &fuga_attribute.attr,
NULL, /* need to NULL terminate the list of attributes */
};

--
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>