The attached patch enables to export capability code/name pairs under /capability of securityfs (revision 2).
Inprovements from the first revison: - simple_read_from_buffer() is used for read method. - cap_entries[] array is generated from include/linux/capability.h automatically. Remaining issues: - We have to mount securityfs explicitly, or use /etc/fstab. It can cause a matter when we want to use this feature on very early phase on boot. (like /sbin/init) It was also concerned at the past. http://marc.info/?l=linux-kernel&m=112063963623190&w=2 How do you think an idea that the root of securityfs is mounted on kernel/security of sysfs when it is initialized? If securityfs got being available when kernel initializing process, we can always use this feature and the matter will be resolved. >>> +static struct cap_entry_data cap_entries[] = { >>> + /* max number of supported format */ >>> + { _LINUX_CAPABILITY_VERSION, "version" }, >>> + /* max number of capability */ >>> + { CAP_LAST_CAP, "index" }, >>> + /* list of capabilities */ >>> + { CAP_CHOWN, "cap_chown" }, >>> + { CAP_DAC_OVERRIDE, "cap_dac_override" }, > - snip - >>> + { CAP_MAC_OVERRIDE, "cap_mac_override" }, >>> + { CAP_MAC_ADMIN, "cap_mac_admin" }, >>> + { -1, NULL}, >>> +}; >> >> I don't like this duplication with the list in >> include/linux/capability.h. >> Now when a new cap is added, it needs to be >> >> 1. added to capability.h >> 2. swapped as the new CAP_LAST_CAP in capability.h >> 3. added to this list... >> >> Could you integrate the two lists (not sure how offhand), or at least >> put them in the same place? kernel/cap_names.sh generates the body of cap_entries[] array, and it is invoked when we make the kernel. Signed-off-by: KaiGai Kohei <[EMAIL PROTECTED]> --- Makefile | 9 +++++++ cap_names.sh | 21 ++++++++++++++++ capability.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/kernel/Makefile b/kernel/Makefile index dfa9695..45d6034 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)/cap_names.sh > $@ +targets += cap_names.h +$(obj)/cap_names.h: $(src)/cap_names.sh $(src)/../include/linux/capability.h FORCE + $(call if_changed,cap_names) diff --git a/kernel/cap_names.sh b/kernel/cap_names.sh index e69de29..7b2fcfe 100644 --- a/kernel/cap_names.sh +++ b/kernel/cap_names.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# +# generate a cap_names.h file from include/linux/capability.h +# + +BASEDIR=`dirname $0` + +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("\t{ %s, \"%s\" },\n", $2, tolower($2)); + } + END { + printf("\t{ %u, \"index\" },\n", max_code); + }' diff --git a/kernel/capability.c b/kernel/capability.c index efbd9cd..03a9b62 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -245,3 +245,78 @@ int capable(int cap) return __capable(current, cap); } EXPORT_SYMBOL(capable); + +/* + * capability code/name pairs are exported under /sys/security/capability/ + */ +struct cap_entry_data { + unsigned int code; + const char *name; +}; + +static struct cap_entry_data cap_entries[] = { + /* max number of supported format */ + { _LINUX_CAPABILITY_VERSION, "version" }, + /* list of capabilities */ +#include "cap_names.h" + { -1, NULL}, +}; + +static ssize_t cap_entry_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct cap_entry_data *cap_entry; + char tmp[32]; + int len; + + cap_entry = file->f_dentry->d_inode->i_private; + BUG_ON(!cap_entry); + + snprintf(tmp, sizeof(tmp), + cap_entry == &cap_entries[0] ? "0x%08x" : "%u", + cap_entry->code); + len = strlen(tmp); + + return simple_read_from_buffer(buffer, count, ppos, tmp, len); +} + +const struct file_operations cap_entry_fops = { + .read = cap_entry_read, +}; + +int __init cap_names_export(void) +{ + struct dentry *d_caps, *f_caps[ARRAY_SIZE(cap_entries)]; + int i; + + /* init max number of capability*/ + cap_entries[1].code = ARRAY_SIZE(cap_entries) - 3; + + d_caps = securityfs_create_dir("capability", NULL); + if (!d_caps) + goto error0; + + memset(f_caps, 0, sizeof(f_caps)); + for (i = 0; cap_entries[i].name; i++) { + f_caps[i] = securityfs_create_file(cap_entries[i].name, 0444, + d_caps, &cap_entries[i], + &cap_entry_fops); + if (!f_caps[i]) + goto error1; + } + printk(KERN_NOTICE "capability code/name pairs are exported\n"); + return 0; + +error1: + while (i > 0) { + i--; + securityfs_remove(f_caps[i]); + } + securityfs_remove(d_caps); +error0: + printk(KERN_ERR "Unable to export capability code/name pairs\n"); + + return 0; +} + +__initcall(cap_names_export); -- 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